Blame agent/object_monitor.c

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