oid_stash.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:13k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. #include <net-snmp/net-snmp-config.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #if HAVE_DMALLOC_H
  6. #include <dmalloc.h>
  7. #endif
  8. #include <net-snmp/net-snmp-includes.h>
  9. /** @defgroup oid_stash Store and retrieve data referenced by an OID.
  10.     This is essentially a way of storing data associated with a given
  11.     OID.  It stores a bunch of data pointers within a memory tree that
  12.     allows fairly efficient lookups with a heavily populated tree.
  13.     @ingroup library
  14.     @{
  15. */
  16. /*
  17.  * xxx-rks: when you have some spare time:
  18.  *
  19.  * b) basically, everything currently creates one node per sub-oid,
  20.  *    which is less than optimal. add code to create nodes with the
  21.  *    longest possible OID per node, and split nodes when necessary
  22.  *    during adds.
  23.  *
  24.  * c) If you are feeling really ambitious, also merge split nodes if
  25.  *    possible on a delete.
  26.  *
  27.  * xxx-wes: uh, right, like I *ever* have that much time.
  28.  *
  29.  */
  30. /***************************************************************************
  31.  *
  32.  *
  33.  ***************************************************************************/
  34. /**
  35.  * Create an netsnmp_oid_stash node
  36.  *
  37.  * @param mysize  the size of the child pointer array
  38.  *
  39.  * @return NULL on error, otherwise the newly allocated node
  40.  */
  41. netsnmp_oid_stash_node *
  42. netsnmp_oid_stash_create_sized_node(size_t mysize)
  43. {
  44.     netsnmp_oid_stash_node *ret;
  45.     ret = SNMP_MALLOC_TYPEDEF(netsnmp_oid_stash_node);
  46.     if (!ret)
  47.         return NULL;
  48.     ret->children = calloc(mysize, sizeof(netsnmp_oid_stash_node *));
  49.     if (!ret->children) {
  50.         free(ret);
  51.         return NULL;
  52.     }
  53.     ret->children_size = mysize;
  54.     return ret;
  55. }
  56. /** Creates a netsnmp_oid_stash_node.
  57.  * Assumes you want the default OID_STASH_CHILDREN_SIZE hash size for the node.
  58.  * @return NULL on error, otherwise the newly allocated node
  59.  */
  60. NETSNMP_INLINE netsnmp_oid_stash_node *
  61. netsnmp_oid_stash_create_node(void)
  62. {
  63.     return netsnmp_oid_stash_create_sized_node(OID_STASH_CHILDREN_SIZE);
  64. }
  65. /** adds data to the stash at a given oid.
  66.  * @param root the top of the stash tree
  67.  * @param lookup the oid index to store the data at.
  68.  * @param lookup_len the length of the lookup oid.
  69.  * @param mydata the data to store
  70.  * @return SNMPERR_SUCCESS on success, SNMPERR_GENERR if data is
  71.    already there, SNMPERR_MALLOC on malloc failures or if arguments
  72.    passed in with NULL values.
  73.  */
  74. int
  75. netsnmp_oid_stash_add_data(netsnmp_oid_stash_node **root,
  76.                            oid * lookup, size_t lookup_len, void *mydata)
  77. {
  78.     netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
  79.     unsigned int    i;
  80.     if (!root || !lookup || lookup_len == 0)
  81.         return SNMPERR_GENERR;
  82.     if (!*root) {
  83.         *root = netsnmp_oid_stash_create_node();
  84.         if (!*root)
  85.             return SNMPERR_MALLOC;
  86.     }
  87.     tmpp = NULL;
  88.     for (curnode = *root, i = 0; i < lookup_len; i++) {
  89.         tmpp = curnode->children[lookup[i] % curnode->children_size];
  90.         if (!tmpp) {
  91.             /*
  92.              * no child in array at all 
  93.              */
  94.             tmpp = curnode->children[lookup[i] % curnode->children_size] =
  95.                 netsnmp_oid_stash_create_node();
  96.             tmpp->value = lookup[i];
  97.             tmpp->parent = curnode;
  98.         } else {
  99.             for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
  100.                 if (loopp->value == lookup[i])
  101.                     break;
  102.             }
  103.             if (loopp) {
  104.                 tmpp = loopp;
  105.             } else {
  106.                 /*
  107.                  * none exists.  Create it 
  108.                  */
  109.                 loopp = netsnmp_oid_stash_create_node();
  110.                 loopp->value = lookup[i];
  111.                 loopp->next_sibling = tmpp;
  112.                 loopp->parent = curnode;
  113.                 tmpp->prev_sibling = loopp;
  114.                 curnode->children[lookup[i] % curnode->children_size] =
  115.                     loopp;
  116.                 tmpp = loopp;
  117.             }
  118.             /*
  119.              * tmpp now points to the proper node 
  120.              */
  121.         }
  122.         curnode = tmpp;
  123.     }
  124.     /*
  125.      * tmpp now points to the exact match 
  126.      */
  127.     if (curnode->thedata)
  128.         return SNMPERR_GENERR;
  129.     if (NULL == tmpp)
  130.         return SNMPERR_GENERR;
  131.     tmpp->thedata = mydata;
  132.     return SNMPERR_SUCCESS;
  133. }
  134. /** returns a node associated with a given OID.
  135.  * @param root the top of the stash tree
  136.  * @param lookup the oid to look up a node for.
  137.  * @param lookup_len the length of the lookup oid
  138.  */
  139. netsnmp_oid_stash_node *
  140. netsnmp_oid_stash_get_node(netsnmp_oid_stash_node *root,
  141.                            oid * lookup, size_t lookup_len)
  142. {
  143.     netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
  144.     unsigned int    i;
  145.     if (!root)
  146.         return NULL;
  147.     tmpp = NULL;
  148.     for (curnode = root, i = 0; i < lookup_len; i++) {
  149.         tmpp = curnode->children[lookup[i] % curnode->children_size];
  150.         if (!tmpp) {
  151.             return NULL;
  152.         } else {
  153.             for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
  154.                 if (loopp->value == lookup[i])
  155.                     break;
  156.             }
  157.             if (loopp) {
  158.                 tmpp = loopp;
  159.             } else {
  160.                 return NULL;
  161.             }
  162.         }
  163.         curnode = tmpp;
  164.     }
  165.     return tmpp;
  166. }
  167. /** returns the next node associated with a given OID. INCOMPLETE.
  168.     This is equivelent to a GETNEXT operation.
  169.  * @internal
  170.  * @param root the top of the stash tree
  171.  * @param lookup the oid to look up a node for.
  172.  * @param lookup_len the length of the lookup oid
  173.  */
  174. netsnmp_oid_stash_node *
  175. netsnmp_oid_stash_getnext_node(netsnmp_oid_stash_node *root,
  176.                                oid * lookup, size_t lookup_len)
  177. {
  178.     netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
  179.     unsigned int    i, j, bigger_than = 0, do_bigger = 0;
  180.     if (!root)
  181.         return NULL;
  182.     tmpp = NULL;
  183.     /* get closest matching node */
  184.     for (curnode = root, i = 0; i < lookup_len; i++) {
  185.         tmpp = curnode->children[lookup[i] % curnode->children_size];
  186.         if (!tmpp) {
  187.             break;
  188.         } else {
  189.             for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
  190.                 if (loopp->value == lookup[i])
  191.                     break;
  192.             }
  193.             if (loopp) {
  194.                 tmpp = loopp;
  195.             } else {
  196.                 break;
  197.             }
  198.         }
  199.         curnode = tmpp;
  200.     }
  201.     /* find the *next* node lexographically greater */
  202.     if (!curnode)
  203.         return NULL; /* ack! */
  204.     if (i+1 < lookup_len) {
  205.         bigger_than = lookup[i+1];
  206.         do_bigger = 1;
  207.     }
  208.     do {
  209.         /* check the children first */
  210.         tmpp = NULL;
  211.         /* next child must be (next) greater than our next search node */
  212.         /* XXX: should start this loop at best_nums[i]%... and wrap */
  213.         for(j = 0; j < curnode->children_size; j++) {
  214.             for (loopp = curnode->children[j];
  215.                  loopp; loopp = loopp->next_sibling) {
  216.                 if ((!do_bigger || loopp->value > bigger_than) &&
  217.                     (!tmpp || tmpp->value > loopp->value)) {
  218.                     tmpp = loopp;
  219.                     /* XXX: can do better and include min_nums[i] */
  220.                     if (tmpp->value <= curnode->children_size-1) {
  221.                         /* best we can do. */
  222.                         goto done_this_loop;
  223.                     }
  224.                 }
  225.             }
  226.         }
  227.       done_this_loop:
  228.         if (tmpp && tmpp->thedata)
  229.             /* found a node with data.  Go with it. */
  230.             return tmpp;
  231.         if (tmpp) {
  232.             /* found a child node without data, maybe find a grandchild? */
  233.             do_bigger = 0;
  234.             curnode = tmpp;
  235.         } else {
  236.             /* no respectable children (the bums), we'll have to go up.
  237.                But to do so, they must be better than our current best_num + 1.
  238.             */
  239.             do_bigger = 1;
  240.             bigger_than = curnode->value;
  241.             curnode = curnode->parent;
  242.         }
  243.     } while (curnode);
  244.     /* fell off the top */
  245.     return NULL;
  246. }
  247. /** returns a data pointer associated with a given OID.
  248.     This is equivelent to netsnmp_oid_stash_get_node, but returns only
  249.     the data not the entire node.
  250.  * @param root the top of the stash
  251.  * @param oid the oid to search for
  252.  * @param the length of the search oid.
  253.  */
  254. void           *
  255. netsnmp_oid_stash_get_data(netsnmp_oid_stash_node *root,
  256.                            oid * lookup, size_t lookup_len)
  257. {
  258.     netsnmp_oid_stash_node *ret;
  259.     ret = netsnmp_oid_stash_get_node(root, lookup, lookup_len);
  260.     if (ret)
  261.         return ret->thedata;
  262.     return NULL;
  263. }
  264. /** a wrapper around netsnmp_oid_stash_store for use with a snmp_alarm.
  265.  * when calling snmp_alarm, you can list this as a callback.  The
  266.  * clientarg should be a pointer to a netsnmp_oid_stash_save_info
  267.  * pointer.  It can also be called directly, of course.  The last
  268.  * argument (clientarg) is the only one that is used.  The rest are
  269.  * ignored by the function.
  270.  * @param clientarg A pointer to a netsnmp_oid_stash_save_info structure.
  271.  */
  272. int
  273. netsnmp_oid_stash_store_all(int majorID, int minorID,
  274.                             void *serverarg, void *clientarg) {
  275.     oid oidbase[MAX_OID_LEN];
  276.     netsnmp_oid_stash_save_info *sinfo;
  277.     
  278.     if (!clientarg)
  279.         return SNMP_ERR_NOERROR;
  280.     
  281.     sinfo = clientarg;
  282.     netsnmp_oid_stash_store(*(sinfo->root), sinfo->token, sinfo->dumpfn,
  283.                             oidbase,0);
  284.     return SNMP_ERR_NOERROR;
  285. }
  286. /** stores data in a starsh tree to peristent storage.
  287.     This function can be called to save all data in a stash tree to
  288.     Net-SNMP's percent storage.  Make sure you register a parsing
  289.     function with the read_config system to re-incorperate your saved
  290.     data into future trees.
  291.     @param root the top of the stash to store.
  292.     @param tokenname the file token name to save in (passing "snmpd" will
  293.     save things into snmpd.conf).
  294.     @param dumpfn A function which can dump the data stored at a particular
  295.     node into a char buffer.
  296.     @param curoid must be a pointer to a OID array of length MAX_OID_LEN.
  297.     @param curoid_len must be 0 for the top level call.
  298. */
  299. void
  300. netsnmp_oid_stash_store(netsnmp_oid_stash_node *root,
  301.                         const char *tokenname, NetSNMPStashDump *dumpfn,
  302.                         oid *curoid, size_t curoid_len) {
  303.     char buf[SNMP_MAXBUF];
  304.     netsnmp_oid_stash_node *tmpp;
  305.     char *cp;
  306.     char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  307.                                           NETSNMP_DS_LIB_APPTYPE);
  308.     int i;
  309.     
  310.     if (!tokenname || !root || !curoid || !dumpfn)
  311.         return;
  312.     for (i = 0; i < (int)root->children_size; i++) {
  313.         if (root->children[i]) {
  314.             for (tmpp = root->children[i]; tmpp; tmpp = tmpp->next_sibling) {
  315.                 curoid[curoid_len] = tmpp->value;
  316.                 if (tmpp->thedata) {
  317.                     snprintf(buf, sizeof(buf), "%s ", tokenname);
  318.                     cp = read_config_save_objid(buf+strlen(buf), curoid,
  319.                                                 curoid_len+1);
  320.                     *cp++ = ' ';
  321.                     *cp = '';
  322.                     if ((*dumpfn)(cp, sizeof(buf) - strlen(buf),
  323.                                   tmpp->thedata, tmpp))
  324.                         read_config_store(appname, buf);
  325.                 }
  326.                 netsnmp_oid_stash_store(tmpp, tokenname, dumpfn,
  327.                                         curoid, curoid_len+1);
  328.             }
  329.         }
  330.     }
  331. }
  332. /** For debugging: dump the netsnmp_oid_stash tree to stdout
  333.     @param root The top of the tree
  334.     @param prefix a character string prefix printed to the beginning of each line.
  335. */
  336. void 
  337. oid_stash_dump(netsnmp_oid_stash_node *root, char *prefix)
  338. {
  339.     char            myprefix[MAX_OID_LEN * 4];
  340.     netsnmp_oid_stash_node *tmpp;
  341.     int             prefix_len = strlen(prefix) + 1;    /* actually it's +2 */
  342.     unsigned int    i;
  343.     memset(myprefix, ' ', MAX_OID_LEN * 4);
  344.     myprefix[prefix_len] = '';
  345.     for (i = 0; i < root->children_size; i++) {
  346.         if (root->children[i]) {
  347.             for (tmpp = root->children[i]; tmpp; tmpp = tmpp->next_sibling) {
  348.                 printf("%s%ld@%d: %sn", prefix, tmpp->value, i,
  349.                        (tmpp->thedata) ? "DATA" : "");
  350.                 oid_stash_dump(tmpp, myprefix);
  351.             }
  352.         }
  353.     }
  354. }
  355. /** Frees the contents of a netsnmp_oid_stash tree.
  356.     @param root the top of the tree (or branch to be freed)
  357.     @param freefn The function to be called on each data (void *)
  358.     pointer.  If left NULL the system free() function will be called
  359. */
  360. void
  361. netsnmp_oid_stash_free(netsnmp_oid_stash_node **root,
  362.                        NetSNMPStashFreeNode *freefn) {
  363.     netsnmp_oid_stash_node *curnode, *tmpp;
  364.     unsigned int    i;
  365.     if (!root || !*root)
  366.         return;
  367.     /* loop through all our children and free each node */
  368.     for (i = 0; i < (*root)->children_size; i++) {
  369.         if ((*root)->children[i]) {
  370.             for(tmpp = (*root)->children[i]; tmpp; tmpp = curnode) {
  371.                 if (tmpp->thedata) {
  372.                     if (freefn)
  373.                         (*freefn)(tmpp->thedata);
  374.                     else
  375.                         free(tmpp->thedata);
  376.                 }
  377.                 curnode = tmpp->next_sibling;
  378.                 netsnmp_oid_stash_free(&tmpp, freefn);
  379.             }
  380.         }
  381.     }
  382.     free((*root)->children);
  383.     free (*root);
  384.     *root = NULL;
  385. }
  386. void
  387. netsnmp_oid_stash_no_free(void *bogus)
  388. {
  389.     /* noop */
  390. }
  391. /** @} */