components/net-snmp/sun/sdk/demo/demo_module_10/demo_module_10.c
changeset 252 ee0fb1eabcbf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/net-snmp/sun/sdk/demo/demo_module_10/demo_module_10.c	Fri May 20 12:17:45 2011 +0530
@@ -0,0 +1,469 @@
+/*
+ * 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.
+ *
+ */
+ 
+/*
+ * Note: this file originally auto-generated by mib2c using :
+ * mib2c.scalar.conf,v 1.5 2002/07/18 14:18:52 dts12 Exp $
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <time.h>
+#include "demo_module_10.h"
+
+// Default scalar data value
+static long exampleData = 0;
+
+// Status of data collection
+static u_long status = 0;
+
+// Default delay time
+static u_long delay_time = 2;
+
+// Default alarm interval
+static u_long alarm_time = 5;
+
+// Data collection timestamp
+char refreshTime[256];
+
+// System date/time
+time_t mytime;
+
+
+/*
+   The following code example demonstrates a module design that handles
+   long running data collections so that their values can be polled by
+   an SNMP manager. The example also shows 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:
+
+   - 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. 
+
+   - Use of a status variable to communicate the status of a data collection to
+     the polling SNMP manager.
+
+   - Use of a refreshTime variable to return the date and time that the data collection
+     completed.
+*/
+
+/*  Initialialization routine that is automatically called by the agent.
+    The function name must match init_FILENAME() */
+
+void
+init_demo_module_10(void)
+{
+	/*
+	 * the OID at which to register the exampleData variable.
+	 */
+	static oid longRunScalar_oid[] =
+	    {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 10, 1, 1, 0};
+
+	/*
+	 * the OID at which to register the status variable.
+	 */
+	static oid status_oid[] =
+	    {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 10, 1, 2, 0};
+	
+	/*
+	 * the OID at which to register the refreshTime variable.
+	 */
+	static oid refreshTime_oid[] =
+	    {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 10, 1, 3, 0};
+
+	
+
+	netsnmp_handler_registration *myreg;
+
+	/*
+	 * A debugging statement.  Run the agent with -Ddemo_module_10 to see
+	 * the output of this debugging statement in /var/log/snmpd.log, by
+	 * default. Use the -L option to write debugging output to the
+	 * screen.
+	 */
+		DEBUGMSGTL(("demo_module_10", "Initializing\n"));
+	/*
+	 * Creates a read-only registration handler named longRunScalar,
+	 * which calls the get_longRunScalar function to service snmp
+	 * requests for the longRunScalar_oid object.  The OID_LENGTH
+	 * argument calculates the length of the longRunScalar_oid.
+	 */
+	myreg = netsnmp_create_handler_registration
+		       ("longRunScalar",
+			get_longRunScalar,
+			longRunScalar_oid,
+			OID_LENGTH(longRunScalar_oid),
+			HANDLER_CAN_RONLY);
+	/*
+	 * Register the instance and handler.
+	 *
+	 */
+	netsnmp_register_read_only_instance(myreg);
+
+	/*
+	 * Creates a read/write registration handler named getStatus,
+	 * which calls the get_status function to service snmp
+	 * requests for the status_oid object.  The OID_LENGTH
+	 * argument calculates the length of the status_oid.
+	 */
+	
+	myreg = netsnmp_create_handler_registration
+		       ("delayed_instance_handler",
+			delayed_instance_handler,
+			status_oid,
+			OID_LENGTH(status_oid),
+			HANDLER_CAN_RWRITE);
+	/*
+	 * Register the instance and handler.
+	 *
+	 */
+	netsnmp_register_instance(myreg);
+
+
+	/*
+	 * Creates a read-only registration handler named getTimestamp,
+	 * which calls the get_timestamp function to service snmp
+	 * get requests for the timestamp_oid object.  The OID_LENGTH
+	 * argument calculates the length of the timestamp_oid.
+	 */
+	
+	myreg = netsnmp_create_handler_registration
+		       ("getTimestamp",
+			get_timestamp,
+			refreshTime_oid,
+			OID_LENGTH(refreshTime_oid),
+			HANDLER_CAN_RONLY);
+	/*
+	 * Register the instance and handler.
+	 *
+	 */
+	netsnmp_register_instance(myreg);
+
+}
+
+#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_10", "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_10", "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. 
+         */
+        snmp_alarm_register(alarm_time, /* seconds */
+                            0,  /* dont repeat. */
+	                    get_status,   /* 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;
+}
+
+
+int
+get_longRunScalar(netsnmp_mib_handler * handler,
+	netsnmp_handler_registration * reginfo,
+	netsnmp_agent_request_info * reqinfo,
+	netsnmp_request_info * requests)
+{
+	/*
+	 * This handler returns the data from the data collection, if the
+	 * collection has finished.  If the collection has not finished.
+	 * it returns an SNMP_ERR_NOACCESS error.
+	 *
+	 * This handler is never called for a getnext if it is registered as
+	 * an instance. An instance handler only delivers one request at a
+	 * time, so we do not need to loop over a list of requests.
+	 */
+	switch (reqinfo->mode) {
+	case MODE_GET:
+		// if collection done, return data; else return snmp error
+		if (status == 2)
+			snmp_set_var_typed_value(requests->requestvb,
+			ASN_INTEGER, (u_char *) & exampleData,
+			sizeof (exampleData) /* length in bytes */);
+		else
+			netsnmp_set_request_error(reqinfo, requests,
+                                      SNMP_ERR_NOACCESS);
+		break;
+	default:
+		/*
+		 * We should never get here, so this is a really bad error.
+		 */
+		return (SNMP_ERR_GENERR);
+	}
+	return (SNMP_ERR_NOERROR);
+}
+
+int
+get_timestamp(netsnmp_mib_handler * handler,
+	netsnmp_handler_registration * reginfo,
+	netsnmp_agent_request_info * reqinfo,
+	netsnmp_request_info * requests)
+{
+	/*
+	 * This handler returns the date and time of the current data
+	 * collection. If the collection has not completed, it returns
+	 * an SNMP_ERR_NOACCESS error.
+	 *
+	 * This handler is never called for a getnext if it is registered as
+	 * an instance. An instance handler only delivers one request at a
+	 * time, so we do not need to loop over a list of requests.
+	 */
+	DEBUGMSGTL(("demo_module_10", "get_timestamp CALLED\n"));
+
+	switch (reqinfo->mode) {
+	case MODE_GET:
+		// A data collection is ready. Return its timestamp.
+		if (status == 2)
+			snmp_set_var_typed_value(requests->requestvb,
+			    ASN_OCTET_STR, (u_char *)refreshTime,
+			    sizeof (refreshTime));
+		else
+			// no data collection, so no timestamp available.
+			netsnmp_set_request_error(reqinfo, requests,
+                                      SNMP_ERR_NOACCESS);
+		break;
+	default:
+		/*
+		 * We should never get here, so this is a really bad error.
+		 */
+		return (SNMP_ERR_GENERR);
+	}
+	return (SNMP_ERR_NOERROR);
+}
+
+void
+get_status(unsigned int clientreg, void *clientarg)
+{
+  /*
+   * This function returns the value of the status variable.
+   * If the value of status is 0 (no collection is running), it
+   * calles collect_data to start one.
+   *  
+   */
+	
+  /*
+   * 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_10",
+                "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;
+
+    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:
+            // no collection running, start one.
+	    if (status == 0)
+		    collect_data();
+	    snmp_set_var_typed_value(requests->requestvb,
+	        ASN_INTEGER, (u_char *) & status,
+		    sizeof (status) /* length in bytes */);
+		break;
+	case MODE_SET_RESERVE1:
+	    /*
+	     * 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:
+		    /*
+		     * 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:
+		// get status integer from request
+		// if status == 0, start data collection, else return error
+		if (*(requests->requestvb->val.integer) == 0) {
+			status = *(requests->requestvb->val.integer);
+		        collect_data();
+		} else
+			netsnmp_set_request_error(reqinfo, requests,
+			    SNMP_ERR_WRONGTYPE);
+		break;
+	case MODE_SET_UNDO:
+	    /*
+	     * 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:
+		break;
+	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;
+    }
+
+    /*
+     * free the information cache 
+     */
+    netsnmp_free_delegated_cache(cache);
+		
+}
+
+void collect_data()
+{
+    /*
+     * This function starts a data collection.
+     */
+		status = 1; // set collection pending flag
+		sleep(delay_time); // simulate long-running collection
+		// get timestamp for this data collection
+		mytime = time(NULL);
+		strftime (refreshTime, sizeof(refreshTime), "%c", localtime(&mytime));
+		exampleData = 325;
+		status = 2; // set collection complete flag
+		return;
+		
+}