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