tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

registrycb.c (9795B)


      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 */
     44 
     45 #include <assert.h>
     46 #include <string.h>
     47 #include <csi_platform.h>
     48 #include "registry.h"
     49 #include "registry_int.h"
     50 #include "r_assoc.h"
     51 #include "r_errors.h"
     52 #include "r_log.h"
     53 #include "r_macros.h"
     54 
     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 };
     59 
     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;
     66 
     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;
     70 
     71 //static size_t SIZEOF_CB_ID = (sizeof(void (*)()) + 1);
     72 #define SIZEOF_CB_ID  (sizeof(void (*)()) + 1)
     73 
     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 
     81 int
     82 nr_reg_cb_init()
     83 {
     84    int r, _status;
     85 
     86    if (nr_registry_callbacks == 0) {
     87        if ((r=r_assoc_create(&nr_registry_callbacks, r_assoc_crc32_hash_compute, 12)))
     88            ABORT(r);
     89    }
     90 
     91    _status=0;
     92  abort:
     93    if (_status) {
     94       r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't init notifications: %s", nr_strerror(_status));
     95    }
     96    return(_status);
     97 }
     98 
     99 int
    100 nr_reg_validate_action(char action)
    101 {
    102    int _status;
    103    size_t i;
    104 
    105    for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
    106        if (action == CB_ACTIONS[i])
    107            return 0;
    108    }
    109    ABORT(R_BAD_ARGS);
    110 
    111    _status=0;
    112  abort:
    113    return(_status);
    114 }
    115 
    116 int
    117 nr_reg_register_callback(NR_registry name, char action, void (*cb)(void *cb_arg, char action, NR_registry name), void *cb_arg)
    118 {
    119    int r, _status;
    120    r_assoc *assoc = 0;
    121    int create_assoc = 0;
    122    nr_reg_cb_info *info = 0;
    123    int create_info = 0;
    124    unsigned char cb_id[SIZEOF_CB_ID];
    125 
    126    if (name == 0 || cb == 0)
    127      ABORT(R_BAD_ARGS);
    128 
    129    if (nr_registry_callbacks == 0)
    130      ABORT(R_FAILED);
    131 
    132    if ((r=nr_reg_is_valid(name)))
    133      ABORT(r);
    134 
    135    if ((r=nr_reg_validate_action(action)))
    136      ABORT(r);
    137 
    138    if ((r=r_assoc_fetch(nr_registry_callbacks, name, strlen(name)+1, (void*)&assoc))) {
    139      if (r == R_NOT_FOUND)
    140        create_assoc = 1;
    141      else
    142        ABORT(r);
    143    }
    144 
    145    if (create_assoc) {
    146      if ((r=r_assoc_create(&assoc, r_assoc_crc32_hash_compute, 5)))
    147        ABORT(r);
    148 
    149      if ((r=r_assoc_insert(nr_registry_callbacks, name, strlen(name)+1, assoc, 0, nr_reg_assoc_destroy, R_ASSOC_NEW)))
    150        ABORT(r);
    151    }
    152 
    153    if ((r=compute_cb_id(cb, action, cb_id)))
    154      ABORT(r);
    155 
    156    if ((r=r_assoc_fetch(assoc, (char*)cb_id, SIZEOF_CB_ID, (void*)&info))) {
    157      if (r == R_NOT_FOUND)
    158        create_info = 1;
    159      else
    160        ABORT(r);
    161    }
    162 
    163    if (create_info) {
    164      if (!(info=(void*)RCALLOC(sizeof(*info))))
    165        ABORT(R_NO_MEMORY);
    166    }
    167 
    168    strncpy(info->name, name, sizeof(info->name));
    169    info->action = action;
    170    info->cb = cb;
    171    info->cb_arg = cb_arg;
    172 
    173    if (create_info) {
    174      if ((r=r_assoc_insert(assoc, (char*)cb_id, SIZEOF_CB_ID, info, 0, nr_reg_info_free, R_ASSOC_NEW)))
    175        ABORT(r);
    176    }
    177 
    178    _status=0;
    179  abort:
    180    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"));
    181 
    182    if (_status) {
    183      if (create_info && info) RFREE(info);
    184      if (create_assoc && assoc) nr_reg_assoc_destroy(&assoc);
    185    }
    186    return(_status);
    187 }
    188 
    189 int
    190 compute_cb_id(void *cb, char action, unsigned char cb_id[SIZEOF_CB_ID])
    191 {
    192   /* callbacks are identified by the pointer to the cb function plus
    193    * the action being watched */
    194   assert(sizeof(cb) == sizeof(void (*)()));
    195   assert(sizeof(cb) == (SIZEOF_CB_ID - 1));
    196 
    197   memcpy(cb_id, &(cb), sizeof(cb));
    198   cb_id[SIZEOF_CB_ID-1] = action;
    199 
    200   return 0;
    201 }
    202 
    203 char *
    204 nr_reg_action_name(int action)
    205 {
    206    char *name = "*Unknown*";
    207 
    208    switch (action) {
    209    case NR_REG_CB_ACTION_ADD:     name = "add";     break;
    210    case NR_REG_CB_ACTION_DELETE:  name = "delete";  break;
    211    case NR_REG_CB_ACTION_CHANGE:  name = "change";  break;
    212    case NR_REG_CB_ACTION_FINAL:   name = "final";  break;
    213    }
    214 
    215    return name;
    216 }
    217 
    218 int
    219 nr_reg_assoc_destroy(void *ptr)
    220 {
    221  return r_assoc_destroy((r_assoc**)&ptr);
    222 }
    223 
    224 int
    225 nr_reg_info_free(void *ptr)
    226 {
    227  RFREE(ptr);
    228  return 0;
    229 }
    230 
    231 /* call with tmp=0 */
    232 int
    233 nr_reg_raise_event_recurse(char *name, char *tmp, int action)
    234 {
    235    int r, _status;
    236    r_assoc *assoc = 0;
    237    nr_reg_cb_info *info;
    238    r_assoc_iterator iter;
    239    char *key = 0;
    240    int keyl;
    241    char *c = 0;
    242    int free_tmp = 0;
    243    int count;
    244 
    245    if (tmp == 0) {
    246      if (!(tmp = (char*)r_strdup(name)))
    247        ABORT(R_NO_MEMORY);
    248      free_tmp = 1;
    249    }
    250 
    251    if ((r=r_assoc_fetch(nr_registry_callbacks, tmp, strlen(tmp)+1, (void*)&assoc))) {
    252      if (r != R_NOT_FOUND)
    253        ABORT(r);
    254 
    255      r_log(NR_LOG_REGISTRY, LOG_DEBUG, "No callbacks found on '%s'", tmp);
    256    }
    257    else {
    258      if (!r_assoc_num_elements(assoc, &count)) {
    259          r_log(NR_LOG_REGISTRY, LOG_DEBUG, "%d callback%s found on '%s'",
    260                count, ((count == 1) ? "" : "s"), tmp);
    261      }
    262 
    263      if ((r=r_assoc_init_iter(assoc, &iter)))
    264          ABORT(r);
    265 
    266      for (;;) {
    267        if ((r=r_assoc_iter(&iter, (void*)&key, &keyl, (void*)&info))) {
    268          if (r == R_EOD)
    269            break;
    270          else
    271            ABORT(r);
    272        }
    273 
    274        if (info->action == action) {
    275          r_log(NR_LOG_REGISTRY, LOG_DEBUG,
    276                "Invoking callback %p for '%s'",
    277                info->cb,
    278                nr_reg_action_name(info->action));
    279 
    280          (void)info->cb(info->cb_arg, action, name);
    281        }
    282        else {
    283          r_log(NR_LOG_REGISTRY, LOG_DEBUG,
    284                "Skipping callback %p for '%s'",
    285                info->cb,
    286                nr_reg_action_name(info->action));
    287        }
    288      }
    289    }
    290 
    291    if (strlen(tmp) > 0) {
    292        c = strrchr(tmp, '.');
    293        if (c != 0)
    294          *c = '\0';
    295        else
    296          tmp[0] = '\0';
    297 
    298        if ((r=nr_reg_raise_event_recurse(name, tmp, action)))
    299          ABORT(r);
    300    }
    301 
    302    _status=0;
    303  abort:
    304    if (free_tmp && tmp != 0) RFREE(tmp);
    305    return(_status);
    306 }
    307 
    308 
    309 /* NON-STATIC METHODS */
    310 
    311 int
    312 nr_reg_raise_event(NR_registry name, int action)
    313 {
    314    int r, _status;
    315    int count;
    316    char *event = nr_reg_action_name(action);
    317 
    318    r_log(NR_LOG_REGISTRY, LOG_DEBUG, "raising event '%s' on '%s'", event, name);
    319 
    320    if (name == 0)
    321      ABORT(R_BAD_ARGS);
    322 
    323    if ((r=nr_reg_validate_action(action)))
    324      ABORT(r);
    325 
    326    if ((r=r_assoc_num_elements(nr_registry_callbacks, &count)))
    327      ABORT(r);
    328 
    329    if (count > 0) {
    330      if ((r=nr_reg_raise_event_recurse(name, 0, action)))
    331        ABORT(r);
    332    }
    333    else {
    334      r_log(NR_LOG_REGISTRY, LOG_DEBUG, "No callbacks found");
    335      return 0;
    336    }
    337 
    338    _status=0;
    339  abort:
    340    return(_status);
    341 }
    342 
    343 
    344 /* PUBLIC METHODS */
    345 
    346 int
    347 NR_reg_register_callback(NR_registry name, char action, void (*cb)(void *cb_arg, char action, NR_registry name), void *cb_arg)
    348 {
    349    int r, _status;
    350    size_t i;
    351 
    352    for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
    353        if (action & CB_ACTIONS[i]) {
    354            if ((r=nr_reg_register_callback(name, CB_ACTIONS[i], cb, cb_arg)))
    355                ABORT(r);
    356 
    357            action &= ~(CB_ACTIONS[i]);
    358        }
    359    }
    360 
    361    if (action)
    362        ABORT(R_BAD_ARGS);
    363 
    364    _status=0;
    365  abort:
    366    return(_status);
    367 }