Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /*
2 *
3 * registrycb.c
4 *
5 * $Source: /Users/ekr/tmp/nrappkit-dump/nrappkit/src/registry/registrycb.c,v $
6 * $Revision: 1.3 $
7 * $Date: 2007/06/26 22:37:51 $
8 *
9 * Callback-related functions
10 *
11 *
12 * Copyright (C) 2005, Network Resonance, Inc.
13 * Copyright (C) 2006, Network Resonance, Inc.
14 * All Rights Reserved
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of Network Resonance, Inc. nor the name of any
26 * contributors to this software may be used to endorse or promote
27 * products derived from this software without specific prior written
28 * permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
31 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
34 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
41 *
42 *
43 */
45 #include <assert.h>
46 #include <string.h>
47 #include "registry.h"
48 #include "registry_int.h"
49 #include "r_assoc.h"
50 #include "r_errors.h"
51 #include "nr_common.h"
52 #include "r_log.h"
53 #include "r_macros.h"
55 static char CB_ACTIONS[] = { NR_REG_CB_ACTION_ADD,
56 NR_REG_CB_ACTION_DELETE,
57 NR_REG_CB_ACTION_CHANGE,
58 NR_REG_CB_ACTION_FINAL };
60 typedef struct nr_reg_cb_info_ {
61 char action;
62 void (*cb)(void *cb_arg, char action, NR_registry name);
63 void *cb_arg;
64 NR_registry name;
65 } nr_reg_cb_info;
67 /* callbacks that are registered, a mapping from names like "foo.bar.baz"
68 * to an r_assoc which contains possibly several nr_reg_cb_info*'s */
69 static r_assoc *nr_registry_callbacks = 0;
71 //static size_t SIZEOF_CB_ID = (sizeof(void (*)()) + 1);
72 #define SIZEOF_CB_ID (sizeof(void (*)()) + 1)
74 static int nr_reg_validate_action(char action);
75 static int nr_reg_assoc_destroy(void *ptr);
76 static int compute_cb_id(void *cb, char action, unsigned char cb_id[SIZEOF_CB_ID]);
77 static int nr_reg_info_free(void *ptr);
78 static int nr_reg_raise_event_recurse(char *name, char *tmp, int action);
79 static int nr_reg_register_callback(NR_registry name, char action, void (*cb)(void *cb_arg, char action, NR_registry name), void *cb_arg);
80 static int nr_reg_unregister_callback(char *name, char action, void (*cb)(void *cb_arg, char action, NR_registry name));
82 int
83 nr_reg_cb_init()
84 {
85 int r, _status;
87 if (nr_registry_callbacks == 0) {
88 if ((r=r_assoc_create(&nr_registry_callbacks, r_assoc_crc32_hash_compute, 12)))
89 ABORT(r);
90 }
92 _status=0;
93 abort:
94 if (_status) {
95 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't init notifications: %s", nr_strerror(_status));
96 }
97 return(_status);
98 }
100 int
101 nr_reg_validate_action(char action)
102 {
103 int _status;
104 int i;
106 for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
107 if (action == CB_ACTIONS[i])
108 return 0;
109 }
110 ABORT(R_BAD_ARGS);
112 _status=0;
113 abort:
114 return(_status);
115 }
117 int
118 nr_reg_register_callback(NR_registry name, char action, void (*cb)(void *cb_arg, char action, NR_registry name), void *cb_arg)
119 {
120 int r, _status;
121 r_assoc *assoc;
122 int create_assoc = 0;
123 nr_reg_cb_info *info;
124 int create_info = 0;
125 unsigned char cb_id[SIZEOF_CB_ID];
127 if (name == 0 || cb == 0)
128 ABORT(R_BAD_ARGS);
130 if (nr_registry_callbacks == 0)
131 ABORT(R_FAILED);
133 if ((r=nr_reg_is_valid(name)))
134 ABORT(r);
136 if ((r=nr_reg_validate_action(action)))
137 ABORT(r);
139 if ((r=r_assoc_fetch(nr_registry_callbacks, name, strlen(name)+1, (void*)&assoc))) {
140 if (r == R_NOT_FOUND)
141 create_assoc = 1;
142 else
143 ABORT(r);
144 }
146 if (create_assoc) {
147 if ((r=r_assoc_create(&assoc, r_assoc_crc32_hash_compute, 5)))
148 ABORT(r);
150 if ((r=r_assoc_insert(nr_registry_callbacks, name, strlen(name)+1, assoc, 0, nr_reg_assoc_destroy, R_ASSOC_NEW)))
151 ABORT(r);
152 }
154 if ((r=compute_cb_id(cb, action, cb_id)))
155 ABORT(r);
157 if ((r=r_assoc_fetch(assoc, (char*)cb_id, SIZEOF_CB_ID, (void*)&info))) {
158 if (r == R_NOT_FOUND)
159 create_info = 1;
160 else
161 ABORT(r);
162 }
164 if (create_info) {
165 if (!(info=(void*)RCALLOC(sizeof(*info))))
166 ABORT(R_NO_MEMORY);
167 }
169 strncpy(info->name, name, sizeof(info->name));
170 info->action = action;
171 info->cb = cb;
172 info->cb_arg = cb_arg;
174 if (create_info) {
175 if ((r=r_assoc_insert(assoc, (char*)cb_id, SIZEOF_CB_ID, info, 0, nr_reg_info_free, R_ASSOC_NEW)))
176 ABORT(r);
177 }
179 _status=0;
180 abort:
181 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "register callback %p on '%s' for '%s' %s", cb, name, nr_reg_action_name(action), (_status ? "FAILED" : "succeeded"));
183 if (_status) {
184 if (create_info && info) RFREE(info);
185 if (create_assoc && assoc) nr_reg_assoc_destroy(&assoc);
186 }
187 return(_status);
188 }
190 int
191 nr_reg_unregister_callback(char *name, char action, void (*cb)(void *cb_arg, char action, NR_registry name))
192 {
193 int r, _status;
194 r_assoc *assoc;
195 int size;
196 unsigned char cb_id[SIZEOF_CB_ID];
198 if (name == 0 || cb == 0)
199 ABORT(R_BAD_ARGS);
201 if (nr_registry_callbacks == 0)
202 ABORT(R_FAILED);
204 if ((r=nr_reg_is_valid(name)))
205 ABORT(r);
207 if ((r=nr_reg_validate_action(action)))
208 ABORT(r);
210 if ((r=r_assoc_fetch(nr_registry_callbacks, name, strlen(name)+1, (void*)&assoc))) {
211 if (r != R_NOT_FOUND)
212 ABORT(r);
213 }
214 else {
215 if ((r=compute_cb_id(cb, action, cb_id)))
216 ABORT(r);
218 if ((r=r_assoc_delete(assoc, (char*)cb_id, SIZEOF_CB_ID))) {
219 if (r != R_NOT_FOUND)
220 ABORT(r);
221 }
223 if ((r=r_assoc_num_elements(assoc, &size)))
224 ABORT(r);
226 if (size == 0) {
227 if ((r=r_assoc_delete(nr_registry_callbacks, name, strlen(name)+1)))
228 ABORT(r);
229 }
230 }
232 _status=0;
233 abort:
234 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "unregister callback %p on '%s' for '%s' %s", cb, name, nr_reg_action_name(action), (_status ? "FAILED" : "succeeded"));
236 return(_status);
237 }
239 int
240 compute_cb_id(void *cb, char action, unsigned char cb_id[SIZEOF_CB_ID])
241 {
242 /* callbacks are identified by the pointer to the cb function plus
243 * the action being watched */
244 assert(sizeof(cb) == sizeof(void (*)()));
245 assert(sizeof(cb) == (SIZEOF_CB_ID - 1));
247 memcpy(cb_id, &(cb), sizeof(cb));
248 cb_id[SIZEOF_CB_ID-1] = action;
250 return 0;
251 }
253 char *
254 nr_reg_action_name(int action)
255 {
256 char *name = "*Unknown*";
258 switch (action) {
259 case NR_REG_CB_ACTION_ADD: name = "add"; break;
260 case NR_REG_CB_ACTION_DELETE: name = "delete"; break;
261 case NR_REG_CB_ACTION_CHANGE: name = "change"; break;
262 case NR_REG_CB_ACTION_FINAL: name = "final"; break;
263 }
265 return name;
266 }
268 int
269 nr_reg_assoc_destroy(void *ptr)
270 {
271 return r_assoc_destroy((r_assoc**)&ptr);
272 }
274 int
275 nr_reg_info_free(void *ptr)
276 {
277 RFREE(ptr);
278 return 0;
279 }
281 /* call with tmp=0 */
282 int
283 nr_reg_raise_event_recurse(char *name, char *tmp, int action)
284 {
285 int r, _status;
286 r_assoc *assoc;
287 nr_reg_cb_info *info;
288 r_assoc_iterator iter;
289 char *key;
290 int keyl;
291 char *c;
292 int free_tmp = 0;
293 int count;
295 if (tmp == 0) {
296 if (!(tmp = (char*)r_strdup(name)))
297 ABORT(R_NO_MEMORY);
298 free_tmp = 1;
299 }
301 if ((r=r_assoc_fetch(nr_registry_callbacks, tmp, strlen(tmp)+1, (void*)&assoc))) {
302 if (r != R_NOT_FOUND)
303 ABORT(r);
305 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "No callbacks found on '%s'", tmp);
306 }
307 else {
308 if (!r_assoc_num_elements(assoc, &count)) {
309 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "%d callback%s found on '%s'",
310 count, ((count == 1) ? "" : "s"), tmp);
311 }
313 if ((r=r_assoc_init_iter(assoc, &iter)))
314 ABORT(r);
316 for (;;) {
317 if ((r=r_assoc_iter(&iter, (void*)&key, &keyl, (void*)&info))) {
318 if (r == R_EOD)
319 break;
320 else
321 ABORT(r);
322 }
324 if (info->action == action) {
325 r_log(NR_LOG_REGISTRY, LOG_DEBUG,
326 "Invoking callback %p for '%s'",
327 info->cb,
328 nr_reg_action_name(info->action));
330 (void)info->cb(info->cb_arg, action, name);
331 }
332 else {
333 r_log(NR_LOG_REGISTRY, LOG_DEBUG,
334 "Skipping callback %p for '%s'",
335 info->cb,
336 nr_reg_action_name(info->action));
337 }
338 }
339 }
341 if (strlen(tmp) > 0) {
342 c = strrchr(tmp, '.');
343 if (c != 0)
344 *c = '\0';
345 else
346 tmp[0] = '\0';
348 if ((r=nr_reg_raise_event_recurse(name, tmp, action)))
349 ABORT(r);
350 }
352 _status=0;
353 abort:
354 if (free_tmp && tmp != 0) RFREE(tmp);
355 return(_status);
356 }
359 /* NON-STATIC METHODS */
361 int
362 nr_reg_raise_event(char *name, int action)
363 {
364 int r, _status;
365 int count;
366 char *event = nr_reg_action_name(action);
368 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "raising event '%s' on '%s'", event, name);
370 if (name == 0)
371 ABORT(R_BAD_ARGS);
373 if ((r=nr_reg_validate_action(action)))
374 ABORT(r);
376 if ((r=r_assoc_num_elements(nr_registry_callbacks, &count)))
377 ABORT(r);
379 if (count > 0) {
380 if ((r=nr_reg_raise_event_recurse(name, 0, action)))
381 ABORT(r);
382 }
383 else {
384 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "No callbacks found");
385 return 0;
386 }
388 _status=0;
389 abort:
390 return(_status);
391 }
394 /* PUBLIC METHODS */
396 int
397 NR_reg_register_callback(NR_registry name, char action, void (*cb)(void *cb_arg, char action, NR_registry name), void *cb_arg)
398 {
399 int r, _status;
400 int i;
402 for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
403 if (action & CB_ACTIONS[i]) {
404 if ((r=nr_reg_register_callback(name, CB_ACTIONS[i], cb, cb_arg)))
405 ABORT(r);
407 action &= ~(CB_ACTIONS[i]);
408 }
409 }
411 if (action)
412 ABORT(R_BAD_ARGS);
414 _status=0;
415 abort:
416 return(_status);
417 }
419 int
420 NR_reg_unregister_callback(char *name, char action, void (*cb)(void *cb_arg, char action, NR_registry name))
421 {
422 int r, _status;
423 int i;
425 for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
426 if (action & CB_ACTIONS[i]) {
427 if ((r=nr_reg_unregister_callback(name, CB_ACTIONS[i], cb)))
428 ABORT(r);
430 action &= ~(CB_ACTIONS[i]);
431 }
432 }
434 if (action)
435 ABORT(R_BAD_ARGS);
437 _status=0;
438 abort:
439 return(_status);
440 }