Blame agent/object_monitor.c

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