Blame snmplib/callback.c

Packit fcad23
/*
Packit fcad23
 * callback.c: A generic callback mechanism 
Packit fcad23
 */
Packit fcad23
/* Portions of this file are subject to the following copyright(s).  See
Packit fcad23
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit fcad23
 * that may apply:
Packit fcad23
 */
Packit fcad23
/*
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 */
Packit fcad23
/** @defgroup callback A generic callback mechanism 
Packit fcad23
 *  @ingroup library
Packit fcad23
 * 
Packit fcad23
 *  @{
Packit fcad23
 */
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#include <net-snmp/net-snmp-features.h>
Packit fcad23
#include <sys/types.h>
Packit fcad23
#include <stdio.h>
Packit fcad23
#if HAVE_STDLIB_H
Packit fcad23
#include <stdlib.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_NETINET_IN_H
Packit fcad23
#include <netinet/in.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_STRING_H
Packit fcad23
#include <string.h>
Packit fcad23
#else
Packit fcad23
#include <strings.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_UNISTD_H
Packit fcad23
#include <unistd.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_DMALLOC_H
Packit fcad23
#include <dmalloc.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_SOCKET_H
Packit fcad23
#include <sys/socket.h>
Packit fcad23
#endif
Packit fcad23
#if !defined(mingw32) && defined(HAVE_SYS_TIME_H)
Packit fcad23
#include <sys/time.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/types.h>
Packit fcad23
#include <net-snmp/output_api.h>
Packit fcad23
#include <net-snmp/utilities.h>
Packit fcad23
Packit fcad23
#include <net-snmp/library/callback.h>
Packit fcad23
#include <net-snmp/library/snmp_api.h>
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(callbacks_all, libnetsnmp)
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(callback_count, callbacks_all)
Packit fcad23
netsnmp_feature_child_of(callback_list, callbacks_all)
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * the inline callback methods use major/minor to index into arrays.
Packit fcad23
 * all users in this function do range checking before calling these
Packit fcad23
 * functions, so it is redundant for them to check again. But if you
Packit fcad23
 * want to be paranoid, define this var, and additional range checks
Packit fcad23
 * will be performed.
Packit fcad23
 * #define NETSNMP_PARANOID_LEVEL_HIGH 1 
Packit fcad23
 */
Packit fcad23
Packit fcad23
static int _callback_need_init = 1;
Packit fcad23
static struct snmp_gen_callback
Packit fcad23
               *thecallbacks[MAX_CALLBACK_IDS][MAX_CALLBACK_SUBIDS];
Packit fcad23
Packit fcad23
#define CALLBACK_NAME_LOGGING 1
Packit fcad23
#ifdef CALLBACK_NAME_LOGGING
Packit fcad23
static const char *types[MAX_CALLBACK_IDS] = { "LIB", "APP" };
Packit fcad23
static const char *lib[MAX_CALLBACK_SUBIDS] = {
Packit fcad23
    "POST_READ_CONFIG", /* 0 */
Packit fcad23
    "STORE_DATA", /* 1 */
Packit fcad23
    "SHUTDOWN", /* 2 */
Packit fcad23
    "POST_PREMIB_READ_CONFIG", /* 3 */
Packit fcad23
    "LOGGING", /* 4 */
Packit fcad23
    "SESSION_INIT", /* 5 */
Packit fcad23
    NULL, /* 6 */
Packit fcad23
    NULL, /* 7 */
Packit fcad23
    NULL, /* 8 */
Packit fcad23
    NULL, /* 9 */
Packit fcad23
    NULL, /* 10 */
Packit fcad23
    NULL, /* 11 */
Packit fcad23
    NULL, /* 12 */
Packit fcad23
    NULL, /* 13 */
Packit fcad23
    NULL, /* 14 */
Packit fcad23
    NULL /* 15 */
Packit fcad23
};
Packit fcad23
#endif
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * extremely simplistic locking, just to find problems were the
Packit fcad23
 * callback list is modified while being traversed. Not intended
Packit fcad23
 * to do any real protection, or in any way imply that this code
Packit fcad23
 * has been evaluated for use in a multi-threaded environment.
Packit fcad23
 * In 5.2, it was a single lock. For 5.3, it has been updated to
Packit fcad23
 * a lock per callback, since a particular callback may trigger
