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 }