00001 /* Portions of this file are subject to the following copyright(s). See 00002 * the Net-SNMP's COPYING file for more details and other copyrights 00003 * that may apply: 00004 */ 00005 /* 00006 * Portions of this file are copyrighted by: 00007 * Copyright (C) 2007 Apple, Inc. All rights reserved. 00008 * Use is subject to license terms specified in the COPYING file 00009 * distributed with the Net-SNMP package. 00010 */ 00011 #include <net-snmp/net-snmp-config.h> 00012 #include <net-snmp/net-snmp-includes.h> 00013 #include <net-snmp/library/container.h> 00014 #include <net-snmp/library/container_binary_array.h> 00015 #include <net-snmp/library/container_list_ssll.h> 00016 #include <net-snmp/library/container_null.h> 00017 00021 /*------------------------------------------------------------------ 00022 */ 00023 static netsnmp_container *containers = NULL; 00024 00025 typedef struct container_type_s { 00026 const char *name; 00027 netsnmp_factory *factory; 00028 netsnmp_container_compare *compare; 00029 } container_type; 00030 00031 netsnmp_factory * 00032 netsnmp_container_get_factory(const char *type); 00033 00034 /*------------------------------------------------------------------ 00035 */ 00036 static void 00037 _factory_free(void *dat, void *context) 00038 { 00039 container_type *data = (container_type *)dat; 00040 if (data == NULL) 00041 return; 00042 00043 if (data->name != NULL) { 00044 DEBUGMSGTL(("container", " _factory_free_list() called for %s\n", 00045 data->name)); 00046 free((void *)data->name); /* SNMP_FREE wasted on object about to be freed */ 00047 } 00048 free(data); /* SNMP_FREE wasted on param */ 00049 } 00050 00051 /*------------------------------------------------------------------ 00052 */ 00053 void 00054 netsnmp_container_init_list(void) 00055 { 00056 if (NULL != containers) 00057 return; 00058 00059 /* 00060 * create a binary arry container to hold container 00061 * factories 00062 */ 00063 containers = netsnmp_container_get_binary_array(); 00064 containers->compare = netsnmp_compare_cstring; 00065 00066 /* 00067 * register containers 00068 */ 00069 netsnmp_container_binary_array_init(); 00070 netsnmp_container_ssll_init(); 00071 netsnmp_container_null_init(); 00072 00073 /* 00074 * default aliases for some containers 00075 */ 00076 netsnmp_container_register("table_container", 00077 netsnmp_container_get_factory("binary_array")); 00078 netsnmp_container_register("linked_list", 00079 netsnmp_container_get_factory("sorted_singly_linked_list")); 00080 netsnmp_container_register("ssll_container", 00081 netsnmp_container_get_factory("sorted_singly_linked_list")); 00082 00083 netsnmp_container_register_with_compare 00084 ("cstring", netsnmp_container_get_factory("binary_array"), 00085 netsnmp_compare_direct_cstring); 00086 00087 netsnmp_container_register_with_compare 00088 ("string", netsnmp_container_get_factory("binary_array"), 00089 netsnmp_compare_cstring); 00090 netsnmp_container_register_with_compare 00091 ("string_binary_array", netsnmp_container_get_factory("binary_array"), 00092 netsnmp_compare_cstring); 00093 00094 } 00095 00096 void 00097 netsnmp_container_free_list(void) 00098 { 00099 DEBUGMSGTL(("container", "netsnmp_container_free_list() called\n")); 00100 if (containers == NULL) 00101 return; 00102 00103 /* 00104 * free memory used by each factory entry 00105 */ 00106 CONTAINER_FOR_EACH(containers, ((netsnmp_container_obj_func *)_factory_free), NULL); 00107 00108 /* 00109 * free factory container 00110 */ 00111 CONTAINER_FREE(containers); 00112 containers = NULL; 00113 } 00114 00115 int 00116 netsnmp_container_register_with_compare(const char* name, netsnmp_factory *f, 00117 netsnmp_container_compare *c) 00118 { 00119 container_type *ct, tmp; 00120 00121 if (NULL==containers) 00122 return -1; 00123 00124 tmp.name = (char *)name; 00125 ct = (container_type *)CONTAINER_FIND(containers, &tmp); 00126 if (NULL!=ct) { 00127 DEBUGMSGT(("container_registry", 00128 "replacing previous container factory\n")); 00129 ct->factory = f; 00130 } 00131 else { 00132 ct = SNMP_MALLOC_TYPEDEF(container_type); 00133 if (NULL == ct) 00134 return -1; 00135 ct->name = strdup(name); 00136 ct->factory = f; 00137 ct->compare = c; 00138 CONTAINER_INSERT(containers, ct); 00139 } 00140 DEBUGMSGT(("container_registry", "registered container factory %s (%s)\n", 00141 ct->name, f->product)); 00142 00143 return 0; 00144 } 00145 00146 int 00147 netsnmp_container_register(const char* name, netsnmp_factory *f) 00148 { 00149 return netsnmp_container_register_with_compare(name, f, NULL); 00150 } 00151 00152 /*------------------------------------------------------------------ 00153 */ 00154 netsnmp_factory * 00155 netsnmp_container_get_factory(const char *type) 00156 { 00157 container_type ct, *found; 00158 00159 if (NULL==containers) 00160 return NULL; 00161 00162 ct.name = type; 00163 found = (container_type *)CONTAINER_FIND(containers, &ct); 00164 00165 return found ? found->factory : NULL; 00166 } 00167 00168 netsnmp_factory * 00169 netsnmp_container_find_factory(const char *type_list) 00170 { 00171 netsnmp_factory *f = NULL; 00172 char *list, *entry; 00173 char *st = NULL; 00174 00175 if (NULL==type_list) 00176 return NULL; 00177 00178 list = strdup(type_list); 00179 entry = strtok_r(list, ":", &st); 00180 while(entry) { 00181 f = netsnmp_container_get_factory(entry); 00182 if (NULL != f) 00183 break; 00184 entry = strtok_r(NULL, ":", &st); 00185 } 00186 00187 free(list); 00188 return f; 00189 } 00190 00191 /*------------------------------------------------------------------ 00192 */ 00193 static container_type * 00194 netsnmp_container_get_ct(const char *type) 00195 { 00196 container_type ct; 00197 00198 if (NULL == containers) 00199 return NULL; 00200 00201 ct.name = type; 00202 return (container_type *)CONTAINER_FIND(containers, &ct); 00203 } 00204 00205 static container_type * 00206 netsnmp_container_find_ct(const char *type_list) 00207 { 00208 container_type *ct = NULL; 00209 char *list, *entry; 00210 char *st = NULL; 00211 00212 if (NULL==type_list) 00213 return NULL; 00214 00215 list = strdup(type_list); 00216 entry = strtok_r(list, ":", &st); 00217 while(entry) { 00218 ct = netsnmp_container_get_ct(entry); 00219 if (NULL != ct) 00220 break; 00221 entry = strtok_r(NULL, ":", &st); 00222 } 00223 00224 free(list); 00225 return ct; 00226 } 00227 00228 00229 00230 /*------------------------------------------------------------------ 00231 */ 00232 netsnmp_container * 00233 netsnmp_container_get(const char *type) 00234 { 00235 netsnmp_container *c; 00236 container_type *ct = netsnmp_container_get_ct(type); 00237 if (ct) { 00238 c = (netsnmp_container *)(ct->factory->produce()); 00239 if (c && ct->compare) 00240 c->compare = ct->compare; 00241 return c; 00242 } 00243 00244 return NULL; 00245 } 00246 00247 /*------------------------------------------------------------------ 00248 */ 00249 netsnmp_container * 00250 netsnmp_container_find(const char *type) 00251 { 00252 container_type *ct = netsnmp_container_find_ct(type); 00253 netsnmp_container *c = ct ? (netsnmp_container *)(ct->factory->produce()) : NULL; 00254 00255 /* 00256 * provide default compare 00257 */ 00258 if (c) { 00259 if (ct->compare) 00260 c->compare = ct->compare; 00261 else if (NULL == c->compare) 00262 c->compare = netsnmp_compare_netsnmp_index; 00263 } 00264 00265 return c; 00266 } 00267 00268 /*------------------------------------------------------------------ 00269 */ 00270 void 00271 netsnmp_container_add_index(netsnmp_container *primary, 00272 netsnmp_container *new_index) 00273 { 00274 netsnmp_container *curr = primary; 00275 00276 if((NULL == new_index) || (NULL == primary)) { 00277 snmp_log(LOG_ERR, "add index called with null pointer\n"); 00278 return; 00279 } 00280 00281 while(curr->next) 00282 curr = curr->next; 00283 00284 curr->next = new_index; 00285 new_index->prev = curr; 00286 } 00287 00288 #ifndef NETSNMP_USE_INLINE /* default is to inline */ 00289 00290 /*------------------------------------------------------------------ 00291 * These functions should EXACTLY match the inline version in 00292 * container.h. If you change one, change them both. 00293 */ 00294 int CONTAINER_INSERT_HELPER(netsnmp_container* x, const void* k) 00295 { 00296 while(x && x->insert_filter && x->insert_filter(x,k) == 1) 00297 x = x->next; 00298 if(x) { 00299 int rc = x->insert(x,k); 00300 if(rc) 00301 snmp_log(LOG_DEBUG,"error on subcontainer '%s' insert (%d)\n", 00302 x->container_name ? x->container_name : "", rc); 00303 else { 00304 rc = CONTAINER_INSERT_HELPER(x->next, k); 00305 if(rc) 00306 x->remove(x,k); 00307 } 00308 return rc; 00309 } 00310 return 0; 00311 } 00312 00313 /*------------------------------------------------------------------ 00314 * These functions should EXACTLY match the inline version in 00315 * container.h. If you change one, change them both. 00316 */ 00317 int CONTAINER_INSERT(netsnmp_container* x, const void* k) 00318 { 00320 while(x->prev) 00321 x = x->prev; 00322 return CONTAINER_INSERT_HELPER(x, k); 00323 } 00324 00325 /*------------------------------------------------------------------ 00326 * These functions should EXACTLY match the inline version in 00327 * container.h. If you change one, change them both. 00328 */ 00329 int CONTAINER_REMOVE(netsnmp_container *x, const void *k) 00330 { 00331 int rc2, rc = 0; 00332 00334 while(x->next) 00335 x = x->next; 00336 while(x) { 00337 rc2 = x->remove(x,k); 00339 if ((rc2) && (NULL == x->insert_filter)) { 00340 snmp_log(LOG_ERR,"error on subcontainer '%s' remove (%d)\n", 00341 x->container_name ? x->container_name : "", rc2); 00342 rc = rc2; 00343 } 00344 x = x->prev; 00345 00346 } 00347 return rc; 00348 } 00349 00350 /*------------------------------------------------------------------ 00351 * These functions should EXACTLY match the inline version in 00352 * container.h. If you change one, change them both. 00353 */ 00354 int CONTAINER_FREE(netsnmp_container *x) 00355 { 00356 int rc2, rc = 0; 00357 00359 while(x->next) 00360 x = x->next; 00361 while(x) { 00362 netsnmp_container *tmp; 00363 const char *name; 00364 tmp = x->prev; 00365 name = x->container_name; 00366 if (NULL != x->container_name) 00367 SNMP_FREE(x->container_name); 00368 rc2 = x->cfree(x); 00369 if (rc2) { 00370 snmp_log(LOG_ERR,"error on subcontainer '%s' cfree (%d)\n", 00371 name ? name : "", rc2); 00372 rc = rc2; 00373 } 00374 x = tmp; 00375 } 00376 return rc; 00377 } 00378 00379 /*------------------------------------------------------------------ 00380 * These functions should EXACTLY match the function version in 00381 * container.c. If you change one, change them both. 00382 */ 00383 /* 00384 * clear all containers. When clearing the *first* container, and 00385 * *only* the first container, call the function f for each item. 00386 * After calling this function, all containers should be empty. 00387 */ 00388 void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f, 00389 void *c) 00390 { 00392 while(x->next) 00393 x = x->next; 00394 while(x->prev) { 00395 x->clear(x, NULL, c); 00396 x = x->prev; 00397 } 00398 x->clear(x, f, c); 00399 } 00400 00401 /*------------------------------------------------------------------ 00402 * These functions should EXACTLY match the function version in 00403 * container.c. If you change one, change them both. 00404 */ 00405 /* 00406 * Find a sub-container with the given name 00407 */ 00408 netsnmp_container *SUBCONTAINER_FIND(netsnmp_container *x, 00409 const char* name) 00410 { 00411 if ((NULL == x) || (NULL == name)) 00412 return NULL; 00413 00415 while(x->prev) 00416 x = x->prev; 00417 while(x) { 00418 if ((NULL != x->container_name) && (0 == strcmp(name,x->container_name))) 00419 break; 00420 x = x->next; 00421 } 00422 return x; 00423 } 00424 #endif 00425 00426 00427 /*------------------------------------------------------------------ 00428 */ 00429 void 00430 netsnmp_init_container(netsnmp_container *c, 00431 netsnmp_container_rc *init, 00432 netsnmp_container_rc *cfree, 00433 netsnmp_container_size *size, 00434 netsnmp_container_compare *cmp, 00435 netsnmp_container_op *ins, 00436 netsnmp_container_op *rem, 00437 netsnmp_container_rtn *fnd) 00438 { 00439 if (c == NULL) 00440 return; 00441 00442 c->init = init; 00443 c->cfree = cfree; 00444 c->get_size = size; 00445 c->compare = cmp; 00446 c->insert = ins; 00447 c->remove = rem; 00448 c->find = fnd; 00449 } 00450 00451 /*------------------------------------------------------------------ 00452 * 00453 * simple comparison routines 00454 * 00455 */ 00456 int 00457 netsnmp_compare_netsnmp_index(const void *lhs, const void *rhs) 00458 { 00459 int rc; 00460 netsnmp_assert((NULL != lhs) && (NULL != rhs)); 00461 DEBUGIF("compare:index") { 00462 DEBUGMSGT(("compare:index", "compare ")); 00463 DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) lhs)->oids, 00464 ((const netsnmp_index *) lhs)->len)); 00465 DEBUGMSG(("compare:index", " to ")); 00466 DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) rhs)->oids, 00467 ((const netsnmp_index *) rhs)->len)); 00468 DEBUGMSG(("compare:index", "\n")); 00469 } 00470 rc = snmp_oid_compare(((const netsnmp_index *) lhs)->oids, 00471 ((const netsnmp_index *) lhs)->len, 00472 ((const netsnmp_index *) rhs)->oids, 00473 ((const netsnmp_index *) rhs)->len); 00474 DEBUGMSGT(("compare:index", "result was %d\n", rc)); 00475 return rc; 00476 } 00477 00478 int 00479 netsnmp_ncompare_netsnmp_index(const void *lhs, const void *rhs) 00480 { 00481 int rc; 00482 netsnmp_assert((NULL != lhs) && (NULL != rhs)); 00483 DEBUGIF("compare:index") { 00484 DEBUGMSGT(("compare:index", "compare ")); 00485 DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) lhs)->oids, 00486 ((const netsnmp_index *) lhs)->len)); 00487 DEBUGMSG(("compare:index", " to ")); 00488 DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) rhs)->oids, 00489 ((const netsnmp_index *) rhs)->len)); 00490 DEBUGMSG(("compare:index", "\n")); 00491 } 00492 rc = snmp_oid_ncompare(((const netsnmp_index *) lhs)->oids, 00493 ((const netsnmp_index *) lhs)->len, 00494 ((const netsnmp_index *) rhs)->oids, 00495 ((const netsnmp_index *) rhs)->len, 00496 ((const netsnmp_index *) rhs)->len); 00497 DEBUGMSGT(("compare:index", "result was %d\n", rc)); 00498 return rc; 00499 } 00500 00501 int 00502 netsnmp_compare_cstring(const void * lhs, const void * rhs) 00503 { 00504 return strcmp(((const container_type*)lhs)->name, 00505 ((const container_type*)rhs)->name); 00506 } 00507 00508 int 00509 netsnmp_ncompare_cstring(const void * lhs, const void * rhs) 00510 { 00511 return strncmp(((const container_type*)lhs)->name, 00512 ((const container_type*)rhs)->name, 00513 strlen(((const container_type*)rhs)->name)); 00514 } 00515 00516 int 00517 netsnmp_compare_direct_cstring(const void * lhs, const void * rhs) 00518 { 00519 return strcmp((const char*)lhs, (const char*)rhs); 00520 } 00521 00522 /* 00523 * compare two memory buffers 00524 * 00525 * since snmp strings aren't NULL terminated, we can't use strcmp. So 00526 * compare up to the length of the smaller, and then use length to 00527 * break any ties. 00528 */ 00529 int 00530 netsnmp_compare_mem(const char * lhs, size_t lhs_len, 00531 const char * rhs, size_t rhs_len) 00532 { 00533 int rc, min = SNMP_MIN(lhs_len, rhs_len); 00534 00535 rc = memcmp(lhs, rhs, min); 00536 if((rc==0) && (lhs_len != rhs_len)) { 00537 if(lhs_len < rhs_len) 00538 rc = -1; 00539 else 00540 rc = 1; 00541 } 00542 00543 return rc; 00544 } 00545 00546 /*------------------------------------------------------------------ 00547 * netsnmp_container_simple_free 00548 * 00549 * useful function to pass to CONTAINER_FOR_EACH, when a simple 00550 * free is needed for every item. 00551 */ 00552 void 00553 netsnmp_container_simple_free(void *data, void *context) 00554 { 00555 if (data == NULL) 00556 return; 00557 00558 DEBUGMSGTL(("verbose:container", 00559 "netsnmp_container_simple_free) called for %p/%p\n", 00560 data, context)); 00561 free((void*)data); /* SNMP_FREE wasted on param */ 00562 }
1.5.7.1
Last modified: Tuesday, 23-Dec-2025 17:22:04 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.