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