1 /** @example delayed_instance.c
2 * This example implements the netSnmpExampleSleeper object.
4 * It demonstrates 2 things:
6 * - The instance helper, which is a way of registering an exact OID
7 * such that GENEXT requests are handled entirely by the helper.
9 * - how to implement objects which normally would block the agent as
10 * it waits for external events in such a way that the agent can
11 * continue responding to other requests while this implementation
14 * - Added bonus: normally the nsTransactionTable is empty, since
15 * there aren't any outstanding requests generally. When accessed,
16 * this module will create some however. Try setting
17 * netSnmpExampleSleeper.0 to 10 and then accessing it (use
18 * "snmpget -t 15 ..." to access it), and then walk the
19 * nsTransactionTable from another shell to see that not only is
20 * the walk not blocked, but that the nsTransactionTable is not
25 #include <net-snmp/net-snmp-config.h>
26 #include <net-snmp/net-snmp-includes.h>
27 #include <net-snmp/agent/net-snmp-agent-includes.h>
29 #include "delayed_instance.h"
31 static u_long delay_time = 1;
34 init_delayed_instance(void)
36 static oid my_delayed_oid[] =
37 { 1, 3, 6, 1, 4, 1, 8072, 2, 1, 2, 0 };
39 * delayed handler test
41 netsnmp_handler_registration *my_test;
44 netsnmp_create_handler_registration("delayed_instance_example",
45 delayed_instance_handler,
47 OID_LENGTH(my_delayed_oid),
50 netsnmp_register_instance(my_test);
53 #define DELAYED_INSTANCE_SET_NAME "test_delayed"
56 delayed_instance_handler(netsnmp_mib_handler *handler,
57 netsnmp_handler_registration *reginfo,
58 netsnmp_agent_request_info *reqinfo,
59 netsnmp_request_info *requests)
62 DEBUGMSGTL(("delayed_instance", "Got request, mode = %d:\n",
65 switch (reqinfo->mode) {
67 * here we merely mention that we'll answer this request
68 * later. we don't actually care about the mode type in this
69 * example, but for certain cases you may, so I'll leave in the
70 * otherwise useless switch and case statements
75 * mark this variable as something that can't be handled now.
76 * We'll answer it later.
78 requests->delegated = 1;
81 * register an alarm to update the results at a later
82 * time. Normally, we might have to query something else
83 * (like an external request sent to a different network
84 * or system socket, etc), but for this example we'll do
85 * something really simply and just insert an alarm for a
86 * certain period of time
88 snmp_alarm_register(delay_time, /* seconds */
90 return_delayed_response, /* the function
93 * here we create a "cache" of useful
94 * information that we'll want later
95 * on. This argument is passed back
96 * to us in the callback function for
100 netsnmp_create_delegated_cache(handler,
109 return SNMP_ERR_NOERROR;
113 return_delayed_response(unsigned int clientreg, void *clientarg)
116 * extract the cache from the passed argument
118 netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) clientarg;
120 netsnmp_request_info *requests;
121 netsnmp_agent_request_info *reqinfo;
122 u_long *delay_time_cache = NULL;
125 * here we double check that the cache we created earlier is still
126 * * valid. If not, the request timed out for some reason and we
127 * * don't need to keep processing things. Should never happen, but
128 * * this double checks.
130 cache = netsnmp_handler_check_cache(cache);
133 snmp_log(LOG_ERR, "illegal call to return delayed response\n");
138 * re-establish the previous pointers we are used to having
140 reqinfo = cache->reqinfo;
141 requests = cache->requests;
143 DEBUGMSGTL(("delayed_instance",
144 "continuing delayed request, mode = %d\n",
145 cache->reqinfo->mode));
148 * mention that it's no longer delegated, and we've now answered
149 * the query (which we'll do down below).
151 requests->delegated = 0;
153 switch (cache->reqinfo->mode) {
155 * registering as an instance means we don't need to deal with
156 * getnext processing, so we don't handle it here at all.
158 * However, since the instance handler already reset the mode
159 * back to GETNEXT from the faked GET mode, we need to do the
160 * same thing in both cases. This should be fixed in future
161 * versions of net-snmp hopefully.
167 * return the currend delay time
169 snmp_set_var_typed_value(cache->requests->requestvb,
171 (u_char *) & delay_time,
175 case MODE_SET_RESERVE1:
179 if (requests->requestvb->type != ASN_INTEGER) {
181 * not an integer. Bad dog, no bone.
183 netsnmp_set_request_error(reqinfo, requests,
186 * we don't need the cache any longer
188 netsnmp_free_delegated_cache(cache);
193 case MODE_SET_RESERVE2:
195 * store old value for UNDO support in the future.
197 memdup((u_char **) & delay_time_cache,
198 (u_char *) & delay_time, sizeof(delay_time));
203 if (delay_time_cache == NULL) {
204 netsnmp_set_request_error(reqinfo, requests,
205 SNMP_ERR_RESOURCEUNAVAILABLE);
206 netsnmp_free_delegated_cache(cache);
211 * Add our temporary information to the request itself.
212 * This is then retrivable later. The free function
213 * passed auto-frees it when the request is later
216 netsnmp_request_add_list_data(requests,
217 netsnmp_create_data_list
218 (DELAYED_INSTANCE_SET_NAME,
219 delay_time_cache, free));
222 case MODE_SET_ACTION:
224 * update current value
226 delay_time = *(requests->requestvb->val.integer);
227 DEBUGMSGTL(("testhandler", "updated delay_time -> %d\n",
233 * ack, something somewhere failed. We reset back to the
234 * previously old value by extracting the previosuly
235 * stored information back out of the request
238 *((u_long *) netsnmp_request_get_list_data(requests,
239 DELAYED_INSTANCE_SET_NAME));
242 case MODE_SET_COMMIT:
245 * the only thing to do here is free the old memdup'ed
246 * value, but it's auto-freed by the datalist recovery, so
247 * we don't have anything to actually do here
253 * free the information cache
255 netsnmp_free_delegated_cache(cache);