diff options
Diffstat (limited to 'agent/mibgroup/examples/delayed_instance.c')
-rw-r--r-- | agent/mibgroup/examples/delayed_instance.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/agent/mibgroup/examples/delayed_instance.c b/agent/mibgroup/examples/delayed_instance.c new file mode 100644 index 0000000..ea59502 --- /dev/null +++ b/agent/mibgroup/examples/delayed_instance.c @@ -0,0 +1,258 @@ +/** @example delayed_instance.c + * This example implements the netSnmpExampleSleeper object. + * + * It demonstrates 2 things: + * + * - The instance helper, which is a way of registering an exact OID + * such that GENEXT requests are handled entirely by the helper. + * + * - how to implement objects which normally would block the agent as + * it waits for external events in such a way that the agent can + * continue responding to other requests while this implementation + * waits. + * + * - Added bonus: normally the nsTransactionTable is empty, since + * there aren't any outstanding requests generally. When accessed, + * this module will create some however. Try setting + * netSnmpExampleSleeper.0 to 10 and then accessing it (use + * "snmpget -t 15 ..." to access it), and then walk the + * nsTransactionTable from another shell to see that not only is + * the walk not blocked, but that the nsTransactionTable is not + * empty. + * + */ + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#include "delayed_instance.h" + +static u_long delay_time = 1; + +void +init_delayed_instance(void) +{ + static oid my_delayed_oid[] = + { 1, 3, 6, 1, 4, 1, 8072, 2, 1, 2, 0 }; + /* + * delayed handler test + */ + netsnmp_handler_registration *my_test; + + my_test = + netsnmp_create_handler_registration("delayed_instance_example", + delayed_instance_handler, + my_delayed_oid, + OID_LENGTH(my_delayed_oid), + HANDLER_CAN_RWRITE); + + netsnmp_register_instance(my_test); +} + +#define DELAYED_INSTANCE_SET_NAME "test_delayed" + +int +delayed_instance_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + + DEBUGMSGTL(("delayed_instance", "Got request, mode = %d:\n", + reqinfo->mode)); + + switch (reqinfo->mode) { + /* + * here we merely mention that we'll answer this request + * later. we don't actually care about the mode type in this + * example, but for certain cases you may, so I'll leave in the + * otherwise useless switch and case statements + */ + + default: + /* + * mark this variable as something that can't be handled now. + * We'll answer it later. + */ + requests->delegated = 1; + + /* + * register an alarm to update the results at a later + * time. Normally, we might have to query something else + * (like an external request sent to a different network + * or system socket, etc), but for this example we'll do + * something really simply and just insert an alarm for a + * certain period of time + */ + snmp_alarm_register(delay_time, /* seconds */ + 0, /* dont repeat. */ + return_delayed_response, /* the function + * to call */ + /* + * here we create a "cache" of useful + * information that we'll want later + * on. This argument is passed back + * to us in the callback function for + * an alarm + */ + (void *) + netsnmp_create_delegated_cache(handler, + reginfo, + reqinfo, + requests, + NULL)); + break; + + } + + return SNMP_ERR_NOERROR; +} + +void +return_delayed_response(unsigned int clientreg, void *clientarg) +{ + /* + * extract the cache from the passed argument + */ + netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) clientarg; + + netsnmp_request_info *requests; + netsnmp_agent_request_info *reqinfo; + u_long *delay_time_cache = NULL; + + /* + * here we double check that the cache we created earlier is still + * * valid. If not, the request timed out for some reason and we + * * don't need to keep processing things. Should never happen, but + * * this double checks. + */ + cache = netsnmp_handler_check_cache(cache); + + if (!cache) { + snmp_log(LOG_ERR, "illegal call to return delayed response\n"); + return; + } + + /* + * re-establish the previous pointers we are used to having + */ + reqinfo = cache->reqinfo; + requests = cache->requests; + + DEBUGMSGTL(("delayed_instance", + "continuing delayed request, mode = %d\n", + cache->reqinfo->mode)); + + /* + * mention that it's no longer delegated, and we've now answered + * the query (which we'll do down below). + */ + requests->delegated = 0; + + switch (cache->reqinfo->mode) { + /* + * registering as an instance means we don't need to deal with + * getnext processing, so we don't handle it here at all. + * + * However, since the instance handler already reset the mode + * back to GETNEXT from the faked GET mode, we need to do the + * same thing in both cases. This should be fixed in future + * versions of net-snmp hopefully. + */ + + case MODE_GET: + case MODE_GETNEXT: + /* + * return the currend delay time + */ + snmp_set_var_typed_value(cache->requests->requestvb, + ASN_INTEGER, + (u_char *) & delay_time, + sizeof(delay_time)); + break; + +#ifndef NETSNMP_NO_WRITE_SUPPORT + case MODE_SET_RESERVE1: + /* + * check type + */ + if (requests->requestvb->type != ASN_INTEGER) { + /* + * not an integer. Bad dog, no bone. + */ + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_WRONGTYPE); + /* + * we don't need the cache any longer + */ + netsnmp_free_delegated_cache(cache); + return; + } + break; + + case MODE_SET_RESERVE2: + /* + * store old value for UNDO support in the future. + */ + memdup((u_char **) & delay_time_cache, + (u_char *) & delay_time, sizeof(delay_time)); + + /* + * malloc failed + */ + if (delay_time_cache == NULL) { + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_RESOURCEUNAVAILABLE); + netsnmp_free_delegated_cache(cache); + return; + } + + /* + * Add our temporary information to the request itself. + * This is then retrivable later. The free function + * passed auto-frees it when the request is later + * deleted. + */ + netsnmp_request_add_list_data(requests, + netsnmp_create_data_list + (DELAYED_INSTANCE_SET_NAME, + delay_time_cache, free)); + break; + + case MODE_SET_ACTION: + /* + * update current value + */ + delay_time = *(requests->requestvb->val.integer); + DEBUGMSGTL(("testhandler", "updated delay_time -> %ld\n", + delay_time)); + break; + + case MODE_SET_UNDO: + /* + * ack, something somewhere failed. We reset back to the + * previously old value by extracting the previosuly + * stored information back out of the request + */ + delay_time = + *((u_long *) netsnmp_request_get_list_data(requests, + DELAYED_INSTANCE_SET_NAME)); + break; + + case MODE_SET_COMMIT: + case MODE_SET_FREE: + /* + * the only thing to do here is free the old memdup'ed + * value, but it's auto-freed by the datalist recovery, so + * we don't have anything to actually do here + */ + break; +#endif /* NETSNMP_NO_WRITE_SUPPORT */ + } + + /* + * free the information cache + */ + netsnmp_free_delegated_cache(cache); +} |