net-snmp  5.4.1
container.c
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 }