diff -r 683c5c035a79 -r 445e2cf1c845 components/net-snmp-57/sun/sdk/demo/demo_module_9/demo_module_9.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components/net-snmp-57/sun/sdk/demo/demo_module_9/demo_module_9.c Fri Dec 11 03:49:26 2015 -0800 @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * + * U.S. Government Rights - Commercial software. Government users are subject + * to the Sun Microsystems, Inc. standard license agreement and applicable + * provisions of the FAR and its supplements. + * + * + * This distribution may include materials developed by third parties. Sun, + * Sun Microsystems, the Sun logo and Solaris are trademarks or registered + * trademarks of Sun Microsystems, Inc. in the U.S. and other countries. + * + */ + +/* @example demo_module_9.c + * + * + * This example demonstrates how to implement objects that 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. + * + * This example uses the following features of SMA: + * + * - Use of the instance helper, which registers an exact OID such that GENEXT requests + * are handled entirely by the helper. + * + * - Setting the delegated member of the requests structure to 1 to indicate to the + * agent that this request should be delayed. The agent queues this request + * to be handled later and then is available to handle other requests. The + * agent is not blocked by this request. + * + * - Registering an SNMP alarm to update the results at a later time. + * + */ + +#include +#include +#include +#include "demo_module_9.h" + +// default delay time for SNMP alarm +static u_long delay_time = 1; + +void +init_demo_module_9(void) +{ + static oid my_delayed_oid[] = + { 1, 3, 6, 1, 4, 1,42, 2, 2, 4, 4, 9, 1, 1, 0 }; + + /* + * Creates a registration handler, my_test, and passes + * the pointer it returns to the netsnmp_register_instance + * helper function. + */ + netsnmp_handler_registration *my_test; + DEBUGMSGTL(("demo_module_9", "Initializing\n")); + 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) +{ + /* + This handler is called to handle SNMP GET and SNMP SET + requests for the my_delayed_oid object. If it is called to + handle SNMP GET requests, the handler does not need to + handle a GETNEXT if it is registered as an instance handler. + Instance handlers only deliver one request at a time, so we + do not need to loop over a list of requests. */ + + DEBUGMSGTL(("demo_module_9", "Handler 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 cannot be handled now + * by setting the delegated member of the requests structure + * to 1. The agent queues the request to be handled at a later + * time and continues responding to other client requests. + * + */ + requests->delegated = 1; + DEBUGMSGTL(("demo_module_9", "Delegated is %d\n", + requests->delegated)); + + /* + * 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. + */ + DEBUGMSGTL(("demo_module_9", "Delay is %d\n", + delay_time)); + snmp_alarm_register(delay_time, /* seconds */ + 0, /* dont repeat. */ + return_delayed_response, /* the function + * to call */ + /* + * Create a "cache" of useful + * information that can be retrieved + * at a later time. This argument is + * passed back to the module 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; + + /* + * Make sure the cache created earlier is still + * valid. If not, the request timed out for some reason and we + * do not 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, + */ + reqinfo = cache->reqinfo; + requests = cache->requests; + + DEBUGMSGTL(("demo_module_9", + "continuing delayed request, mode = %d\n", + cache->reqinfo->mode)); + + + /* + * Set delegated to zero to indicate that the request is no longer + * delegated and answer the query. + */ + requests->delegated = 0; + + DEBUGMSGTL(("demo_module_9", "Set delegated to %d\n", + requests->delegated)); + + + switch (cache->reqinfo->mode) { + /* + * Registering as an instance means we do not need to deal with + * GETNEXT processing, so we do not handle it here at all. + * + * However, since the instance handler already reset the mode + * back to GETNEXT from the GET mode, we need to do the + * same thing in both cases. + * + */ + + case MODE_GET: + case MODE_GETNEXT: + /* + * Return the current delay time + */ + DEBUGMSGTL(("demo_module_9", "Got to MODE_GETNEXT\n")); + + snmp_set_var_typed_value(cache->requests->requestvb, + ASN_INTEGER, + (u_char *) & delay_time, + sizeof(delay_time)); + DEBUGMSGTL(("demo_module_9", + "Got delay time = %d\n", + delay_time)); + break; + + case MODE_SET_RESERVE1: + DEBUGMSGTL(("demo_module_9", "Got to MODE_SET_RESERVE1\n")); + + /* + * check type + */ + if (requests->requestvb->type != ASN_INTEGER) { + /* + * If not an integer, return SNMP error. + */ + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_WRONGTYPE); + /* + * Free cache. It is no longer needed. + */ + netsnmp_free_delegated_cache(cache); + return; + } + break; + + case MODE_SET_RESERVE2: + DEBUGMSGTL(("demo_module_9", "Got to MODE_SET_RESERVE2\n")); + /* + * 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: + DEBUGMSGTL(("demo_module_9", "Got to MODE_SET_ACTION\n")); + /* + * Update current value. + */ + delay_time = *(requests->requestvb->val.integer); + DEBUGMSGTL(("demo_module_9", "updated delay_time -> %d\n", + delay_time)); + break; + + case MODE_SET_UNDO: + DEBUGMSGTL(("demo_module_9", "Got to MODE_SET_UNDO\n")); + + /* + * A failure occurred. Reset to the + * previously value by extracting the previosuly + * stored information from 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: + DEBUGMSGTL(("demo_module_9", "Got to MODE_SET_UNDO\n")); + /* + * 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; + } + + /* + * free the information cache + */ + netsnmp_free_delegated_cache(cache); +}