net-snmp 5.7
delayed_instance.c
00001 
00025 #include <net-snmp/net-snmp-config.h>
00026 #include <net-snmp/net-snmp-includes.h>
00027 #include <net-snmp/agent/net-snmp-agent-includes.h>
00028 
00029 #include "delayed_instance.h"
00030 
00031 static u_long   delay_time = 1;
00032 
00033 void
00034 init_delayed_instance(void)
00035 {
00036     static oid      my_delayed_oid[] =
00037         { 1, 3, 6, 1, 4, 1, 8072, 2, 1, 2, 0 };
00038     /*
00039      * delayed handler test
00040      */
00041     netsnmp_handler_registration *my_test;
00042 
00043     my_test =
00044         netsnmp_create_handler_registration("delayed_instance_example",
00045                                             delayed_instance_handler,
00046                                             my_delayed_oid,
00047                                             OID_LENGTH(my_delayed_oid),
00048                                             HANDLER_CAN_RWRITE);
00049 
00050     netsnmp_register_instance(my_test);
00051 }
00052 
00053 #define DELAYED_INSTANCE_SET_NAME "test_delayed"
00054 
00055 int
00056 delayed_instance_handler(netsnmp_mib_handler *handler,
00057                          netsnmp_handler_registration *reginfo,
00058                          netsnmp_agent_request_info *reqinfo,
00059                          netsnmp_request_info *requests)
00060 {
00061 
00062     DEBUGMSGTL(("delayed_instance", "Got request, mode = %d:\n",
00063                 reqinfo->mode));
00064 
00065     switch (reqinfo->mode) {
00066         /*
00067          * here we merely mention that we'll answer this request
00068          * later.  we don't actually care about the mode type in this
00069          * example, but for certain cases you may, so I'll leave in the
00070          * otherwise useless switch and case statements 
00071          */
00072 
00073     default:
00074         /*
00075          * mark this variable as something that can't be handled now.
00076          * We'll answer it later. 
00077          */
00078         requests->delegated = 1;
00079 
00080         /*
00081          * register an alarm to update the results at a later
00082          * time.  Normally, we might have to query something else
00083          * (like an external request sent to a different network
00084          * or system socket, etc), but for this example we'll do
00085          * something really simply and just insert an alarm for a
00086          * certain period of time 
00087          */
00088         snmp_alarm_register(delay_time, /* seconds */
00089                             0,  /* dont repeat. */
00090                             return_delayed_response,    /* the function
00091                                                          * to call */
00092                             /*
00093                              * here we create a "cache" of useful
00094                              * information that we'll want later
00095                              * on.  This argument is passed back
00096                              * to us in the callback function for
00097                              * an alarm 
00098                              */
00099                             (void *)
00100                             netsnmp_create_delegated_cache(handler,
00101                                                            reginfo,
00102                                                            reqinfo,
00103                                                            requests,
00104                                                            NULL));
00105         break;
00106 
00107     }
00108 
00109     return SNMP_ERR_NOERROR;
00110 }
00111 
00112 void
00113 return_delayed_response(unsigned int clientreg, void *clientarg)
00114 {
00115     /*
00116      * extract the cache from the passed argument 
00117      */
00118     netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) clientarg;
00119 
00120     netsnmp_request_info *requests;
00121     netsnmp_agent_request_info *reqinfo;
00122     u_long         *delay_time_cache = NULL;
00123 
00124     /*
00125      * here we double check that the cache we created earlier is still
00126      * * valid.  If not, the request timed out for some reason and we
00127      * * don't need to keep processing things.  Should never happen, but
00128      * * this double checks. 
00129      */
00130     cache = netsnmp_handler_check_cache(cache);
00131 
00132     if (!cache) {
00133         snmp_log(LOG_ERR, "illegal call to return delayed response\n");
00134         return;
00135     }
00136 
00137     /*
00138      * re-establish the previous pointers we are used to having 
00139      */
00140     reqinfo = cache->reqinfo;
00141     requests = cache->requests;
00142 
00143     DEBUGMSGTL(("delayed_instance",
00144                 "continuing delayed request, mode = %d\n",
00145                 cache->reqinfo->mode));
00146 
00147     /*
00148      * mention that it's no longer delegated, and we've now answered
00149      * the query (which we'll do down below). 
00150      */
00151     requests->delegated = 0;
00152 
00153     switch (cache->reqinfo->mode) {
00154         /*
00155          * registering as an instance means we don't need to deal with
00156          * getnext processing, so we don't handle it here at all.
00157          * 
00158          * However, since the instance handler already reset the mode
00159          * back to GETNEXT from the faked GET mode, we need to do the
00160          * same thing in both cases.  This should be fixed in future
00161          * versions of net-snmp hopefully. 
00162          */
00163 
00164     case MODE_GET:
00165     case MODE_GETNEXT:
00166         /*
00167          * return the currend delay time 
00168          */
00169         snmp_set_var_typed_value(cache->requests->requestvb,
00170                                  ASN_INTEGER,
00171                                  (u_char *) & delay_time,
00172                                  sizeof(delay_time));
00173         break;
00174 
00175 #ifndef NETSNMP_NO_WRITE_SUPPORT
00176     case MODE_SET_RESERVE1:
00177         /*
00178          * check type 
00179          */
00180         if (requests->requestvb->type != ASN_INTEGER) {
00181             /*
00182              * not an integer.  Bad dog, no bone. 
00183              */
00184             netsnmp_set_request_error(reqinfo, requests,
00185                                       SNMP_ERR_WRONGTYPE);
00186             /*
00187              * we don't need the cache any longer 
00188              */
00189             netsnmp_free_delegated_cache(cache);
00190             return;
00191         }
00192         break;
00193 
00194     case MODE_SET_RESERVE2:
00195         /*
00196          * store old value for UNDO support in the future. 
00197          */
00198         memdup((u_char **) & delay_time_cache,
00199                (u_char *) & delay_time, sizeof(delay_time));
00200 
00201         /*
00202          * malloc failed 
00203          */
00204         if (delay_time_cache == NULL) {
00205             netsnmp_set_request_error(reqinfo, requests,
00206                                       SNMP_ERR_RESOURCEUNAVAILABLE);
00207             netsnmp_free_delegated_cache(cache);
00208             return;
00209         }
00210 
00211         /*
00212          * Add our temporary information to the request itself.
00213          * This is then retrivable later.  The free function
00214          * passed auto-frees it when the request is later
00215          * deleted.  
00216          */
00217         netsnmp_request_add_list_data(requests,
00218                                       netsnmp_create_data_list
00219                                       (DELAYED_INSTANCE_SET_NAME,
00220                                        delay_time_cache, free));
00221         break;
00222 
00223     case MODE_SET_ACTION:
00224         /*
00225          * update current value 
00226          */
00227         delay_time = *(requests->requestvb->val.integer);
00228         DEBUGMSGTL(("testhandler", "updated delay_time -> %ld\n",
00229                     delay_time));
00230         break;
00231 
00232     case MODE_SET_UNDO:
00233         /*
00234          * ack, something somewhere failed.  We reset back to the
00235          * previously old value by extracting the previosuly
00236          * stored information back out of the request 
00237          */
00238         delay_time =
00239             *((u_long *) netsnmp_request_get_list_data(requests,
00240                                                        DELAYED_INSTANCE_SET_NAME));
00241         break;
00242 
00243     case MODE_SET_COMMIT:
00244     case MODE_SET_FREE:
00245         /*
00246          * the only thing to do here is free the old memdup'ed
00247          * value, but it's auto-freed by the datalist recovery, so
00248          * we don't have anything to actually do here 
00249          */
00250         break;
00251 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00252     }
00253 
00254     /*
00255      * free the information cache 
00256      */
00257     netsnmp_free_delegated_cache(cache);
00258 }