object_monitor.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:21k
- /*
- * object_monitor.c
- *
- * $Id: object_monitor.c,v 1.6 2002/07/23 19:02:56 rstory Exp $
- *
- * functions and data structures for cooperating code to monitor objects.
- *
- * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
- * WARNING! WARNING!
- * WARNING! WARNING!
- * WARNING! This code is under active development WARNING!
- * WARNING! and is subject to change at any time. WARNING!
- * WARNING! WARNING!
- * WARNING! WARNING!
- * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
- */
- #include <net-snmp/net-snmp-config.h>
- #include <net-snmp/net-snmp-includes.h>
- #include <net-snmp/agent/net-snmp-agent-includes.h>
- #include <net-snmp/library/container.h>
- #include <net-snmp/library/snmp_assert.h>
- #include "net-snmp/agent/object_monitor.h"
- #if ! defined TRUE
- # define TRUE 1
- #elsif TRUE != 1
- error "TRUE != 1"
- #endif
- /**************************************************************************
- *
- * Private data structures
- *
- **************************************************************************/
- /*
- * individual callback info for an object
- */
- typedef struct monitor_info_s {
- /** priority for this callback */
- int priority;
- /** handler that registred to watch this object */
- netsnmp_mib_handler *watcher;
- /** events that the watcher cares about */
- unsigned int events;
- /** callback function */
- netsnmp_object_monitor_callback *cb;
- /** pointer to data from the watcher */
- void *watcher_data;
- struct monitor_info_s *next;
- } monitor_info;
- /*
- * list of watchers for a given object
- */
- typedef struct watcher_list_s {
- /** netsnmp_index must be first! */
- netsnmp_index monitored_object;
- monitor_info *head;
- } watcher_list;
- /*
- * temp holder for ordered list of callbacks
- */
- typedef struct callback_placeholder_s {
- monitor_info *mi;
- netsnmp_monitor_callback_header *cbh;
- struct callback_placeholder_s *next;
- } callback_placeholder;
- /**************************************************************************
- *
- *
- *
- **************************************************************************/
- /*
- * local statics
- */
- static char need_init = 1;
- static netsnmp_container *monitored_objects = NULL;
- static netsnmp_monitor_callback_header *callback_pending_list;
- static callback_placeholder *callback_ready_list;
- /*
- * local prototypes
- */
- static watcher_list *find_watchers(oid * object, size_t oid_len);
- static int insert_watcher(oid *, size_t, monitor_info *);
- static int check_registered(unsigned int event, oid * o, int o_l,
- watcher_list ** pWl, monitor_info ** pMi);
- static void move_pending_to_ready(void);
- /**************************************************************************
- *
- * Public functions
- *
- **************************************************************************/
- /*
- *
- */
- void
- netsnmp_monitor_init(void)
- {
- if (!need_init)
- return;
- callback_pending_list = NULL;
- callback_ready_list = NULL;
- monitored_objects = netsnmp_container_get("object_monitor:binary_array");
- if (NULL != monitored_objects)
- need_init = 0;
- monitored_objects->compare = netsnmp_compare_netsnmp_index;
- monitored_objects->ncompare = netsnmp_ncompare_netsnmp_index;
-
- return;
- }
- /**************************************************************************
- *
- * Registration functions
- *
- **************************************************************************/
- /**
- * Register a callback for the specified object.
- *
- * @param object pointer to the OID of the object to monitor.
- * @param oid_len length of the OID pointed to by object.
- * @param priority the priority to associate with this callback. A
- * higher number indicates higher priority. This
- * allows multiple callbacks for the same object to
- * coordinate the order in which they are called. If
- * two callbacks register with the same priority, the
- * order is undefined.
- * @param events the events which the callback is interested in.
- * @param watcher_data pointer to data that will be supplied to the
- * callback method when an event occurs.
- * @param cb pointer to the function to be called when an event occurs.
- *
- * NOTE: the combination of the object, priority and watcher_data must
- * be unique, as they are the parameters for unregistering a
- * callback.
- *
- * @return SNMPERR_NOERR registration was successful
- * @return SNMPERR_MALLOC memory allocation failed
- * @return SNMPERR_VALUE the combination of the object, priority and
- * watcher_data is not unique.
- */
- int
- netsnmp_monitor_register(oid * object, size_t oid_len, int priority,
- unsigned int events, void *watcher_data,
- netsnmp_object_monitor_callback * cb)
- {
- monitor_info *mi;
- int rc;
- netsnmp_assert(need_init == 0);
- mi = calloc(1, sizeof(monitor_info));
- if (NULL == mi)
- return SNMPERR_MALLOC;
- mi->priority = priority;
- mi->events = events;
- mi->watcher_data = watcher_data;
- mi->cb = cb;
- rc = insert_watcher(object, oid_len, mi);
- if (rc != SNMPERR_SUCCESS)
- free(mi);
- return rc;
- }
- /**
- * Unregister a callback for the specified object.
- *
- * @param object pointer to the OID of the object to monitor.
- * @param oid_len length of the OID pointed to by object.
- * @param priority the priority to associate with this callback.
- * @param watcher_data pointer to data that was supplied when the
- * callback was registered.
- * @param cb pointer to the function to be called when an event occurs.
- */
- int
- netsnmp_monitor_unregister(oid * object, size_t oid_len, int priority,
- void *wd, netsnmp_object_monitor_callback * cb)
- {
- monitor_info *mi, *last;
- watcher_list *wl = find_watchers(object, oid_len);
- if (NULL == wl)
- return SNMPERR_GENERR;
- last = NULL;
- mi = wl->head;
- while (mi) {
- if ((mi->cb == cb) && (mi->priority == priority) &&
- (mi->watcher_data == wd))
- break;
- last = mi;
- mi = mi->next;
- }
- if (NULL == mi)
- return SNMPERR_GENERR;
- if (NULL == last)
- wl->head = mi->next;
- else
- last->next = mi->next;
- if (NULL == wl->head) {
- CONTAINER_REMOVE(monitored_objects, wl);
- free(wl->monitored_object.oids);
- free(wl);
- }
- free(mi);
- return SNMPERR_SUCCESS;
- }
- /**************************************************************************
- *
- * object monitor functions
- *
- **************************************************************************/
- /**
- * Notifies the object monitor of an event.
- *
- * The object monitor funtions will save the callback information
- * until all varbinds in the current PDU have been processed and
- * a response has been sent. At that time, the object monitor will
- * determine if there are any watchers monitoring for the event.
- *
- * NOTE: the actual type of the callback structure may vary. The
- * object monitor functions require only that the start of
- * the structure match the netsnmp_monitor_callback_header
- * structure. It is up to the watcher and monitored objects
- * to agree on the format of other data.
- *
- * @param cbh pointer to a callback header.
- */
- void
- netsnmp_notify_monitor(netsnmp_monitor_callback_header * cbh)
- {
- netsnmp_assert(need_init == 0);
- /*
- * put processing of until response has been sent
- */
- cbh->private = callback_pending_list;
- callback_pending_list = cbh;
- return;
- }
- /**
- * check to see if a registration exists for an object/event combination
- *
- * @param event the event type to check for
- * @param o the oid to check for
- * @param o_l the length of the oid
- *
- * @returns TRUE(1) if a callback is registerd
- * @returns FALSE(0) if no callback is registered
- */
- int
- netsnmp_monitor_check_registered(int event, oid * o, int o_l)
- {
- return check_registered(event, o, o_l, NULL, NULL);
- }
- /**
- * Process all pending callbacks
- *
- * NOTE: this method is not in the public header, as it should only be
- * called in one place, in the agent.
- */
- void
- netsnmp_monitor_process_callbacks(void)
- {
- netsnmp_assert(need_init == 0);
- netsnmp_assert(NULL == callback_ready_list);
- if (NULL == callback_pending_list) {
- DEBUGMSGT(("object_monitor", "No callbacks to process"));
- return;
- }
- DEBUGMSG(("object_monitor", "Checking for registered " "callbacks."));
- /*
- * move an pending notification which has a registered watcher to the
- * ready list. Free any other notifications.
- */
- move_pending_to_ready();
- /*
- * call callbacks
- */
- while (callback_ready_list) {
- /*
- * pop off the first item
- */
- callback_placeholder *current_cbr;
- current_cbr = callback_ready_list;
- callback_ready_list = current_cbr->next;
- /*
- * setup, then call callback
- */
- current_cbr->cbh->watcher_data = current_cbr->mi->watcher_data;
- current_cbr->cbh->priority = current_cbr->mi->priority;
- (*current_cbr->mi->cb) (current_cbr->cbh);
- /*
- * release memory (don't free current_cbr->mi)
- */
- if (--(current_cbr->cbh->refs) == 0) {
- free(current_cbr->cbh->monitored_object.oids);
- free(current_cbr->cbh);
- }
- free(current_cbr);
- /*
- * check for any new pending notifications
- */
- move_pending_to_ready();
- }
- netsnmp_assert(callback_ready_list == NULL);
- netsnmp_assert(callback_pending_list = NULL);
- return;
- }
- /**************************************************************************
- *
- * COOPERATIVE helpers
- *
- **************************************************************************/
- /**
- * Notifies the object monitor of a cooperative event.
- *
- * This convenience function will build a
- * @link netsnmp_monitor_callback_header@endlink and call
- * @link netsnmp_notify_monitor@endlink.
- *
- * @param event the event type
- * @param object pointer to the oid of the object sending the event
- * @param len the lenght of the oid
- * @param oid_steal set to true if the function may keep the pointer
- * to the memory (and free it later). set to false
- * to make the function allocate and copy the oid.
- * @param object_info pointer to data supplied by the object for
- * the callback. This pointer must remain valid,
- * will be provided to each callback registered
- * for the object (i.e. it will not be copied or
- * freed).
- */
- void
- netsnmp_notify_cooperative(int event, oid * o, size_t o_len, char o_steal,
- void *object_info)
- {
- netsnmp_monitor_callback_cooperative *cbh;
- netsnmp_assert(need_init == 0);
- cbh = SNMP_MALLOC_TYPEDEF(netsnmp_monitor_callback_cooperative);
- if (NULL == cbh) {
- snmp_log(LOG_ERR, "could not allocate memory for "
- "cooperative callback");
- return;
- }
- cbh->hdr.event = event;
- cbh->hdr.object_info = object_info;
- cbh->hdr.monitored_object.len = o_len;
- if (o_steal) {
- cbh->hdr.monitored_object.oids = o;
- } else {
- cbh->hdr.monitored_object.oids = snmp_duplicate_objid(o, o_len);
- }
- netsnmp_notify_monitor((netsnmp_monitor_callback_header *) cbh);
- }
- #ifndef DOXYGEN_SHOULD_IGNORE_THIS
- /*************************************************************************
- *************************************************************************
- *************************************************************************
- * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
- * WARNING! WARNING!
- * WARNING! WARNING!
- * WARNING! This code is under active development WARNING!
- * WARNING! and is subject to change at any time. WARNING!
- * WARNING! WARNING!
- * WARNING! WARNING!
- * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
- *************************************************************************
- *************************************************************************
- *************************************************************************
- */
- static watcher_list *
- find_watchers(oid * object, size_t oid_len)
- {
- netsnmp_index oah;
- oah.oids = object;
- oah.len = oid_len;
- return (watcher_list *)CONTAINER_FIND(monitored_objects, &oah);
- }
- static int
- insert_watcher(oid * object, size_t oid_len, monitor_info * mi)
- {
- watcher_list *wl = find_watchers(object, oid_len);
- int rc = SNMPERR_SUCCESS;
- if (NULL != wl) {
- monitor_info *last, *current;
- netsnmp_assert(wl->head != NULL);
- last = NULL;
- current = wl->head;
- while (current) {
- if (mi->priority == current->priority) {
- /*
- * check for duplicate
- */
- if (mi->watcher_data == current->watcher_data)
- return SNMPERR_VALUE; /** duplicate! */
- } else if (mi->priority > current->priority) {
- break;
- }
- last = current;
- current = current->next;
- }
- if (NULL == last) {
- mi->next = wl->head;
- wl->head = mi;
- } else {
- mi->next = last->next;
- last->next = mi;
- }
- } else {
- /*
- * first watcher for this oid; set up list
- */
- wl = SNMP_MALLOC_TYPEDEF(watcher_list);
- if (NULL == wl)
- return SNMPERR_MALLOC;
- /*
- * copy index oid
- */
- wl->monitored_object.len = oid_len;
- wl->monitored_object.oids = malloc(sizeof(oid) * oid_len);
- if (NULL == wl->monitored_object.oids) {
- free(wl);
- return SNMPERR_MALLOC;
- }
- memcpy(wl->monitored_object.oids, object, sizeof(oid) * oid_len);
- /*
- * add watcher, and insert into array
- */
- wl->head = mi;
- mi->next = NULL;
- rc = CONTAINER_INSERT(monitored_objects, wl);
- if (rc) {
- free(wl->monitored_object.oids);
- free(wl);
- return rc;
- }
- }
- return rc;
- }
- /**
- * @internal
- * check to see if a registration exists for an object/event combination
- *
- * @param event the event type to check for
- * @param o the oid to check for
- * @param o_l the length of the oid
- * @param pWl if a pointer to a watcher_list pointer is supplied,
- * upon return the watcher list pointer will be set to
- * the watcher list for the object, or NULL if there are
- * no watchers for the object.
- * @param pMi if a pointer to a monitor_info pointer is supplied,
- * upon return the pointer will be set to the first
- * monitor_info object for the specified event.
- *
- * @returns TRUE(1) if a callback is registerd
- * @returns FALSE(0) if no callback is registered
- */
- static int
- check_registered(unsigned int event, oid * o, int o_l,
- watcher_list ** pWl, monitor_info ** pMi)
- {
- watcher_list *wl;
- monitor_info *mi;
- netsnmp_assert(need_init == 0);
- /*
- * check to see if anyone has registered for callbacks
- * for the object.
- */
- wl = find_watchers(o, o_l);
- if (pWl)
- *pWl = wl;
- if (NULL == wl)
- return 0;
- /*
- * check if any watchers are watching for this specific event
- */
- for (mi = wl->head; mi; mi = mi->next) {
- if (mi->events & event) {
- if (pMi)
- *pMi = mi;
- return TRUE;
- }
- }
- return 0;
- }
- /**
- *@internal
- */
- inline void
- insert_ready(callback_placeholder * new_cbr)
- {
- callback_placeholder *current_cbr, *last_cbr;
- /*
- * insert in callback ready list
- */
- last_cbr = NULL;
- current_cbr = callback_ready_list;
- while (current_cbr) {
- if (new_cbr->mi->priority > current_cbr->mi->priority)
- break;
- last_cbr = current_cbr;
- current_cbr = current_cbr->next;
- }
- if (NULL == last_cbr) {
- new_cbr->next = callback_ready_list;
- callback_ready_list = new_cbr;
- } else {
- new_cbr->next = last_cbr->next;
- last_cbr->next = new_cbr;
- }
- }
- /**
- *@internal
- *
- * move an pending notification which has a registered watcher to the
- * ready list. Free any other notifications.
- */
- static void
- move_pending_to_ready(void)
- {
- /*
- * check to see if anyone has registered for callbacks
- * for each object.
- */
- while (callback_pending_list) {
- watcher_list *wl;
- monitor_info *mi;
- netsnmp_monitor_callback_header *cbp;
- /*
- * pop off first item
- */
- cbp = callback_pending_list;
- callback_pending_list = cbp->private; /** next */
- if (0 == check_registered(cbp->event, cbp->monitored_object.oids,
- cbp->monitored_object.len, &wl,
- &mi)) {
- /*
- * nobody watching, free memory
- */
- free(cbp);
- continue;
- }
- /*
- * Found at least one; check the rest of the list and
- * save callback for processing
- */
- for (; mi; mi = mi->next) {
- callback_placeholder *new_cbr;
- if (0 == (mi->events & cbp->event))
- continue;
- /*
- * create temprory placeholder.
- *
- * I hate to allocate memory here, as I'd like this code to
- * be fast and lean. But I don't have time to think of another
- * solution os this will have to do for now.
- *
- * I need a list of monitor_info (mi) objects for each
- * callback which has registered for the event, and want
- * that list sorted by the priority required by the watcher.
- */
- new_cbr = SNMP_MALLOC_TYPEDEF(callback_placeholder);
- if (NULL == new_cbr) {
- snmp_log(LOG_ERR, "malloc failed, callback dropped.");
- continue;
- }
- new_cbr->cbh = cbp;
- new_cbr->mi = mi;
- ++cbp->refs;
- /*
- * insert in callback ready list
- */
- insert_ready(new_cbr);
- } /** end mi loop */
- } /** end cbp loop */
- netsnmp_assert(callback_pending_list == NULL);
- }
- #if defined TESTING_OBJECT_MONITOR
- /**************************************************************************
- *
- * (untested) TEST CODE
- *
- */
- void
- dummy_callback(netsnmp_monitor_callback_header * cbh)
- {
- printf("Callback received.n");
- }
- void
- dump_watchers(netsnmp_index *oah, void *)
- {
- watcher_list *wl = (watcher_list *) oah;
- netsnmp_monitor_callback_header *cbh = wl->head;
- printf("Watcher List for OID ");
- print_objid(wl->hdr->oids, wl->hdr->len);
- printf("n");
- while (cbh) {
- printf("Priority = %d;, Events = %d; Watcher Data = 0x%xn",
- cbh->priority, cbh->events, cbh->watcher_data);
- cbh = cbh->private;
- }
- }
- void
- main(int argc, char **argv)
- {
- oid object[3] = { 1, 3, 6 };
- int object_len = 3;
- int rc;
- /*
- * init
- */
- netsnmp_monitor_init();
- /*
- * insert an object
- */
- rc = netsnmp_monitor_register(object, object_len, 0,
- EVENT_ROW_ADD, (void *) 0xdeadbeef,
- dummy_callback);
- printf("insert an object: %dn", rc);
- /*
- * insert same object, new priority
- */
- netsnmp_monitor_register(object, object_len, 10,
- EVENT_ROW_ADD, (void *) 0xdeadbeef,
- dummy_callback);
- printf("insert same object, new priority: %dn", rc);
- /*
- * insert same object, same priority, new data
- */
- netsnmp_monitor_register(object, object_len, 10,
- EVENT_ROW_ADD, (void *) 0xbeefdead,
- dummy_callback);
- printf("insert same object, same priority, new data: %dn", rc);
- /*
- * insert same object, same priority, same data
- */
- netsnmp_monitor_register(object, object_len, 10,
- EVENT_ROW_ADD, (void *) 0xbeefdead,
- dummy_callback);
- printf("insert same object, same priority, new data: %dn", rc);
- /*
- * dump table
- */
- CONTAINER_FOR_EACH(monitored_objects, dump_watchers, NULL);
- }
- #endif /** defined TESTING_OBJECT_MONITOR */
- #endif /** DOXYGEN_SHOULD_IGNORE_THIS */