#include #include #include #include #include #include /*------------------------------------------------------------------ */ static netsnmp_container *containers = NULL; typedef struct container_type_s { const char *name; netsnmp_factory *factory; } container_type; netsnmp_factory * netsnmp_container_get_factory(const char *type); /*------------------------------------------------------------------ */ static void _factory_free(container_type *data, void *context) { if (data == NULL) return; if (data->name != NULL) { DEBUGMSGTL(("container", " _factory_free_list() called for %s\n", data->name)); free((void *)data->name); /* SNMP_FREE wasted on object about to be freed */ } free(data); /* SNMP_FREE wasted on param */ } /*------------------------------------------------------------------ */ void netsnmp_container_init_list(void) { if (NULL != containers) return; /* * create a binary arry container to hold container * factories */ containers = netsnmp_container_get_binary_array(); containers->compare = netsnmp_compare_cstring; /* * register containers */ netsnmp_container_binary_array_init(); netsnmp_container_ssll_init(); netsnmp_container_null_init(); /* * default aliases for some containers */ netsnmp_container_register("table_container", netsnmp_container_get_factory("binary_array")); netsnmp_container_register("linked_list", netsnmp_container_get_factory("sorted_singly_linked_list")); netsnmp_container_register("ssll_container", netsnmp_container_get_factory("sorted_singly_linked_list")); } void netsnmp_container_free_list(void) { DEBUGMSGTL(("container", "netsnmp_container_free_list() called\n")); if (containers == NULL) return; /* * free memory used by each factory entry */ CONTAINER_FOR_EACH(containers, _factory_free, NULL); /* * free factory container */ CONTAINER_FREE(containers); containers = NULL; } int netsnmp_container_register(const char* name, netsnmp_factory *f) { container_type *ct, tmp; tmp.name = name; ct = CONTAINER_FIND(containers, &tmp); if (NULL!=ct) { DEBUGMSGT(("container_registry", "replacing previous container factory\n")); ct->factory = f; } else { ct = SNMP_MALLOC_TYPEDEF(container_type); if (NULL == ct) return -1; ct->name = strdup(name); ct->factory = f; CONTAINER_INSERT(containers, ct); } DEBUGMSGT(("container_registry", "registered container factory %s (%s)\n", ct->name, f->product)); return 0; } /*------------------------------------------------------------------ */ netsnmp_factory * netsnmp_container_get_factory(const char *type) { container_type ct, *found; ct.name = type; found = CONTAINER_FIND(containers, &ct); return found ? found->factory : NULL; } netsnmp_factory * netsnmp_container_find_factory(const char *type_list) { netsnmp_factory *f = NULL; char *list, *entry; char *st; if (NULL==type_list) return NULL; list = strdup(type_list); entry = strtok_r(list, ":", &st); while(entry) { f = netsnmp_container_get_factory(entry); if (NULL != f) break; entry = strtok_r(NULL, ":", &st); } free(list); return f; } /*------------------------------------------------------------------ */ netsnmp_container * netsnmp_container_get(const char *type) { netsnmp_factory *f = netsnmp_container_get_factory(type); if (f) return f->produce(); return NULL; } /*------------------------------------------------------------------ */ netsnmp_container * netsnmp_container_find(const char *type) { netsnmp_factory *f = netsnmp_container_find_factory(type); netsnmp_container *c = f ? f->produce() : NULL; /* * provide default compare */ if (c && (NULL == c->compare)) c->compare = netsnmp_compare_netsnmp_index; return c; } /*------------------------------------------------------------------ */ void netsnmp_container_add_index(netsnmp_container *primary, netsnmp_container *new_index) { netsnmp_container *curr = primary; if((NULL == new_index) || (NULL == primary)) { snmp_log(LOG_ERR, "add index called with null pointer\n"); return; } while(curr->next) curr = curr->next; curr->next = new_index; new_index->prev = curr; } #ifndef NETSNMP_USE_INLINE /* default is to inline */ /*------------------------------------------------------------------ * These functions should EXACTLY match the inline version in * container.h. If you chance one, change them both. */ int CONTAINER_INSERT(netsnmp_container *x, const void *k) { int rc2, rc = 0; /** start at first container */ while(x->prev) x = x->prev; while(x) { rc2 = x->insert(x,k); if (rc2) { snmp_log(LOG_ERR,"error on subcontainer insert (%d)\n", rc2); rc = rc2; } x = x->next; } return rc; } /*------------------------------------------------------------------ * These functions should EXACTLY match the inline version in * container.h. If you chance one, change them both. */ int CONTAINER_REMOVE(netsnmp_container *x, const void *k) { int rc2, rc = 0; /** start at last container */ while(x->next) x = x->next; while(x) { rc2 = x->remove(x,k); if (rc2) { snmp_log(LOG_ERR,"error on subcontainer remove (%d)\n", rc2); rc = rc2; } x = x->prev; } return rc; } /*------------------------------------------------------------------ * These functions should EXACTLY match the inline version in * container.h. If you chance one, change them both. */ int CONTAINER_FREE(netsnmp_container *x) { int rc2, rc = 0; /** start at last container */ while(x->next) x = x->next; while(x) { netsnmp_container *tmp; tmp = x->prev; if (NULL != x->container_name) SNMP_FREE(x->container_name); rc2 = x->cfree(x); if (rc2) { snmp_log(LOG_ERR,"error on subcontainer cfree (%d)\n", rc2); rc = rc2; } x = tmp; } return rc; } /*------------------------------------------------------------------ * These functions should EXACTLY match the function version in * container.c. If you change one, change them both. */ /* * clear all containers. When clearing the *first* container, and * *only* the first container, call the function f for each item. * After calling this function, all containers should be empty. */ void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f, void *c) { /** start at last container */ while(x->next) x = x->next; while(x->prev) { x->clear(x, NULL, c); x = x->prev; } x->clear(x, f, c); } /*------------------------------------------------------------------ * These functions should EXACTLY match the function version in * container.c. If you change one, change them both. */ /* * Find a sub-container with the given name */ netsnmp_container *SUBCONTAINER_FIND(netsnmp_container *x, const char* name) { if ((NULL == x) || (NULL == name)) return NULL; /** start at first container */ while(x->prev) x = x->prev; while(x) { if ((NULL != x->container_name) && (0 == strcmp(name,x->container_name))) break; x = x->next; } return x; } #endif /*------------------------------------------------------------------ */ void netsnmp_init_container(netsnmp_container *c, netsnmp_container_rc *init, netsnmp_container_rc *cfree, netsnmp_container_size *size, netsnmp_container_compare *cmp, netsnmp_container_op *ins, netsnmp_container_op *rem, netsnmp_container_rtn *fnd) { if (c == NULL) return; c->init = init; c->cfree = cfree; c->get_size = size; c->compare = cmp; c->insert = ins; c->remove = rem; c->find = fnd; } /*------------------------------------------------------------------ * * simple comparison routines * */ int netsnmp_compare_netsnmp_index(const void *lhs, const void *rhs) { int rc; netsnmp_assert((NULL != lhs) && (NULL != rhs)); DEBUGIF("compare:index") { DEBUGMSGT(("compare:index", "compare ")); DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) lhs)->oids, ((const netsnmp_index *) lhs)->len)); DEBUGMSG(("compare:index", " to ")); DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) rhs)->oids, ((const netsnmp_index *) rhs)->len)); DEBUGMSG(("compare:index", "\n")); } rc = snmp_oid_compare(((const netsnmp_index *) lhs)->oids, ((const netsnmp_index *) lhs)->len, ((const netsnmp_index *) rhs)->oids, ((const netsnmp_index *) rhs)->len); DEBUGMSGT(("compare:index", "result was %d\n", rc)); return rc; } int netsnmp_ncompare_netsnmp_index(const void *lhs, const void *rhs) { int rc; netsnmp_assert((NULL != lhs) && (NULL != rhs)); DEBUGIF("compare:index") { DEBUGMSGT(("compare:index", "compare ")); DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) lhs)->oids, ((const netsnmp_index *) lhs)->len)); DEBUGMSG(("compare:index", " to ")); DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) rhs)->oids, ((const netsnmp_index *) rhs)->len)); DEBUGMSG(("compare:index", "\n")); } rc = snmp_oid_ncompare(((const netsnmp_index *) lhs)->oids, ((const netsnmp_index *) lhs)->len, ((const netsnmp_index *) rhs)->oids, ((const netsnmp_index *) rhs)->len, ((const netsnmp_index *) rhs)->len); DEBUGMSGT(("compare:index", "result was %d\n", rc)); return rc; } int netsnmp_compare_cstring(const void * lhs, const void * rhs) { return strcmp(((const container_type*)lhs)->name, ((const container_type*)rhs)->name); } int netsnmp_ncompare_cstring(const void * lhs, const void * rhs) { return strncmp(((const container_type*)lhs)->name, ((const container_type*)rhs)->name, strlen(((const container_type*)rhs)->name)); } /* * compare two memory buffers * * since snmp strings aren't NULL terminated, we can't use strcmp. So * compare up to the length of the smaller, and then use length to * break any ties. */ int netsnmp_compare_mem(const char * lhs, size_t lhs_len, const char * rhs, size_t rhs_len) { int rc, min = SNMP_MIN(lhs_len, rhs_len); rc = memcmp(lhs, rhs, min); if((rc==0) && (lhs_len != rhs_len)) { if(lhs_len < rhs_len) rc = -1; else rc = 1; } return rc; } /*------------------------------------------------------------------ * netsnmp_container_simple_free * * useful function to pass to CONTAINER_FOR_EACH, when a simple * free is needed for every item. */ void netsnmp_container_simple_free(void *data, void *context) { if (data == NULL) return; DEBUGMSGTL(("verbose:container", "netsnmp_container_simple_free) called for %p/%p\n", data, context)); free((void*)data); /* SNMP_FREE wasted on param */ }