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

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: container_iterator.c,v 5.9 2004/08/28 19:25:47 rstory Exp $
  3.  *
  4.  */
  5. #include <net-snmp/net-snmp-config.h>
  6. #include <stdio.h>
  7. #if HAVE_STDLIB_H
  8. #include <stdlib.h>
  9. #endif
  10. #if HAVE_MALLOC_H
  11. #include <malloc.h>
  12. #endif
  13. #include <sys/types.h>
  14. #if HAVE_STRING_H
  15. #include <string.h>
  16. #else
  17. #include <strings.h>
  18. #endif
  19. #include <net-snmp/net-snmp-includes.h>
  20. #include <net-snmp/types.h>
  21. #include <net-snmp/library/snmp_api.h>
  22. #include <net-snmp/library/container.h>
  23. #include <net-snmp/library/tools.h>
  24. #include <net-snmp/library/snmp_assert.h>
  25. #include <net-snmp/library/container_iterator.h>
  26. /** @typedef struct iterator_info_s iterator_info
  27.  * Typedefs the iterator_info_s struct into iterator_info */
  28. /** @struct iterator_info_s
  29.     
  30. * Holds iterator information containing functions which should be
  31. called by the iterator_handler to loop over your data set and
  32. sort it in a SNMP specific manner.
  33. The iterator_info typedef can be used instead of directly
  34. calling this struct if you would prefer.
  35. */
  36. typedef struct iterator_info_s {
  37.    /*
  38.     * netsnmp_conatiner  must be first
  39.     */
  40.    netsnmp_container c;
  41.    /*
  42.     * iterator data
  43.     */
  44.    Netsnmp_Iterator_Loop_Key *get_first;
  45.    Netsnmp_Iterator_Loop_Key *get_next;
  46.    
  47.    Netsnmp_Iterator_Loop_Data *get_data;
  48.    Netsnmp_Iterator_Data *free_user_ctx;
  49.    
  50.    Netsnmp_Iterator_Ctx *init_loop_ctx;
  51.    Netsnmp_Iterator_Ctx *cleanup_loop_ctx;
  52.    Netsnmp_Iterator_Ctx_Dup *save_pos;
  53.    
  54.    Netsnmp_Iterator_Data * release_data;
  55.    Netsnmp_Iterator_Data * insert_data;
  56.    Netsnmp_Iterator_Data * remove_data;
  57.    Netsnmp_Iterator_Op * get_size;
  58.    
  59.    int             sorted;
  60.    
  61.    /** This can be used by client handlers to store any
  62.        information they need */
  63.    void           *user_ctx;
  64. } iterator_info;
  65. /**********************************************************************
  66.  *
  67.  * iterator
  68.  *
  69.  **********************************************************************/
  70. static void *
  71. _iterator_get(iterator_info *ii, const void *key)
  72. {
  73.     int cmp, rc = SNMP_ERR_NOERROR;
  74.     netsnmp_ref_void best = { NULL };
  75.     netsnmp_ref_void tmp = { NULL };
  76.     netsnmp_ref_void loop_ctx = { NULL };
  77.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_get"));
  78.     
  79.     if(ii->init_loop_ctx)
  80.         ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
  81.     
  82.     rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
  83.     if(SNMP_ERR_NOERROR != rc) {
  84.         if(SNMP_ENDOFMIBVIEW != rc)
  85.             snmp_log(LOG_ERR, "bad rc %d from get_nextn", rc);
  86.     }
  87.     else {
  88.         for( ;
  89.              (NULL != tmp.val) && (SNMP_ERR_NOERROR == rc);
  90.              rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
  91.             
  92.             /*
  93.              * if keys are equal, we are done.
  94.              */
  95.             cmp = ii->c.compare(tmp.val, key);
  96.             if(0 == cmp) {
  97.                 best.val = tmp.val;
  98.                 if(ii->get_data)
  99.                     ii->get_data(ii->user_ctx, &loop_ctx, &best);
  100.             }
  101.             
  102.             /*
  103.              * if data is sorted and if key is greater,
  104.              * we are done (not found)
  105.              */
  106.             if((cmp > 0) && ii->sorted)
  107.                 break;
  108.         } /* end for */
  109.     }
  110.     
  111.     if(ii->cleanup_loop_ctx)
  112.         ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
  113.     return best.val;
  114. }
  115. /**
  116.  *
  117.  * NOTE: the returned data context can be reused, to save from
  118.  *   having to allocate memory repeatedly. However, in this case,
  119.  *   the get_data and get_pos functions must be implemented to
  120.  *   return unique memory that will be saved for later comparisons.
  121.  */
  122. static void *
  123. _iterator_get_next(iterator_info *ii, const void *key)
  124. {
  125.     int cmp, rc = SNMP_ERR_NOERROR;
  126.     netsnmp_ref_void best_val = { NULL };
  127.     netsnmp_ref_void best_ctx = { NULL };
  128.     netsnmp_ref_void tmp = { NULL };
  129.     netsnmp_ref_void loop_ctx = { NULL };
  130.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_get_next"));
  131.     
  132.     /*
  133.      * initialize loop context
  134.      */
  135.     if(ii->init_loop_ctx)
  136.         ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
  137.     
  138.     /*
  139.      * get first item
  140.      */
  141.     rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
  142.     if(SNMP_ERR_NOERROR == rc) {
  143.         /*
  144.          * special case: if key is null, find the first item.
  145.          * this is each if the container is sorted, since we're
  146.          * already done!  Otherwise, get the next item for the
  147.          * first comparison in the loop below.
  148.          */
  149.         if (NULL == key) {
  150.             if(ii->get_data)
  151.                 ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
  152.             best_val.val = tmp.val;
  153.             if(ii->sorted)
  154.                 tmp.val = NULL; /* so we skip for loop */
  155.             else
  156.                 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
  157.         }
  158.         /*
  159.          * loop over remaining items
  160.          */
  161.         for( ;
  162.              (NULL != tmp.val) && (rc == SNMP_ERR_NOERROR);
  163.              rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
  164.             
  165.             /*
  166.              * if we have a key, this is a get-next, and we need to compare
  167.              * the key to the tmp value to see if the tmp value is greater
  168.              * than the key, but less than any previous match.
  169.              *
  170.              * if there is no key, this is a get-first, and we need to
  171.              * compare the best value agains the tmp value to see if the
  172.              * tmp value is lesser than the best match.
  173.              */
  174.             if(key) /* get next */
  175.                 cmp = ii->c.compare(tmp.val, key);
  176.             else { /* get first */
  177.                 /*
  178.                  * best value and tmp value should never be equal,
  179.                  * otherwise we'd be comparing a pointer to itself.
  180.                  * (see note on context reuse in comments above function.
  181.                  */
  182.                 if(best_val.val == tmp.val) {
  183.                     snmp_log(LOG_ERR,"illegal reuse of data context in "
  184.                              "container_iteratorn");
  185.                     rc = SNMP_ERR_GENERR;
  186.                     break;
  187.                 }
  188.                 cmp = ii->c.compare(best_val.val, tmp.val);
  189.             }
  190.             if(cmp > 0) {
  191.                 /*
  192.                  * if we don't have a key (get-first) or a current best match,
  193.                  * then the comparison above is all we need to know that
  194.                  * tmp is the best match. otherwise, compare against the
  195.                  * current best match.
  196.                  */
  197.                 if((NULL == key) || (NULL == best_val.val) ||
  198.                    ((cmp=ii->c.compare(tmp.val, best_val.val)) < 0) ) {
  199.                     DEBUGMSGT(("container_iterator:results"," best matchn"));
  200.                     best_val.val = tmp.val;
  201.                     if(ii->get_data)
  202.                         ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
  203.                 }
  204.             }
  205.             else if((cmp == 0) && ii->sorted && key) {
  206.                 /*
  207.                  * if keys are equal and container is sorted, then we know
  208.                  * the next key will be the one we want.
  209.                  * NOTE: if no vars, treat as generr, since we
  210.                  *    went past the end of the container when we know
  211.                  *    the next item is the one we want. (IGN-A)
  212.                  */
  213.                 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
  214.                 if(SNMP_ERR_NOERROR == rc) {
  215.                     best_val.val = tmp.val;
  216.                     if(ii->get_data)
  217.                         ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
  218.                 }
  219.                 else if(SNMP_ENDOFMIBVIEW == rc)
  220.                     rc = SNMPERR_GENERR; /* not found */
  221.                 break;
  222.             }
  223.             
  224.         } /* end for */
  225.     }
  226.     /*
  227.      * no vars is ok, except as noted above (IGN-A)
  228.      */
  229.     if(SNMP_ENDOFMIBVIEW == rc)
  230.         rc = SNMP_ERR_NOERROR;
  231.             
  232.     /*
  233.      * get data, iff necessary
  234.      * clear return value iff errors
  235.      */
  236.     if(SNMP_ERR_NOERROR == rc) {
  237.         if(ii->get_data && best_val.val) {
  238.             rc = ii->get_data(ii->user_ctx, &best_ctx, &best_val);
  239.             if(SNMP_ERR_NOERROR != rc) {
  240.                 snmp_log(LOG_ERR, "bad rc %d from get_datan", rc);
  241.                 best_val.val = NULL;
  242.             }
  243.         }
  244.     }
  245.     else if(SNMP_ENDOFMIBVIEW != rc) {
  246.         snmp_log(LOG_ERR, "bad rc %d from get_nextn", rc);
  247.         best_val.val = NULL;
  248.     }
  249.     /*
  250.      * if we have a saved loop ctx, clean it up
  251.      */
  252.     if((best_ctx.val != NULL) && (best_ctx.val != loop_ctx.val) &&
  253.        (ii->cleanup_loop_ctx))
  254.         ii->cleanup_loop_ctx(ii->user_ctx,&best_ctx);
  255.     /*
  256.      * clean up loop ctx
  257.      */
  258.     if(ii->cleanup_loop_ctx)
  259.         ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
  260.     DEBUGMSGT(("container_iterator:results"," returning %pn", best_val.val));
  261.     return best_val.val;
  262. }
  263. /**********************************************************************
  264.  *
  265.  * container
  266.  *
  267.  **********************************************************************/
  268. static void
  269. _iterator_free(iterator_info *ii)
  270. {
  271.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_free"));
  272.     
  273.     if(NULL == ii)
  274.         return;
  275.     
  276.     if(ii->user_ctx)
  277.         ii->free_user_ctx(ii->user_ctx,ii->user_ctx);
  278.     
  279.     free(ii);
  280. }
  281. static void *
  282. _iterator_find(iterator_info *ii, const void *data)
  283. {
  284.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_find"));
  285.     
  286.     if((NULL == ii) || (NULL == data))
  287.         return NULL;
  288.     return _iterator_get(ii, data);
  289. }
  290. static void *
  291. _iterator_find_next(iterator_info *ii, const void *data)
  292. {
  293.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_find_next"));
  294.     
  295.     if(NULL == ii)
  296.         return NULL;
  297.     return _iterator_get_next(ii, data);
  298. }
  299. static int
  300. _iterator_insert(iterator_info *ii, const void *data)
  301. {
  302.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_insert"));
  303.     
  304.     if(NULL == ii)
  305.         return -1;
  306.     if(NULL == ii->insert_data)
  307.         return -1;
  308.     return ii->insert_data(ii->user_ctx, data);
  309. }
  310. static int
  311. _iterator_remove(iterator_info *ii, const void *data)
  312. {
  313.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_remove"));
  314.     
  315.     if(NULL == ii)
  316.         return -1;
  317.     if(NULL == ii->remove_data)
  318.         return -1;
  319.     return ii->remove_data(ii->user_ctx, data);
  320. }
  321. static int
  322. _iterator_release(iterator_info *ii, const void *data)
  323. {
  324.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_release"));
  325.     
  326.     if(NULL == ii)
  327.         return -1;
  328.     if(NULL == ii->release_data)
  329.         return -1;
  330.     return ii->release_data(ii->user_ctx, data);
  331. }
  332. static size_t
  333. _iterator_size(iterator_info *ii)
  334. {
  335.     size_t count = 0;
  336.     int rc = SNMP_ERR_NOERROR;
  337.     netsnmp_ref_void loop_ctx = { NULL };
  338.     netsnmp_ref_void tmp = { NULL };
  339.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_size"));
  340.     
  341.     if(NULL == ii)
  342.         return -1;
  343.     if(NULL != ii->get_size)
  344.         return ii->get_size(ii->user_ctx);
  345.     /*
  346.      * no get_size. loop and count ourselves
  347.      */
  348.     if(ii->init_loop_ctx)
  349.         ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
  350.     
  351.     for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
  352.          NULL != tmp.val;
  353.          rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
  354.         ++count;
  355.     if(ii->cleanup_loop_ctx)
  356.         ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
  357.     return count;
  358. }
  359. static void
  360. _iterator_for_each(iterator_info *ii, netsnmp_container_obj_func *f,
  361.                    void *ctx)
  362. {
  363.     int rc = SNMP_ERR_NOERROR;
  364.     netsnmp_ref_void loop_ctx = { NULL };
  365.     netsnmp_ref_void tmp = { NULL };
  366.     DEBUGMSGT(("container_iterator",">%sn", "_iterator_foreach"));
  367.     
  368.     if(NULL == ii)
  369.         return;
  370.     if(ii->init_loop_ctx)
  371.         ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
  372.     
  373.     for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
  374.          NULL != tmp.val;
  375.          rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
  376.         (*f) (tmp.val, ctx);
  377.     if(ii->cleanup_loop_ctx)
  378.         ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
  379. }
  380. static void
  381. _iterator_clear(netsnmp_container *container, netsnmp_container_obj_func *f,
  382.                  void *context)
  383. {
  384.     snmp_log(LOG_WARNING,"clear is meaningless for iterator container.n");
  385. }
  386. /**********************************************************************
  387.  *
  388.  */
  389. netsnmp_container*
  390. netsnmp_container_iterator_get(void *iterator_user_ctx,
  391.                                netsnmp_container_compare * compare,
  392.                                Netsnmp_Iterator_Loop_Key * get_first,
  393.                                Netsnmp_Iterator_Loop_Key * get_next,
  394.                                Netsnmp_Iterator_Loop_Data * get_data,
  395.                                Netsnmp_Iterator_Ctx_Dup * save_pos,
  396.                                Netsnmp_Iterator_Ctx * init_loop_ctx,
  397.                                Netsnmp_Iterator_Ctx * cleanup_loop_ctx,
  398.                                Netsnmp_Iterator_Data * free_user_ctx,
  399.                                int sorted)
  400. {
  401.     iterator_info *ii;
  402.     /*
  403.      * sanity checks
  404.      */
  405.     if(get_data && ! save_pos) {
  406.         snmp_log(LOG_ERR, "save_pos required with get_datan");
  407.         return NULL;
  408.     }
  409.     /*
  410.      * allocate memory
  411.      */
  412.     ii = SNMP_MALLOC_TYPEDEF(iterator_info);
  413.     if (NULL==ii) {
  414.         snmp_log(LOG_ERR, "couldn't allocate memoryn");
  415.         return NULL;
  416.     }
  417.     /*
  418.      * init container structure with iterator functions
  419.      */
  420.     ii->c.cfree = (netsnmp_container_rc*)_iterator_free;
  421.     ii->c.compare = compare;
  422.     ii->c.get_size = (netsnmp_container_size*)_iterator_size;
  423.     ii->c.init = NULL;
  424.     ii->c.insert = (netsnmp_container_op*)_iterator_insert;
  425.     ii->c.remove = (netsnmp_container_op*)_iterator_remove;
  426.     ii->c.release = (netsnmp_container_op*)_iterator_release;
  427.     ii->c.find = (netsnmp_container_rtn*)_iterator_find;
  428.     ii->c.find_next = (netsnmp_container_rtn*)_iterator_find_next;
  429.     ii->c.get_subset = NULL;
  430.     ii->c.get_iterator = NULL;
  431.     ii->c.for_each = (netsnmp_container_func*)_iterator_for_each;
  432.     ii->c.clear = _iterator_clear;
  433.     /*
  434.      * init iterator structure with user functions
  435.      */
  436.     ii->get_first = get_first;
  437.     ii->get_next = get_next;
  438.     ii->get_data = get_data;
  439.     ii->save_pos = save_pos;
  440.     ii->init_loop_ctx = init_loop_ctx;
  441.     ii->cleanup_loop_ctx = cleanup_loop_ctx;
  442.     ii->free_user_ctx = free_user_ctx;
  443.     ii->sorted = sorted;
  444.     ii->user_ctx = iterator_user_ctx;
  445.     return (netsnmp_container*)ii;
  446. }
  447. void
  448. netsnmp_container_iterator_set_data_cb(netsnmp_container *c,
  449.                                        Netsnmp_Iterator_Data * insert_data,
  450.                                        Netsnmp_Iterator_Data * remove_data,
  451.                                        Netsnmp_Iterator_Op * get_size)
  452. {
  453.     iterator_info *ii = (iterator_info *)c;
  454.     if(NULL == ii)
  455.         return;
  456.     
  457.     ii->insert_data = insert_data;
  458.     ii->remove_data = remove_data;
  459.     ii->get_size = get_size;
  460. }