Packit fcad23
 * registration/unregistration of other callbacks (eg AgentX
Packit fcad23
 * subagents do this).
Packit fcad23
 */
Packit fcad23
#define LOCK_PER_CALLBACK_SUBID 1
Packit fcad23
#ifdef LOCK_PER_CALLBACK_SUBID
Packit fcad23
static int _locks[MAX_CALLBACK_IDS][MAX_CALLBACK_SUBIDS];
Packit fcad23
#define CALLBACK_LOCK(maj,min) ++_locks[maj][min]
Packit fcad23
#define CALLBACK_UNLOCK(maj,min) --_locks[maj][min]
Packit fcad23
#define CALLBACK_LOCK_COUNT(maj,min) _locks[maj][min]
Packit fcad23
#else
Packit fcad23
static int _lock;
Packit fcad23
#define CALLBACK_LOCK(maj,min) ++_lock
Packit fcad23
#define CALLBACK_UNLOCK(maj,min) --_lock
Packit fcad23
#define CALLBACK_LOCK_COUNT(maj,min) _lock
Packit fcad23
#endif
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE int
Packit fcad23
_callback_lock(int major, int minor, const char* warn, int do_assert)
Packit fcad23
{
Packit fcad23
    int lock_holded=0;
Packit fcad23
    struct timeval lock_time = { 0, 1000 };
Packit fcad23
Packit fcad23
#ifdef NETSNMP_PARANOID_LEVEL_HIGH
Packit fcad23
    if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
Packit fcad23
        netsnmp_assert("bad callback id");
Packit fcad23
        return 1;
Packit fcad23
    }
Packit fcad23
#endif
Packit fcad23
    
Packit fcad23
#ifdef CALLBACK_NAME_LOGGING
Packit fcad23
    DEBUGMSGTL(("9:callback:lock", "locked (%s,%s)\n",
Packit fcad23
                types[major], (SNMP_CALLBACK_LIBRARY == major) ?
Packit fcad23
                SNMP_STRORNULL(lib[minor]) : "null"));
Packit fcad23
#endif
Packit fcad23
    while (CALLBACK_LOCK_COUNT(major,minor) >= 1 && ++lock_holded < 100)
Packit fcad23
	select(0, NULL, NULL, NULL, &lock_time);
