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

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * object_monitor.c
  3.  *
  4.  * $Id: object_monitor.c,v 1.6 2002/07/23 19:02:56 rstory Exp $
  5.  *
  6.  * functions and data structures for cooperating code to monitor objects.
  7.  *
  8.  * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
  9.  * WARNING!                                                       WARNING!
  10.  * WARNING!                                                       WARNING!
  11.  * WARNING!         This code is under active development         WARNING!
  12.  * WARNING!         and is subject to change at any time.         WARNING!
  13.  * WARNING!                                                       WARNING!
  14.  * WARNING!                                                       WARNING!
  15.  * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
  16.  */
  17. #include <net-snmp/net-snmp-config.h>
  18. #include <net-snmp/net-snmp-includes.h>
  19. #include <net-snmp/agent/net-snmp-agent-includes.h>
  20. #include <net-snmp/library/container.h>
  21. #include <net-snmp/library/snmp_assert.h>
  22. #include "net-snmp/agent/object_monitor.h"
  23. #if ! defined TRUE
  24. #  define TRUE 1
  25. #elsif TRUE != 1
  26. error "TRUE != 1"
  27. #endif
  28. /**************************************************************************
  29.  *
  30.  * Private data structures
  31.  *
  32.  **************************************************************************/
  33.     /*
  34.      * individual callback info for an object
  35.      */
  36.     typedef struct monitor_info_s {
  37.    /** priority for this callback */
  38.     int             priority;
  39.    /** handler that registred to watch this object */
  40.     netsnmp_mib_handler *watcher;
  41.    /** events that the watcher cares about */
  42.     unsigned int    events;
  43.    /** callback function */
  44.     netsnmp_object_monitor_callback *cb;
  45.    /** pointer to data from the watcher */
  46.     void           *watcher_data;
  47.     struct monitor_info_s *next;
  48. } monitor_info;
  49. /*
  50.  * list of watchers for a given object
  51.  */
  52. typedef struct watcher_list_s {
  53.    /** netsnmp_index must be first! */
  54.     netsnmp_index  monitored_object;
  55.     monitor_info   *head;
  56. } watcher_list;
  57. /*
  58.  * temp holder for ordered list of callbacks
  59.  */
  60. typedef struct callback_placeholder_s {
  61.     monitor_info   *mi;
  62.     netsnmp_monitor_callback_header *cbh;
  63.     struct callback_placeholder_s *next;
  64. } callback_placeholder;
  65. /**************************************************************************
  66.  *
  67.  * 
  68.  *
  69.  **************************************************************************/
  70. /*
  71.  * local statics
  72.  */
  73. static char     need_init = 1;
  74. static netsnmp_container *monitored_objects = NULL;
  75. static netsnmp_monitor_callback_header *callback_pending_list;
  76. static callback_placeholder *callback_ready_list;
  77. /*
  78.  * local prototypes
  79.  */
  80. static watcher_list *find_watchers(oid * object, size_t oid_len);
  81. static int      insert_watcher(oid *, size_t, monitor_info *);
  82. static int      check_registered(unsigned int event, oid * o, int o_l,
  83.                                  watcher_list ** pWl, monitor_info ** pMi);
  84. static void     move_pending_to_ready(void);
  85. /**************************************************************************
  86.  *
  87.  * Public functions
  88.  *
  89.  **************************************************************************/
  90. /*
  91.  * 
  92.  */
  93. void
  94. netsnmp_monitor_init(void)
  95. {
  96.     if (!need_init)
  97.         return;
  98.     callback_pending_list = NULL;
  99.     callback_ready_list = NULL;
  100.     monitored_objects = netsnmp_container_get("object_monitor:binary_array");
  101.     if (NULL != monitored_objects)
  102.         need_init = 0;
  103.     monitored_objects->compare = netsnmp_compare_netsnmp_index;
  104.     monitored_objects->ncompare = netsnmp_ncompare_netsnmp_index;
  105.     
  106.     return;
  107. }
  108. /**************************************************************************
  109.  *
  110.  * Registration functions
  111.  *
  112.  **************************************************************************/
  113. /**
  114.  * Register a callback for the specified object.
  115.  *
  116.  * @param object  pointer to the OID of the object to monitor.
  117.  * @param oid_len length of the OID pointed to by object.
  118.  * @param priority the priority to associate with this callback. A
  119.  *                 higher number indicates higher priority. This
  120.  *                 allows multiple callbacks for the same object to
  121.  *                 coordinate the order in which they are called. If
  122.  *                 two callbacks register with the same priority, the
  123.  *                 order is undefined.
  124.  * @param events  the events which the callback is interested in.
  125.  * @param watcher_data pointer to data that will be supplied to the
  126.  *                     callback method when an event occurs.
  127.  * @param cb pointer to the function to be called when an event occurs.
  128.  *
  129.  * NOTE: the combination of the object, priority and watcher_data must
  130.  *       be unique, as they are the parameters for unregistering a
  131.  *       callback.
  132.  *
  133.  * @return SNMPERR_NOERR registration was successful
  134.  * @return SNMPERR_MALLOC memory allocation failed
  135.  * @return SNMPERR_VALUE the combination of the object, priority and
  136.  *                        watcher_data is not unique.
  137.  */
  138. int
  139. netsnmp_monitor_register(oid * object, size_t oid_len, int priority,
  140.                          unsigned int events, void *watcher_data,
  141.                          netsnmp_object_monitor_callback * cb)
  142. {
  143.     monitor_info   *mi;
  144.     int             rc;
  145.     netsnmp_assert(need_init == 0);
  146.     mi = calloc(1, sizeof(monitor_info));
  147.     if (NULL == mi)
  148.         return SNMPERR_MALLOC;
  149.     mi->priority = priority;
  150.     mi->events = events;
  151.     mi->watcher_data = watcher_data;
  152.     mi->cb = cb;
  153.     rc = insert_watcher(object, oid_len, mi);
  154.     if (rc != SNMPERR_SUCCESS)
  155.         free(mi);
  156.     return rc;
  157. }
  158. /**
  159.  * Unregister a callback for the specified object.
  160.  *
  161.  * @param object  pointer to the OID of the object to monitor.
  162.  * @param oid_len length of the OID pointed to by object.
  163.  * @param priority the priority to associate with this callback.
  164.  * @param watcher_data pointer to data that was supplied when the
  165.  *                     callback was registered.
  166.  * @param cb pointer to the function to be called when an event occurs.
  167.  */
  168. int
  169. netsnmp_monitor_unregister(oid * object, size_t oid_len, int priority,
  170.                            void *wd, netsnmp_object_monitor_callback * cb)
  171. {
  172.     monitor_info   *mi, *last;
  173.     watcher_list   *wl = find_watchers(object, oid_len);
  174.     if (NULL == wl)
  175.         return SNMPERR_GENERR;
  176.     last = NULL;
  177.     mi = wl->head;
  178.     while (mi) {
  179.         if ((mi->cb == cb) && (mi->priority == priority) &&
  180.             (mi->watcher_data == wd))
  181.             break;
  182.         last = mi;
  183.         mi = mi->next;
  184.     }
  185.     if (NULL == mi)
  186.         return SNMPERR_GENERR;
  187.     if (NULL == last)
  188.         wl->head = mi->next;
  189.     else
  190.         last->next = mi->next;
  191.     if (NULL == wl->head) {
  192.         CONTAINER_REMOVE(monitored_objects, wl);
  193.         free(wl->monitored_object.oids);
  194.         free(wl);
  195.     }
  196.     free(mi);
  197.     return SNMPERR_SUCCESS;
  198. }
  199. /**************************************************************************
  200.  *
  201.  * object monitor functions
  202.  *
  203.  **************************************************************************/
  204. /**
  205.  * Notifies the object monitor of an event.
  206.  *
  207.  * The object monitor funtions will save the callback information
  208.  * until all varbinds in the current PDU have been processed and
  209.  * a response has been sent. At that time, the object monitor will
  210.  * determine if there are any watchers monitoring for the event.
  211.  *
  212.  * NOTE: the actual type of the callback structure may vary. The
  213.  *       object monitor functions require only that the start of
  214.  *       the structure match the netsnmp_monitor_callback_header
  215.  *       structure. It is up to the watcher and monitored objects
  216.  *       to agree on the format of other data.
  217.  *
  218.  * @param cbh pointer to a callback header.
  219.  */
  220. void
  221. netsnmp_notify_monitor(netsnmp_monitor_callback_header * cbh)
  222. {
  223.     netsnmp_assert(need_init == 0);
  224.     /*
  225.      * put processing of until response has been sent
  226.      */
  227.     cbh->private = callback_pending_list;
  228.     callback_pending_list = cbh;
  229.     return;
  230. }
  231. /**
  232.  * check to see if a registration exists for an object/event combination
  233.  *
  234.  * @param event the event type to check for
  235.  * @param o     the oid to check for
  236.  * @param o_l   the length of the oid
  237.  *
  238.  * @returns TRUE(1) if a callback is registerd
  239.  * @returns FALSE(0) if no callback is registered
  240.  */
  241. int
  242. netsnmp_monitor_check_registered(int event, oid * o, int o_l)
  243. {
  244.     return check_registered(event, o, o_l, NULL, NULL);
  245. }
  246. /**
  247.  * Process all pending callbacks
  248.  *
  249.  * NOTE: this method is not in the public header, as it should only be
  250.  *       called in one place, in the agent.
  251.  */
  252. void
  253. netsnmp_monitor_process_callbacks(void)
  254. {
  255.     netsnmp_assert(need_init == 0);
  256.     netsnmp_assert(NULL == callback_ready_list);
  257.     if (NULL == callback_pending_list) {
  258.         DEBUGMSGT(("object_monitor", "No callbacks to process"));
  259.         return;
  260.     }
  261.     DEBUGMSG(("object_monitor", "Checking for registered " "callbacks."));
  262.     /*
  263.      * move an pending notification which has a registered watcher to the
  264.      * ready list. Free any other notifications.
  265.      */
  266.     move_pending_to_ready();
  267.     /*
  268.      * call callbacks
  269.      */
  270.     while (callback_ready_list) {
  271.         /*
  272.          * pop off the first item
  273.          */
  274.         callback_placeholder *current_cbr;
  275.         current_cbr = callback_ready_list;
  276.         callback_ready_list = current_cbr->next;
  277.         /*
  278.          * setup, then call callback
  279.          */
  280.         current_cbr->cbh->watcher_data = current_cbr->mi->watcher_data;
  281.         current_cbr->cbh->priority = current_cbr->mi->priority;
  282.         (*current_cbr->mi->cb) (current_cbr->cbh);
  283.         /*
  284.          * release memory (don't free current_cbr->mi)
  285.          */
  286.         if (--(current_cbr->cbh->refs) == 0) {
  287.             free(current_cbr->cbh->monitored_object.oids);
  288.             free(current_cbr->cbh);
  289.         }
  290.         free(current_cbr);
  291.         /*
  292.          * check for any new pending notifications
  293.          */
  294.         move_pending_to_ready();
  295.     }
  296.     netsnmp_assert(callback_ready_list == NULL);
  297.     netsnmp_assert(callback_pending_list = NULL);
  298.     return;
  299. }
  300. /**************************************************************************
  301.  *
  302.  * COOPERATIVE helpers
  303.  *
  304.  **************************************************************************/
  305. /**
  306.  * Notifies the object monitor of a cooperative event.
  307.  *
  308.  * This convenience function will build a
  309.  * @link netsnmp_monitor_callback_header@endlink and call
  310.  * @link netsnmp_notify_monitor@endlink.
  311.  *
  312.  * @param event the event type
  313.  * @param object pointer to the oid of the object sending the event
  314.  * @param len    the lenght of the oid
  315.  * @param oid_steal set to true if the function may keep the pointer
  316.  *                  to the memory (and free it later). set to false
  317.  *                  to make the function allocate and copy the oid.
  318.  * @param object_info pointer to data supplied by the object for
  319.  *                    the callback. This pointer must remain valid,
  320.  *                    will be provided to each callback registered
  321.  *                    for the object (i.e. it will not be copied or
  322.  *                    freed).
  323.  */
  324. void
  325. netsnmp_notify_cooperative(int event, oid * o, size_t o_len, char o_steal,
  326.                            void *object_info)
  327. {
  328.     netsnmp_monitor_callback_cooperative *cbh;
  329.     netsnmp_assert(need_init == 0);
  330.     cbh = SNMP_MALLOC_TYPEDEF(netsnmp_monitor_callback_cooperative);
  331.     if (NULL == cbh) {
  332.         snmp_log(LOG_ERR, "could not allocate memory for "
  333.                  "cooperative callback");
  334.         return;
  335.     }
  336.     cbh->hdr.event = event;
  337.     cbh->hdr.object_info = object_info;
  338.     cbh->hdr.monitored_object.len = o_len;
  339.     if (o_steal) {
  340.         cbh->hdr.monitored_object.oids = o;
  341.     } else {
  342.         cbh->hdr.monitored_object.oids = snmp_duplicate_objid(o, o_len);
  343.     }
  344.     netsnmp_notify_monitor((netsnmp_monitor_callback_header *) cbh);
  345. }
  346. #ifndef DOXYGEN_SHOULD_IGNORE_THIS
  347. /*************************************************************************
  348.  *************************************************************************
  349.  *************************************************************************
  350.  * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
  351.  * WARNING!                                                       WARNING!
  352.  * WARNING!                                                       WARNING!
  353.  * WARNING!         This code is under active development         WARNING!
  354.  * WARNING!         and is subject to change at any time.         WARNING!
  355.  * WARNING!                                                       WARNING!
  356.  * WARNING!                                                       WARNING!
  357.  * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
  358.  *************************************************************************
  359.  *************************************************************************
  360.  *************************************************************************
  361.  */
  362. static watcher_list *
  363. find_watchers(oid * object, size_t oid_len)
  364. {
  365.     netsnmp_index oah;
  366.     oah.oids = object;
  367.     oah.len = oid_len;
  368.     return (watcher_list *)CONTAINER_FIND(monitored_objects, &oah);
  369. }
  370. static int
  371. insert_watcher(oid * object, size_t oid_len, monitor_info * mi)
  372. {
  373.     watcher_list   *wl = find_watchers(object, oid_len);
  374.     int             rc = SNMPERR_SUCCESS;
  375.     if (NULL != wl) {
  376.         monitor_info   *last, *current;
  377.         netsnmp_assert(wl->head != NULL);
  378.         last = NULL;
  379.         current = wl->head;
  380.         while (current) {
  381.             if (mi->priority == current->priority) {
  382.                 /*
  383.                  * check for duplicate
  384.                  */
  385.                 if (mi->watcher_data == current->watcher_data)
  386.                     return SNMPERR_VALUE; /** duplicate! */
  387.             } else if (mi->priority > current->priority) {
  388.                 break;
  389.             }
  390.             last = current;
  391.             current = current->next;
  392.         }
  393.         if (NULL == last) {
  394.             mi->next = wl->head;
  395.             wl->head = mi;
  396.         } else {
  397.             mi->next = last->next;
  398.             last->next = mi;
  399.         }
  400.     } else {
  401.         /*
  402.          * first watcher for this oid; set up list
  403.          */
  404.         wl = SNMP_MALLOC_TYPEDEF(watcher_list);
  405.         if (NULL == wl)
  406.             return SNMPERR_MALLOC;
  407.         /*
  408.          * copy index oid
  409.          */
  410.         wl->monitored_object.len = oid_len;
  411.         wl->monitored_object.oids = malloc(sizeof(oid) * oid_len);
  412.         if (NULL == wl->monitored_object.oids) {
  413.             free(wl);
  414.             return SNMPERR_MALLOC;
  415.         }
  416.         memcpy(wl->monitored_object.oids, object, sizeof(oid) * oid_len);
  417.         /*
  418.          * add watcher, and insert into array
  419.          */
  420.         wl->head = mi;
  421.         mi->next = NULL;
  422.         rc = CONTAINER_INSERT(monitored_objects, wl);
  423.         if (rc) {
  424.             free(wl->monitored_object.oids);
  425.             free(wl);
  426.             return rc;
  427.         }
  428.     }
  429.     return rc;
  430. }
  431. /**
  432.  * @internal
  433.  * check to see if a registration exists for an object/event combination
  434.  *
  435.  * @param event the event type to check for
  436.  * @param o     the oid to check for
  437.  * @param o_l   the length of the oid
  438.  * @param pWl   if a pointer to a watcher_list pointer is supplied,
  439.  *              upon return the watcher list pointer will be set to
  440.  *              the watcher list for the object, or NULL if there are
  441.  *              no watchers for the object.
  442.  * @param pMi   if a pointer to a monitor_info pointer is supplied,
  443.  *              upon return the pointer will be set to the first
  444.  *              monitor_info object for the specified event.
  445.  *
  446.  * @returns TRUE(1) if a callback is registerd
  447.  * @returns FALSE(0) if no callback is registered
  448.  */
  449. static int
  450. check_registered(unsigned int event, oid * o, int o_l,
  451.                  watcher_list ** pWl, monitor_info ** pMi)
  452. {
  453.     watcher_list   *wl;
  454.     monitor_info   *mi;
  455.     netsnmp_assert(need_init == 0);
  456.     /*
  457.      * check to see if anyone has registered for callbacks
  458.      * for the object.
  459.      */
  460.     wl = find_watchers(o, o_l);
  461.     if (pWl)
  462.         *pWl = wl;
  463.     if (NULL == wl)
  464.         return 0;
  465.     /*
  466.      * check if any watchers are watching for this specific event
  467.      */
  468.     for (mi = wl->head; mi; mi = mi->next) {
  469.         if (mi->events & event) {
  470.             if (pMi)
  471.                 *pMi = mi;
  472.             return TRUE;
  473.         }
  474.     }
  475.     return 0;
  476. }
  477. /**
  478.  *@internal
  479.  */
  480. inline void
  481. insert_ready(callback_placeholder * new_cbr)
  482. {
  483.     callback_placeholder *current_cbr, *last_cbr;
  484.     /*
  485.      * insert in callback ready list
  486.      */
  487.     last_cbr = NULL;
  488.     current_cbr = callback_ready_list;
  489.     while (current_cbr) {
  490.         if (new_cbr->mi->priority > current_cbr->mi->priority)
  491.             break;
  492.         last_cbr = current_cbr;
  493.         current_cbr = current_cbr->next;
  494.     }
  495.     if (NULL == last_cbr) {
  496.         new_cbr->next = callback_ready_list;
  497.         callback_ready_list = new_cbr;
  498.     } else {
  499.         new_cbr->next = last_cbr->next;
  500.         last_cbr->next = new_cbr;
  501.     }
  502. }
  503. /**
  504.  *@internal
  505.  *
  506.  * move an pending notification which has a registered watcher to the
  507.  * ready list. Free any other notifications.
  508.  */
  509. static void
  510. move_pending_to_ready(void)
  511. {
  512.     /*
  513.      * check to see if anyone has registered for callbacks
  514.      * for each object.
  515.      */
  516.     while (callback_pending_list) {
  517.         watcher_list   *wl;
  518.         monitor_info   *mi;
  519.         netsnmp_monitor_callback_header *cbp;
  520.         /*
  521.          * pop off first item
  522.          */
  523.         cbp = callback_pending_list;
  524.         callback_pending_list = cbp->private; /** next */
  525.         if (0 == check_registered(cbp->event, cbp->monitored_object.oids,
  526.                                   cbp->monitored_object.len, &wl,
  527.                                   &mi)) {
  528.             /*
  529.              * nobody watching, free memory
  530.              */
  531.             free(cbp);
  532.             continue;
  533.         }
  534.         /*
  535.          * Found at least one; check the rest of the list and
  536.          * save callback for processing
  537.          */
  538.         for (; mi; mi = mi->next) {
  539.             callback_placeholder *new_cbr;
  540.             if (0 == (mi->events & cbp->event))
  541.                 continue;
  542.             /*
  543.              * create temprory placeholder.
  544.              *
  545.              * I hate to allocate memory here, as I'd like this code to
  546.              * be fast and lean. But I don't have time to think of another
  547.              * solution os this will have to do for now.
  548.              *
  549.              * I need a list of monitor_info (mi) objects for each
  550.              * callback which has registered for the event, and want
  551.              * that list sorted by the priority required by the watcher.
  552.              */
  553.             new_cbr = SNMP_MALLOC_TYPEDEF(callback_placeholder);
  554.             if (NULL == new_cbr) {
  555.                 snmp_log(LOG_ERR, "malloc failed, callback dropped.");
  556.                 continue;
  557.             }
  558.             new_cbr->cbh = cbp;
  559.             new_cbr->mi = mi;
  560.             ++cbp->refs;
  561.             /*
  562.              * insert in callback ready list
  563.              */
  564.             insert_ready(new_cbr);
  565.         } /** end mi loop */
  566.     } /** end cbp loop */
  567.     netsnmp_assert(callback_pending_list == NULL);
  568. }
  569. #if defined TESTING_OBJECT_MONITOR
  570. /**************************************************************************
  571.  *
  572.  * (untested) TEST CODE
  573.  *
  574.  */
  575. void
  576. dummy_callback(netsnmp_monitor_callback_header * cbh)
  577. {
  578.     printf("Callback received.n");
  579. }
  580. void
  581. dump_watchers(netsnmp_index *oah, void *)
  582. {
  583.     watcher_list   *wl = (watcher_list *) oah;
  584.     netsnmp_monitor_callback_header *cbh = wl->head;
  585.     printf("Watcher List for OID ");
  586.     print_objid(wl->hdr->oids, wl->hdr->len);
  587.     printf("n");
  588.     while (cbh) {
  589.         printf("Priority = %d;, Events = %d; Watcher Data = 0x%xn",
  590.                cbh->priority, cbh->events, cbh->watcher_data);
  591.         cbh = cbh->private;
  592.     }
  593. }
  594. void
  595. main(int argc, char **argv)
  596. {
  597.     oid             object[3] = { 1, 3, 6 };
  598.     int             object_len = 3;
  599.     int             rc;
  600.     /*
  601.      * init
  602.      */
  603.     netsnmp_monitor_init();
  604.     /*
  605.      * insert an object
  606.      */
  607.     rc = netsnmp_monitor_register(object, object_len, 0,
  608.                                   EVENT_ROW_ADD, (void *) 0xdeadbeef,
  609.                                   dummy_callback);
  610.     printf("insert an object: %dn", rc);
  611.     /*
  612.      * insert same object, new priority
  613.      */
  614.     netsnmp_monitor_register(object, object_len, 10,
  615.                              EVENT_ROW_ADD, (void *) 0xdeadbeef,
  616.                              dummy_callback);
  617.     printf("insert same object, new priority: %dn", rc);
  618.     /*
  619.      * insert same object, same priority, new data
  620.      */
  621.     netsnmp_monitor_register(object, object_len, 10,
  622.                              EVENT_ROW_ADD, (void *) 0xbeefdead,
  623.                              dummy_callback);
  624.     printf("insert same object, same priority, new data: %dn", rc);
  625.     /*
  626.      * insert same object, same priority, same data
  627.      */
  628.     netsnmp_monitor_register(object, object_len, 10,
  629.                              EVENT_ROW_ADD, (void *) 0xbeefdead,
  630.                              dummy_callback);
  631.     printf("insert same object, same priority, new data: %dn", rc);
  632.     /*
  633.      * dump table
  634.      */
  635.     CONTAINER_FOR_EACH(monitored_objects, dump_watchers, NULL);
  636. }
  637. #endif /** defined TESTING_OBJECT_MONITOR */
  638. #endif /** DOXYGEN_SHOULD_IGNORE_THIS */