blob: af6c44d8cd2c531c0335d2cde42714a440fbd067 [file] [log] [blame]
/*
* callback.c: A generic callback mechanism
*/
#include <net-snmp/net-snmp-config.h>
#include <sys/types.h>
#include <stdio.h>
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_WINSOCK_H
#include <winsock.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#if HAVE_DMALLOC_H
#include <dmalloc.h>
#endif
#include <net-snmp/types.h>
#include <net-snmp/output_api.h>
#include <net-snmp/utilities.h>
#include <net-snmp/library/callback.h>
#include <net-snmp/library/snmp_api.h>
static struct snmp_gen_callback
*thecallbacks[MAX_CALLBACK_IDS][MAX_CALLBACK_SUBIDS];
/*
* the chicken. or the egg. You pick.
*/
void
init_callbacks(void)
{
/*
* probably not needed? Should be full of 0's anyway?
*/
/*
* (poses a problem if you put init_callbacks() inside of
* init_snmp() and then want the app to register a callback before
* init_snmp() is called in the first place. -- Wes
*/
/*
* memset(thecallbacks, 0, sizeof(thecallbacks));
*/
DEBUGMSGTL(("callback", "initialized\n"));
}
int
snmp_register_callback(int major, int minor, SNMPCallback * new_callback,
void *arg)
{
return netsnmp_register_callback( major, minor, new_callback, arg, 0);
}
int
netsnmp_register_callback(int major, int minor, SNMPCallback * new_callback,
void *arg, int priority)
{
struct snmp_gen_callback *newscp = NULL, *scp = NULL;
struct snmp_gen_callback **prevNext = &(thecallbacks[major][minor]);
if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
return SNMPERR_GENERR;
}
if ((newscp = SNMP_MALLOC_STRUCT(snmp_gen_callback)) == NULL) {
return SNMPERR_GENERR;
} else {
newscp->priority = priority;
newscp->sc_client_arg = arg;
newscp->sc_callback = new_callback;
newscp->next = NULL;
for (scp = thecallbacks[major][minor]; scp != NULL;
scp = scp->next) {
if (newscp->priority < scp->priority) {
newscp->next = scp;
break;
}
prevNext = &(scp->next);
}
*prevNext = newscp;
DEBUGMSGTL(("callback", "registered (%d,%d) at %p with priority %d\n",
major, minor, newscp, priority));
return SNMPERR_SUCCESS;
}
}
int
snmp_call_callbacks(int major, int minor, void *caller_arg)
{
struct snmp_gen_callback *scp;
unsigned int count = 0;
if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
return SNMPERR_GENERR;
}
DEBUGMSGTL(("callback", "START calling callbacks for maj=%d min=%d\n",
major, minor));
/*
* for each registered callback of type major and minor
*/
for (scp = thecallbacks[major][minor]; scp != NULL; scp = scp->next) {
DEBUGMSGTL(("callback", "calling a callback for maj=%d min=%d\n",
major, minor));
/*
* call them
*/
(*(scp->sc_callback)) (major, minor, caller_arg,
scp->sc_client_arg);
count++;
}
DEBUGMSGTL(("callback",
"END calling callbacks for maj=%d min=%d (%d called)\n",
major, minor, count));
return SNMPERR_SUCCESS;
}
int
snmp_count_callbacks(int major, int minor)
{
int count = 0;
struct snmp_gen_callback *scp;
if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
return SNMPERR_GENERR;
}
for (scp = thecallbacks[major][minor]; scp != NULL; scp = scp->next) {
count++;
}
return count;
}
int
snmp_callback_available(int major, int minor)
{
if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
return SNMPERR_GENERR;
}
if (thecallbacks[major][minor] != NULL) {
return SNMPERR_SUCCESS;
}
return SNMPERR_GENERR;
}
int
snmp_unregister_callback(int major, int minor, SNMPCallback * target,
void *arg, int matchargs)
{
struct snmp_gen_callback *scp = thecallbacks[major][minor];
struct snmp_gen_callback **prevNext = &(thecallbacks[major][minor]);
int count = 0;
while (scp != NULL) {
if ((scp->sc_callback == target) &&
(!matchargs || (scp->sc_client_arg == arg))) {
DEBUGMSGTL(("callback", "unregistering (%d,%d) at %p\n", major,
minor, scp));
*prevNext = scp->next;
SNMP_FREE(scp);
scp = *prevNext;
count++;
} else {
prevNext = &(scp->next);
scp = scp->next;
}
}
return count;
}
void
clear_callback(void)
{
unsigned int i = 0, j = 0;
struct snmp_gen_callback *scp = NULL, *next = NULL;
DEBUGMSGTL(("callback", "clear callback\n"));
for (i = 0; i < MAX_CALLBACK_IDS; i++) {
for (j = 0; j < MAX_CALLBACK_SUBIDS; j++) {
scp = thecallbacks[i][j];
while (scp != NULL) {
next = scp->next;
if (scp->sc_client_arg != NULL)
SNMP_FREE(scp->sc_client_arg);
SNMP_FREE(scp);
scp = next;
}
thecallbacks[i][j] = NULL;
}
}
}
struct snmp_gen_callback *
snmp_callback_list(int major, int minor)
{
return (thecallbacks[major][minor]);
}