Packit fcad23
Packit fcad23
    if(lock_holded >= 100) {
Packit fcad23
        if (NULL != warn)
Packit fcad23
            snmp_log(LOG_WARNING,
Packit fcad23
                     "lock in _callback_lock sleeps more than 100 milliseconds in %s\n", warn);
Packit fcad23
        if (do_assert)
Packit fcad23
            netsnmp_assert(lock_holded < 100);
Packit fcad23
        
Packit fcad23
        return 1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    CALLBACK_LOCK(major,minor);
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
_callback_unlock(int major, int minor)
Packit fcad23
{
Packit fcad23
#ifdef NETSNMP_PARANOID_LEVEL_HIGH
Packit fcad23
    if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
Packit fcad23
        netsnmp_assert("bad callback id");
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
#endif
Packit fcad23
    
Packit fcad23
    CALLBACK_UNLOCK(major,minor);
Packit fcad23
Packit fcad23
#ifdef CALLBACK_NAME_LOGGING
Packit fcad23
    DEBUGMSGTL(("9:callback:lock", "unlocked (%s,%s)\n",
Packit fcad23
                types[major], (SNMP_CALLBACK_LIBRARY == major) ?
Packit fcad23
                SNMP_STRORNULL(lib[minor]) : "null"));
Packit fcad23
#endif
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * the chicken. or the egg.  You pick. 
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
init_callbacks(void)
Packit fcad23
{
Packit fcad23
    /*
Packit fcad23
     * (poses a problem if you put init_callbacks() inside of
Packit fcad23
     * init_snmp() and then want the app to register a callback before
Packit fcad23
     * init_snmp() is called in the first place.  -- Wes 
Packit fcad23
     */
Packit fcad23
    if (0 == _callback_need_init)
Packit fcad23
        return;
Packit fcad23
    
Packit fcad23
    _callback_need_init = 0;
Packit fcad23
    
Packit fcad23
    memset(thecallbacks, 0, sizeof(thecallbacks)); 
Packit fcad23
#ifdef LOCK_PER_CALLBACK_SUBID
Packit fcad23
    memset(_locks, 0, sizeof(_locks));
Packit fcad23
#else
Packit fcad23
    _lock = 0;
Packit fcad23
#endif
Packit fcad23
    
Packit fcad23
    DEBUGMSGTL(("callback", "initialized\n"));
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * This function registers a generic callback function.  The major and
Packit fcad23
 * minor values are used to set the new_callback function into a global 
Packit fcad23
 * static multi-dimensional array of type struct snmp_gen_callback.  
Packit fcad23
 * The function makes sure to append this callback function at the end
Packit fcad23
 * of the link list, snmp_gen_callback->next.
Packit fcad23
 *
Packit fcad23
 * @param major is the SNMP callback major type used
Packit fcad23
 * 		- SNMP_CALLBACK_LIBRARY
Packit fcad23
 *              - SNMP_CALLBACK_APPLICATION
Packit fcad23
 *
Packit fcad23
 * @param minor is the SNMP callback minor type used
Packit fcad23
 *		- SNMP_CALLBACK_POST_READ_CONFIG
Packit fcad23
 *		- SNMP_CALLBACK_STORE_DATA	        
Packit fcad23
 *		- SNMP_CALLBACK_SHUTDOWN		        
Packit fcad23
 *		- SNMP_CALLBACK_POST_PREMIB_READ_CONFIG	
Packit fcad23
 *		- SNMP_CALLBACK_LOGGING			
Packit fcad23
 *		- SNMP_CALLBACK_SESSION_INIT	       
Packit fcad23
 *
Packit fcad23
 * @param new_callback is the callback function that is registered.
Packit fcad23
 *
Packit fcad23
 * @param arg when not NULL is a void pointer used whenever new_callback 
Packit fcad23
 *	function is exercised. Ownership is transferred to the twodimensional
Packit fcad23
 *      thecallbacks[][] array. The function clear_callback() will deallocate
Packit fcad23
 *      the memory pointed at by calling free().
Packit fcad23
 *
Packit fcad23
 * @return 
Packit fcad23
 *	Returns SNMPERR_GENERR if major is >= MAX_CALLBACK_IDS or minor is >=
Packit fcad23
 *	MAX_CALLBACK_SUBIDS or a snmp_gen_callback pointer could not be 
Packit fcad23
 *	allocated, otherwise SNMPERR_SUCCESS is returned.
Packit fcad23
 * 	- \#define MAX_CALLBACK_IDS    2
Packit fcad23
 *	- \#define MAX_CALLBACK_SUBIDS 16
Packit fcad23
 *
Packit fcad23
 * @see snmp_call_callbacks
Packit fcad23
 * @see snmp_unregister_callback
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
snmp_register_callback(int major, int minor, SNMPCallback * new_callback,
Packit fcad23
                       void *arg)
Packit fcad23
{
Packit fcad23
    return netsnmp_register_callback( major, minor, new_callback, arg,
Packit fcad23
                                      NETSNMP_CALLBACK_DEFAULT_PRIORITY);
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * Register a callback function.
Packit fcad23
 *
Packit fcad23
 * @param major        Major callback event type.
Packit fcad23
 * @param minor        Minor callback event type.
Packit fcad23
 * @param new_callback Callback function being registered.
Packit fcad23
 * @param arg          Argument that will be passed to the callback function.
Packit fcad23
 * @param priority     Handler invocation priority. When multiple handlers have
Packit fcad23
 *   been registered for the same (major, minor) callback event type, handlers
Packit fcad23
 *   with the numerically lowest priority will be invoked first. Handlers with
Packit fcad23
 *   identical priority are invoked in the order they have been registered.
Packit fcad23
 *
Packit fcad23
 * @see snmp_register_callback
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_register_callback(int major, int minor, SNMPCallback * new_callback,
Packit fcad23
                          void *arg, int priority)
Packit fcad23
{
Packit fcad23
    struct snmp_gen_callback *newscp = NULL, *scp = NULL;
Packit fcad23
    struct snmp_gen_callback **prevNext = &(thecallbacks[major][minor]);
Packit fcad23
Packit fcad23
    if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (_callback_need_init)
Packit fcad23
        init_callbacks();
Packit fcad23
Packit fcad23
    _callback_lock(major,minor, "netsnmp_register_callback", 1);
Packit fcad23
    
Packit fcad23
    if ((newscp = SNMP_MALLOC_STRUCT(snmp_gen_callback)) == NULL) {
Packit fcad23
        _callback_unlock(major,minor);
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    } else {
Packit fcad23
        newscp->priority = priority;
Packit fcad23
        newscp->sc_client_arg = arg;
Packit fcad23
        newscp->sc_callback = new_callback;
Packit fcad23
        newscp->next = NULL;
Packit fcad23
Packit fcad23
        for (scp = thecallbacks[major][minor]; scp != NULL;
Packit fcad23
             scp = scp->next) {
Packit fcad23
            if (newscp->priority < scp->priority) {
Packit fcad23
                newscp->next = scp;
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
            prevNext = &(scp->next);
Packit fcad23
        }
Packit fcad23
Packit fcad23
        *prevNext = newscp;
Packit fcad23
Packit fcad23
        DEBUGMSGTL(("callback", "registered (%d,%d) at %p with priority %d\n",
Packit fcad23
                    major, minor, newscp, priority));
Packit fcad23
        _callback_unlock(major,minor);
Packit fcad23
        return SNMPERR_SUCCESS;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * This function calls the callback function for each registered callback of
Packit fcad23
 * type major and minor.
Packit fcad23
 *
Packit fcad23
 * @param major is the SNMP callback major type used
Packit fcad23
 *
Packit fcad23
 * @param minor is the SNMP callback minor type used
Packit fcad23
 *
Packit fcad23
 * @param caller_arg is a void pointer which is sent in as the callback's 
Packit fcad23
 *	serverarg parameter, if needed.
Packit fcad23
 *
Packit fcad23
 * @return Returns SNMPERR_GENERR if major is >= MAX_CALLBACK_IDS or
Packit fcad23
 * minor is >= MAX_CALLBACK_SUBIDS, otherwise SNMPERR_SUCCESS is returned.
Packit fcad23
 *
Packit fcad23
 * @see snmp_register_callback
Packit fcad23
 * @see snmp_unregister_callback
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
snmp_call_callbacks(int major, int minor, void *caller_arg)
Packit fcad23
{
Packit fcad23
    struct snmp_gen_callback *scp;
Packit fcad23
    unsigned int    count = 0;
Packit fcad23
    
Packit fcad23
    if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (_callback_need_init)
Packit fcad23
        init_callbacks();
Packit fcad23
Packit fcad23
#ifdef LOCK_PER_CALLBACK_SUBID
Packit fcad23
    _callback_lock(major,minor,"snmp_call_callbacks", 1);
Packit fcad23
#else
Packit fcad23
    /*
Packit fcad23
     * Notes:
Packit fcad23
     * - this gets hit the first time a trap is sent after a new trap
Packit fcad23
     *   destination has been added (session init cb during send trap cb)
Packit fcad23
     */
Packit fcad23
    _callback_lock(major,minor, NULL, 0);
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("callback", "START calling callbacks for maj=%d min=%d\n",
Packit fcad23
                major, minor));
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * for each registered callback of type major and minor 
Packit fcad23
     */
Packit fcad23
    for (scp = thecallbacks[major][minor]; scp != NULL; scp = scp->next) {
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * skip unregistered callbacks
Packit fcad23
         */
Packit fcad23
        if(NULL == scp->sc_callback)
Packit fcad23
            continue;
Packit fcad23
Packit fcad23
        DEBUGMSGTL(("callback", "calling a callback for maj=%d min=%d\n",
Packit fcad23
                    major, minor));
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * call them 
Packit fcad23
         */
Packit fcad23
        (*(scp->sc_callback)) (major, minor, caller_arg,
Packit fcad23
                               scp->sc_client_arg);
Packit fcad23
        count++;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("callback",
Packit fcad23
                "END calling callbacks for maj=%d min=%d (%d called)\n",
Packit fcad23
                major, minor, count));
Packit fcad23
Packit fcad23
    _callback_unlock(major,minor);
Packit fcad23
    return SNMPERR_SUCCESS;
Packit fcad23
}
Packit fcad23
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_CALLBACK_COUNT
Packit fcad23
int
Packit fcad23
snmp_count_callbacks(int major, int minor)
Packit fcad23
{
Packit fcad23
    int             count = 0;
Packit fcad23
    struct snmp_gen_callback *scp;
Packit fcad23
Packit fcad23
    if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (_callback_need_init)
Packit fcad23
        init_callbacks();
Packit fcad23
Packit fcad23
    for (scp = thecallbacks[major][minor]; scp != NULL; scp = scp->next) {
Packit fcad23
        count++;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return count;
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_CALLBACK_COUNT */
Packit fcad23
Packit fcad23
int
Packit fcad23
snmp_callback_available(int major, int minor)
Packit fcad23
{
Packit fcad23
    if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (_callback_need_init)
Packit fcad23
        init_callbacks();
Packit fcad23
Packit fcad23
    if (thecallbacks[major][minor] != NULL) {
Packit fcad23
        return SNMPERR_SUCCESS;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return SNMPERR_GENERR;
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * This function unregisters a specified callback function given a major
Packit fcad23
 * and minor type.
Packit fcad23
 *
Packit fcad23
 * Note: no bound checking on major and minor.
Packit fcad23
 *
Packit fcad23
 * @param major is the SNMP callback major type used
Packit fcad23
 *
Packit fcad23
 * @param minor is the SNMP callback minor type used
Packit fcad23
 *
Packit fcad23
 * @param target is the callback function that will be unregistered.
Packit fcad23
 *
Packit fcad23
 * @param arg is a void pointer used for comparison against the registered 
Packit fcad23
 *	callback's sc_client_arg variable.
Packit fcad23
 *
Packit fcad23
 * @param matchargs is an integer used to bypass the comparison of arg and the
Packit fcad23
 *	callback's sc_client_arg variable only when matchargs is set to 0.
Packit fcad23
 *
Packit fcad23
 *
Packit fcad23
 * @return
Packit fcad23
 *        Returns the number of callbacks that were unregistered.
Packit fcad23
 *
Packit fcad23
 * @see snmp_register_callback
Packit fcad23
 * @see snmp_call_callbacks
Packit fcad23
 */
Packit fcad23
Packit fcad23
int
Packit fcad23
snmp_unregister_callback(int major, int minor, SNMPCallback * target,
Packit fcad23
                         void *arg, int matchargs)
Packit fcad23
{
Packit fcad23
    struct snmp_gen_callback *scp;
Packit fcad23
    struct snmp_gen_callback **prevNext;
Packit fcad23
    int             count = 0;
Packit fcad23
Packit fcad23
    if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS)
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
Packit fcad23
    scp = thecallbacks[major][minor];
Packit fcad23
    prevNext = &(thecallbacks[major][minor]);
Packit fcad23
Packit fcad23
    if (_callback_need_init)
Packit fcad23
        init_callbacks();
Packit fcad23
Packit fcad23
#ifdef LOCK_PER_CALLBACK_SUBID
Packit fcad23
    _callback_lock(major,minor,"snmp_unregister_callback", 1);
Packit fcad23
#else
Packit fcad23
    /*
Packit fcad23
     * Notes;
Packit fcad23
     * - this gets hit at shutdown, during cleanup. No easy fix.
Packit fcad23
     */
Packit fcad23
    _callback_lock(major,minor,"snmp_unregister_callback", 0);
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    while (scp != NULL) {
Packit fcad23
        if ((scp->sc_callback == target) &&
Packit fcad23
            (!matchargs || (scp->sc_client_arg == arg))) {
Packit fcad23
            DEBUGMSGTL(("callback", "unregistering (%d,%d) at %p\n", major,
Packit fcad23
                        minor, scp));
Packit fcad23
            if(1 == CALLBACK_LOCK_COUNT(major,minor)) {
Packit fcad23
                *prevNext = scp->next;
Packit fcad23
                SNMP_FREE(scp);
Packit fcad23
                scp = *prevNext;
Packit fcad23
            }
Packit fcad23
            else {
Packit fcad23
                scp->sc_callback = NULL;
Packit fcad23
                /** set cleanup flag? */
Packit fcad23
            }
Packit fcad23
            count++;
Packit fcad23
        } else {
Packit fcad23
            prevNext = &(scp->next);
Packit fcad23
            scp = scp->next;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    _callback_unlock(major,minor);
Packit fcad23
    return count;
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * find and clear client args that match ptr
Packit fcad23
 *
Packit fcad23
 * @param ptr  pointer to search for
Packit fcad23
 * @param i    callback id to start at
Packit fcad23
 * @param j    callback subid to start at
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_callback_clear_client_arg(void *ptr, int i, int j)
Packit fcad23
{
Packit fcad23
    struct snmp_gen_callback *scp = NULL;
Packit fcad23
    int rc = 0;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * don't init i and j before loop, since the caller specified
Packit fcad23
     * the starting point explicitly. But *after* the i loop has
Packit fcad23
     * finished executing once, init j to 0 for the next pass
Packit fcad23
     * through the subids.
Packit fcad23
     */
Packit fcad23
    for (; i < MAX_CALLBACK_IDS; i++,j=0) {
Packit fcad23
        for (; j < MAX_CALLBACK_SUBIDS; j++) {
Packit fcad23
            scp = thecallbacks[i][j]; 
Packit fcad23
            while (scp != NULL) {
Packit fcad23
                if ((NULL != scp->sc_callback) &&
Packit fcad23
                    (scp->sc_client_arg != NULL) &&
Packit fcad23
                    (scp->sc_client_arg == ptr)) {
Packit fcad23
                    DEBUGMSGTL(("9:callback", "  clearing %p at [%d,%d]\n", ptr, i, j));
Packit fcad23
                    scp->sc_client_arg = NULL;
Packit fcad23
                    ++rc;
Packit fcad23
                }
Packit fcad23
                scp = scp->next;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (0 != rc) {
Packit fcad23
        DEBUGMSGTL(("callback", "removed %d client args\n", rc));
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return rc;
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
clear_callback(void)
Packit fcad23
{
Packit fcad23
    unsigned int i = 0, j = 0;
Packit fcad23
    struct snmp_gen_callback *scp = NULL;
Packit fcad23
Packit fcad23
    if (_callback_need_init)
Packit fcad23
        init_callbacks();
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("callback", "clear callback\n"));
Packit fcad23
    for (i = 0; i < MAX_CALLBACK_IDS; i++) {
Packit fcad23
        for (j = 0; j < MAX_CALLBACK_SUBIDS; j++) {
Packit fcad23
            _callback_lock(i,j, "clear_callback", 1);
Packit fcad23
            scp = thecallbacks[i][j];
Packit fcad23
            while (scp != NULL) {
Packit fcad23
                thecallbacks[i][j] = scp->next;
Packit fcad23
                /*
Packit fcad23
                 * if there is a client arg, check for duplicates
Packit fcad23
                 * and then free it.
Packit fcad23
                 */
Packit fcad23
                if ((NULL != scp->sc_callback) &&
Packit fcad23
                    (scp->sc_client_arg != NULL)) {
Packit fcad23
                    void *tmp_arg;
Packit fcad23
                    /*
Packit fcad23
                     * save the client arg, then set it to null so that it
Packit fcad23
                     * won't look like a duplicate, then check for duplicates
Packit fcad23
                     * starting at the current i,j (earlier dups should have
Packit fcad23
                     * already been found) and free the pointer.
Packit fcad23
                     */
Packit fcad23
                    tmp_arg = scp->sc_client_arg;
Packit fcad23
                    scp->sc_client_arg = NULL;
Packit fcad23
                    DEBUGMSGTL(("9:callback", "  freeing %p at [%d,%d]\n", tmp_arg, i, j));
Packit fcad23
                    (void)netsnmp_callback_clear_client_arg(tmp_arg, i, j);
Packit fcad23
                    free(tmp_arg);
Packit fcad23
                }
Packit fcad23
                SNMP_FREE(scp);
Packit fcad23
                scp = thecallbacks[i][j];
Packit fcad23
            }
Packit fcad23
            _callback_unlock(i,j);
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_CALLBACK_LIST
Packit fcad23
struct snmp_gen_callback *
Packit fcad23
snmp_callback_list(int major, int minor)
Packit fcad23
{
Packit fcad23
    if (_callback_need_init)
Packit fcad23
        init_callbacks();
Packit fcad23
Packit fcad23
    return (thecallbacks[major][minor]);
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_CALLBACK_LIST */
Packit fcad23
/**  @} */