diff options
Diffstat (limited to 'snmplib/container.c')
-rw-r--r-- | snmplib/container.c | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/snmplib/container.c b/snmplib/container.c new file mode 100644 index 0000000..b2ac97e --- /dev/null +++ b/snmplib/container.c @@ -0,0 +1,714 @@ +/* Portions of this file are subject to the following copyright(s). See + * the Net-SNMP's COPYING file for more details and other copyrights + * that may apply: + */ +/* + * Portions of this file are copyrighted by: + * Copyright (C) 2007 Apple, Inc. All rights reserved. + * Use is subject to license terms specified in the COPYING file + * distributed with the Net-SNMP package. + */ +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-features.h> +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/library/container.h> +#include <net-snmp/library/container_binary_array.h> +#include <net-snmp/library/container_list_ssll.h> +#include <net-snmp/library/container_null.h> + +netsnmp_feature_child_of(container_all, libnetsnmp) + +netsnmp_feature_child_of(container_factories, container_all) +netsnmp_feature_child_of(container_types, container_all) +netsnmp_feature_child_of(container_compare, container_all) +netsnmp_feature_child_of(container_dup, container_all) +netsnmp_feature_child_of(container_free_all, container_all) +netsnmp_feature_child_of(subcontainer_find, container_all) + +netsnmp_feature_child_of(container_ncompare_cstring, container_compare) +netsnmp_feature_child_of(container_compare_mem, container_compare) +netsnmp_feature_child_of(container_compare_long, container_compare) +netsnmp_feature_child_of(container_compare_ulong, container_compare) +netsnmp_feature_child_of(container_compare_int32, container_compare) +netsnmp_feature_child_of(container_compare_uint32, container_compare) + +netsnmp_feature_child_of(container_find_factory, container_factories) + +/** @defgroup container container + */ + +/*------------------------------------------------------------------ + */ +static netsnmp_container *containers = NULL; + +typedef struct container_type_s { + const char *name; + netsnmp_factory *factory; + netsnmp_container_compare *compare; +} container_type; + +netsnmp_factory * +netsnmp_container_get_factory(const char *type); + +/*------------------------------------------------------------------ + */ +static void +_factory_free(void *dat, void *context) +{ + container_type *data = (container_type *)dat; + if (data == NULL) + return; + + if (data->name != NULL) { + DEBUGMSGTL(("container", " _factory_free_list() called for %s\n", + data->name)); + free(NETSNMP_REMOVE_CONST(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; + containers->container_name = strdup("container list"); + + /* + * register containers + */ + netsnmp_container_binary_array_init(); +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST + netsnmp_container_ssll_init(); +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */ +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_NULL + netsnmp_container_null_init(); +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_NULL */ + + /* + * default aliases for some containers + */ + netsnmp_container_register("table_container", + netsnmp_container_get_factory("binary_array")); + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST + 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")); +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */ + + netsnmp_container_register_with_compare + ("cstring", netsnmp_container_get_factory("binary_array"), + netsnmp_compare_direct_cstring); + + netsnmp_container_register_with_compare + ("string", netsnmp_container_get_factory("binary_array"), + netsnmp_compare_cstring); + netsnmp_container_register_with_compare + ("string_binary_array", netsnmp_container_get_factory("binary_array"), + netsnmp_compare_cstring); + +} + +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, ((netsnmp_container_obj_func *)_factory_free), NULL); + + /* + * free factory container + */ + CONTAINER_FREE(containers); + containers = NULL; +} + +int +netsnmp_container_register_with_compare(const char* name, netsnmp_factory *f, + netsnmp_container_compare *c) +{ + container_type *ct, tmp; + + if (NULL==containers) + return -1; + + tmp.name = NETSNMP_REMOVE_CONST(char *, name); + ct = (container_type *)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; + ct->compare = c; + CONTAINER_INSERT(containers, ct); + } + DEBUGMSGT(("container_registry", "registered container factory %s (%s)\n", + ct->name, f->product)); + + return 0; +} + +int +netsnmp_container_register(const char* name, netsnmp_factory *f) +{ + return netsnmp_container_register_with_compare(name, f, NULL); +} + +/*------------------------------------------------------------------ + */ +netsnmp_factory * +netsnmp_container_get_factory(const char *type) +{ + container_type ct, *found; + + if (NULL==containers) + return NULL; + + ct.name = type; + found = (container_type *)CONTAINER_FIND(containers, &ct); + + return found ? found->factory : NULL; +} + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_FIND_FACTORY +netsnmp_factory * +netsnmp_container_find_factory(const char *type_list) +{ + netsnmp_factory *f = NULL; + char *list, *entry; + char *st = NULL; + + 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; +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_FIND_FACTORY */ + +/*------------------------------------------------------------------ + */ +static container_type * +netsnmp_container_get_ct(const char *type) +{ + container_type ct; + + if (NULL == containers) + return NULL; + + ct.name = type; + return (container_type *)CONTAINER_FIND(containers, &ct); +} + +static container_type * +netsnmp_container_find_ct(const char *type_list) +{ + container_type *ct = NULL; + char *list, *entry; + char *st = NULL; + + if (NULL==type_list) + return NULL; + + list = strdup(type_list); + entry = strtok_r(list, ":", &st); + while(entry) { + ct = netsnmp_container_get_ct(entry); + if (NULL != ct) + break; + entry = strtok_r(NULL, ":", &st); + } + + free(list); + return ct; +} + + + +/*------------------------------------------------------------------ + */ +netsnmp_container * +netsnmp_container_get(const char *type) +{ + netsnmp_container *c; + container_type *ct = netsnmp_container_get_ct(type); + if (ct) { + c = (netsnmp_container *)(ct->factory->produce()); + if (c && ct->compare) + c->compare = ct->compare; + return c; + } + + return NULL; +} + +/*------------------------------------------------------------------ + */ +netsnmp_container * +netsnmp_container_find(const char *type) +{ + container_type *ct = netsnmp_container_find_ct(type); + netsnmp_container *c = ct ? (netsnmp_container *)(ct->factory->produce()) : NULL; + + /* + * provide default compare + */ + if (c) { + if (ct->compare) + c->compare = ct->compare; + else if (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; +} + +/*------------------------------------------------------------------ + * These functions should EXACTLY match the inline version in + * container.h. If you change one, change them both. + */ +int CONTAINER_INSERT_HELPER(netsnmp_container* x, const void* k) +{ + while(x && x->insert_filter && x->insert_filter(x,k) == 1) + x = x->next; + if(x) { + int rc = x->insert(x,k); + if(rc) + snmp_log(LOG_DEBUG,"error on subcontainer '%s' insert (%d)\n", + x->container_name ? x->container_name : "", rc); + else { + rc = CONTAINER_INSERT_HELPER(x->next, k); + if(rc) + x->remove(x,k); + } + return rc; + } + return 0; +} + +/*------------------------------------------------------------------ + * These functions should EXACTLY match the inline version in + * container.h. If you change one, change them both. + */ +int CONTAINER_INSERT(netsnmp_container* x, const void* k) +{ + /** start at first container */ + while(x->prev) + x = x->prev; + return CONTAINER_INSERT_HELPER(x, k); +} + +/*------------------------------------------------------------------ + * These functions should EXACTLY match the inline version in + * container.h. If you change 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); + /** ignore remove errors if there is a filter in place */ + if ((rc2) && (NULL == x->insert_filter)) { + snmp_log(LOG_ERR,"error on subcontainer '%s' remove (%d)\n", + x->container_name ? x->container_name : "", rc2); + rc = rc2; + } + x = x->prev; + + } + return rc; +} + +/*------------------------------------------------------------------ + * These functions should EXACTLY match the function version in + * container.c. If you change one, change them both. + */ +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_DUP +netsnmp_container *CONTAINER_DUP(netsnmp_container *x, void *ctx, u_int flags) +{ + if (NULL == x->duplicate) { + snmp_log(LOG_ERR, "container '%s' does not support duplicate\n", + x->container_name ? x->container_name : ""); + return NULL; + } + return x->duplicate(x, ctx, flags); +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_DUP */ + +/*------------------------------------------------------------------ + * These functions should EXACTLY match the inline version in + * container.h. If you change 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; + char *name; + tmp = x->prev; + name = x->container_name; + x->container_name = NULL; + rc2 = x->cfree(x); + if (rc2) { + snmp_log(LOG_ERR,"error on subcontainer '%s' cfree (%d)\n", + name ? name : "", rc2); + rc = rc2; + } + SNMP_FREE(name); + 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); +} + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_FREE_ALL +/* + * clear all containers. When clearing the *first* container, and + * *only* the first container, call the free_item function for each item. + * After calling this function, all containers should be empty. + */ +void CONTAINER_FREE_ALL(netsnmp_container *x, void *c) +{ + CONTAINER_CLEAR(x, x->free_item, c); +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_FREE_ALL */ + +#ifndef NETSNMP_FEATURE_REMOVE_SUBCONTAINER_FIND +/*------------------------------------------------------------------ + * 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 /* NETSNMP_FEATURE_REMOVE_SUBCONTAINER_FIND */ + + +/*------------------------------------------------------------------ + */ +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; + c->free_item = netsnmp_container_simple_free; +} + +int +netsnmp_container_data_dup(netsnmp_container *dup, netsnmp_container *c) +{ + if (!dup || !c) + return -1; + + if (c->container_name) + dup->container_name = strdup(c->container_name); + dup->compare = c->compare; + dup->ncompare = c->ncompare; + dup->release = c->release; + dup->insert_filter = c->insert_filter; + dup->free_item = c->free_item; + dup->sync = c->sync; + dup->flags = c->flags; + + return 0; +} + +/*------------------------------------------------------------------ + * + * 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); +} + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_NCOMPARE_CSTRING +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)); +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_NCOMPARE_CSTRING */ + +int +netsnmp_compare_direct_cstring(const void * lhs, const void * rhs) +{ + return strcmp((const char*)lhs, (const char*)rhs); +} + +/* + * 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. + */ +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_MEM +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; +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_MEM */ + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_LONG +int +netsnmp_compare_long(const void * lhs, const void * rhs) +{ + typedef struct { long index; } dummy; + + const dummy *lhd = (const dummy*)lhs; + const dummy *rhd = (const dummy*)rhs; + + if (lhd->index < rhd->index) + return -1; + else if (lhd->index > rhd->index) + return 1; + + return 0; +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_LONG */ + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_ULONG +int +netsnmp_compare_ulong(const void * lhs, const void * rhs) +{ + typedef struct { u_long index; } dummy; + + const dummy *lhd = (const dummy*)lhs; + const dummy *rhd = (const dummy*)rhs; + + if (lhd->index < rhd->index) + return -1; + else if (lhd->index > rhd->index) + return 1; + + return 0; +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_ULONG */ + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_INT32 +int +netsnmp_compare_int32(const void * lhs, const void * rhs) +{ + typedef struct { int32_t index; } dummy; + + const dummy *lhd = (const dummy*)lhs; + const dummy *rhd = (const dummy*)rhs; + + if (lhd->index < rhd->index) + return -1; + else if (lhd->index > rhd->index) + return 1; + + return 0; +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_INT32 */ + +#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_UINT32 +int +netsnmp_compare_uint32(const void * lhs, const void * rhs) +{ + typedef struct { uint32_t index; } dummy; + + const dummy *lhd = (const dummy*)lhs; + const dummy *rhd = (const dummy*)rhs; + + if (lhd->index < rhd->index) + return -1; + else if (lhd->index > rhd->index) + return 1; + + return 0; +} +#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_UINT32 */ + +/*------------------------------------------------------------------ + * 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 */ +} |