summaryrefslogtreecommitdiff
path: root/agent/helpers/baby_steps.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/helpers/baby_steps.c')
-rw-r--r--agent/helpers/baby_steps.c518
1 files changed, 518 insertions, 0 deletions
diff --git a/agent/helpers/baby_steps.c b/agent/helpers/baby_steps.c
new file mode 100644
index 0000000..77619f5
--- /dev/null
+++ b/agent/helpers/baby_steps.c
@@ -0,0 +1,518 @@
+/*
+ * baby_steps.c
+ * $Id: baby_steps.c 14169 2006-01-25 16:28:12Z dts12 $
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include <net-snmp/agent/baby_steps.h>
+
+#define BABY_STEPS_PER_MODE_MAX 4
+#define BSTEP_USE_ORIGINAL 0xffff
+
+static u_short get_mode_map[BABY_STEPS_PER_MODE_MAX] = {
+ MODE_BSTEP_PRE_REQUEST, MODE_BSTEP_OBJECT_LOOKUP, BSTEP_USE_ORIGINAL, MODE_BSTEP_POST_REQUEST };
+
+static u_short set_mode_map[SNMP_MSG_INTERNAL_SET_MAX][BABY_STEPS_PER_MODE_MAX] = {
+ /*R1*/
+ { MODE_BSTEP_PRE_REQUEST, MODE_BSTEP_OBJECT_LOOKUP, MODE_BSTEP_ROW_CREATE,
+ MODE_BSTEP_CHECK_VALUE },
+ /*R2*/
+ { MODE_BSTEP_UNDO_SETUP, BABY_STEP_NONE, BABY_STEP_NONE, BABY_STEP_NONE },
+ /*A */
+ { MODE_BSTEP_SET_VALUE,MODE_BSTEP_CHECK_CONSISTENCY,
+ MODE_BSTEP_COMMIT, BABY_STEP_NONE },
+ /*C */
+ { MODE_BSTEP_IRREVERSIBLE_COMMIT, MODE_BSTEP_UNDO_CLEANUP, MODE_BSTEP_POST_REQUEST,
+ BABY_STEP_NONE},
+ /*F */
+ { MODE_BSTEP_UNDO_CLEANUP, MODE_BSTEP_POST_REQUEST, BABY_STEP_NONE,
+ BABY_STEP_NONE },
+ /*U */
+ { MODE_BSTEP_UNDO_COMMIT, MODE_BSTEP_UNDO_SET, MODE_BSTEP_UNDO_CLEANUP,
+ MODE_BSTEP_POST_REQUEST}
+};
+
+static int
+_baby_steps_helper(netsnmp_mib_handler *handler,
+ netsnmp_handler_registration *reginfo,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests);
+static int
+_baby_steps_access_multiplexer(netsnmp_mib_handler *handler,
+ netsnmp_handler_registration *reginfo,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests);
+
+/** @defgroup baby_steps baby_steps
+ * Calls your handler in baby_steps for set processing.
+ * @ingroup handler
+ * @{
+ */
+
+/** returns a baby_steps handler that can be injected into a given
+ * handler chain.
+ */
+netsnmp_mib_handler *
+netsnmp_baby_steps_handler_get(u_long modes)
+{
+ netsnmp_mib_handler *mh;
+ netsnmp_baby_steps_modes *md;
+
+ mh = netsnmp_create_handler("baby_steps", _baby_steps_helper);
+ if(!mh)
+ return NULL;
+
+ md = SNMP_MALLOC_TYPEDEF(netsnmp_baby_steps_modes);
+ if (NULL == md) {
+ snmp_log(LOG_ERR,"malloc failed in netsnmp_baby_steps_handler_get\n");
+ netsnmp_handler_free(mh);
+ mh = NULL;
+ }
+ else {
+ mh->myvoid = md;
+ if (0 == modes)
+ modes = BABY_STEP_ALL;
+ md->registered = modes;
+ }
+
+ /*
+ * don't set MIB_HANDLER_AUTO_NEXT, since we need to call lower
+ * handlers with a munged mode.
+ */
+
+ return mh;
+}
+
+/** @internal Implements the baby_steps handler */
+static int
+_baby_steps_helper(netsnmp_mib_handler *handler,
+ netsnmp_handler_registration *reginfo,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests)
+{
+ netsnmp_baby_steps_modes *bs_modes;
+ int save_mode, i, rc = SNMP_ERR_NOERROR;
+ u_short *mode_map_ptr;
+
+ DEBUGMSGTL(("baby_steps", "Got request, mode %s\n",
+ se_find_label_in_slist("agent_mode",reqinfo->mode)));
+
+ bs_modes = handler->myvoid;
+ netsnmp_assert(NULL != bs_modes);
+
+ switch (reqinfo->mode) {
+
+ case MODE_SET_RESERVE1:
+ /*
+ * clear completed modes
+ * xxx-rks: this will break for pdus with set requests to different
+ * rows in the same table when the handler is set up to use the row
+ * merge helper as well (or if requests are serialized).
+ */
+ bs_modes->completed = 0;
+ /** fall through */
+
+ case MODE_SET_RESERVE2:
+ case MODE_SET_ACTION:
+ case MODE_SET_COMMIT:
+ case MODE_SET_FREE:
+ case MODE_SET_UNDO:
+ mode_map_ptr = set_mode_map[reqinfo->mode];
+ break;
+
+ default:
+ /*
+ * clear completed modes
+ */
+ bs_modes->completed = 0;
+
+ mode_map_ptr = get_mode_map;
+ }
+
+ /*
+ * NOTE: if you update this chart, please update the versions in
+ * local/mib2c-conf.d/parent-set.m2i
+ * agent/mibgroup/helpers/baby_steps.c
+ * while you're at it.
+ */
+ /*
+ ***********************************************************************
+ * Baby Steps Flow Chart (2004.06.05) *
+ * *
+ * +--------------+ +================+ U = unconditional path *
+ * |optional state| ||required state|| S = path for success *
+ * +--------------+ +================+ E = path for error *
+ ***********************************************************************
+ *
+ * +--------------+
+ * | pre |
+ * | request |
+ * +--------------+
+ * | U
+ * +-------------+ +==============+
+ * | row |f|<-------|| object ||
+ * | create |1| E || lookup ||
+ * +-------------+ +==============+
+ * E | | S | S
+ * | +------------------>|
+ * | +==============+
+ * | E || check ||
+ * |<---------------|| values ||
+ * | +==============+
+ * | | S
+ * | +==============+
+ * | +<-------|| undo ||
+ * | | E || setup ||
+ * | | +==============+
+ * | | | S
+ * | | +==============+
+ * | | || set ||-------------------------->+
+ * | | || value || E |
+ * | | +==============+ |
+ * | | | S |
+ * | | +--------------+ |
+ * | | | check |-------------------------->|
+ * | | | consistency | E |
+ * | | +--------------+ |
+ * | | | S |
+ * | | +==============+ +==============+ |
+ * | | || commit ||-------->|| undo || |
+ * | | || || E || commit || |
+ * | | +==============+ +==============+ |
+ * | | | S U |<--------+
+ * | | +--------------+ +==============+
+ * | | | irreversible | || undo ||
+ * | | | commit | || set ||
+ * | | +--------------+ +==============+
+ * | | | U U |
+ * | +-------------->|<------------------------+
+ * | +==============+
+ * | || undo ||
+ * | || cleanup ||
+ * | +==============+
+ * +---------------------->| U
+ * |
+ * (err && f1)------------------->+
+ * | |
+ * +--------------+ +--------------+
+ * | post |<--------| row |
+ * | request | U | release |
+ * +--------------+ +--------------+
+ *
+ */
+ /*
+ * save original mode
+ */
+ save_mode = reqinfo->mode;
+ for(i = 0; i < BABY_STEPS_PER_MODE_MAX; ++i ) {
+ /*
+ * break if we run out of baby steps for this mode
+ */
+ if(mode_map_ptr[i] == BABY_STEP_NONE)
+ break;
+
+ DEBUGMSGTL(("baby_steps", " baby step mode %s\n",
+ se_find_label_in_slist("babystep_mode",mode_map_ptr[i])));
+
+ /*
+ * skip modes the handler didn't register for
+ */
+ if (BSTEP_USE_ORIGINAL != mode_map_ptr[i]) {
+ u_int mode_flag;
+
+ /*
+ * skip undo commit if commit wasn't hit, and
+ * undo_cleanup if undo_setup wasn't hit.
+ */
+ if((MODE_SET_UNDO == save_mode) &&
+ (MODE_BSTEP_UNDO_COMMIT == mode_map_ptr[i]) &&
+ !(BABY_STEP_COMMIT & bs_modes->completed)) {
+ DEBUGMSGTL(("baby_steps",
+ " skipping commit undo (no commit)\n"));
+ continue;
+ }
+ else if((MODE_SET_FREE == save_mode) &&
+ (MODE_BSTEP_UNDO_CLEANUP == mode_map_ptr[i]) &&
+ !(BABY_STEP_UNDO_SETUP & bs_modes->completed)) {
+ DEBUGMSGTL(("baby_steps",
+ " skipping undo cleanup (no undo setup)\n"));
+ continue;
+ }
+
+ reqinfo->mode = mode_map_ptr[i];
+ mode_flag = netsnmp_baby_step_mode2flag( mode_map_ptr[i] );
+ if((mode_flag & bs_modes->registered))
+ bs_modes->completed |= mode_flag;
+ else {
+ DEBUGMSGTL(("baby_steps",
+ " skipping mode (not registered)\n"));
+ continue;
+ }
+
+
+ }
+ else {
+ reqinfo->mode = save_mode;
+ }
+
+#ifdef BABY_STEPS_NEXT_MODE
+ /*
+ * I can't remember why I wanted the next mode in the request,
+ * but it's not used anywhere, so don't use this code. saved,
+ * in case I remember why I thought needed it. - rstory 040911
+ */
+ if((BABY_STEPS_PER_MODE_MAX - 1) == i)
+ reqinfo->next_mode_ok = BABY_STEP_NONE;
+ else {
+ if(BSTEP_USE_ORIGINAL == mode_map_ptr[i+1])
+ reqinfo->next_mode_ok = save_mode;
+ else
+ reqinfo->next_mode_ok = mode_map_ptr[i+1];
+ }
+#endif
+
+ /*
+ * call handlers for baby step
+ */
+ rc = netsnmp_call_next_handler(handler, reginfo, reqinfo,
+ requests);
+
+ /*
+ * check for error calling handler (unlikely, but...)
+ */
+ if(rc) {
+ DEBUGMSGTL(("baby_steps", " ERROR:handler error\n"));
+ break;
+ }
+
+ /*
+ * check for errors in any of the requests for GET-like, reserve1,
+ * reserve2 and action. (there is no recovery from errors
+ * in commit, free or undo.)
+ */
+ if (MODE_IS_GET(save_mode)
+ || (save_mode < SNMP_MSG_INTERNAL_SET_COMMIT)) {
+ rc = netsnmp_check_requests_error(requests);
+ if(rc) {
+ DEBUGMSGTL(("baby_steps", " ERROR:request error\n"));
+ break;
+ }
+ }
+ }
+
+ /*
+ * restore original mode
+ */
+ reqinfo->mode = save_mode;
+
+
+ return rc;
+}
+
+/** initializes the baby_steps helper which then registers a baby_steps
+ * handler as a run-time injectable handler for configuration file
+ * use.
+ */
+void
+netsnmp_baby_steps_handler_init(void)
+{
+ netsnmp_register_handler_by_name("baby_steps",
+ netsnmp_baby_steps_handler_get(BABY_STEP_ALL));
+}
+
+/** @} */
+
+/** @defgroup access_multiplexer baby_steps_access_multiplexer: calls individual access methods based on baby_step mode.
+ * @ingroup baby_steps
+ * @{
+ */
+
+/** returns a baby_steps handler that can be injected into a given
+ * handler chain.
+ */
+netsnmp_mib_handler *
+netsnmp_baby_steps_access_multiplexer_get(netsnmp_baby_steps_access_methods *am)
+{
+ netsnmp_mib_handler *mh;
+
+ mh = netsnmp_create_handler("baby_steps_mux",
+ _baby_steps_access_multiplexer);
+ if(!mh)
+ return NULL;
+
+ mh->myvoid = am;
+ mh->flags |= MIB_HANDLER_AUTO_NEXT;
+
+ return mh;
+}
+
+/** @internal Implements the baby_steps handler */
+static int
+_baby_steps_access_multiplexer(netsnmp_mib_handler *handler,
+ netsnmp_handler_registration *reginfo,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests)
+{
+ void *temp_void;
+ Netsnmp_Node_Handler *method = NULL;
+ netsnmp_baby_steps_access_methods *access_methods;
+ int rc = SNMP_ERR_NOERROR;
+
+ /** call handlers should enforce these */
+ netsnmp_assert((handler!=NULL) && (reginfo!=NULL) && (reqinfo!=NULL) &&
+ (requests!=NULL));
+
+ DEBUGMSGT(("baby_steps_mux", "mode %s\n",
+ se_find_label_in_slist("babystep_mode",reqinfo->mode)));
+
+ access_methods = (netsnmp_baby_steps_access_methods *)handler->myvoid;
+ if(!access_methods) {
+ snmp_log(LOG_ERR,"baby_steps_access_multiplexer has no methods\n");
+ return SNMPERR_GENERR;
+ }
+
+ switch(reqinfo->mode) {
+
+ case MODE_BSTEP_PRE_REQUEST:
+ if( access_methods->pre_request )
+ method = access_methods->pre_request;
+ break;
+
+ case MODE_BSTEP_OBJECT_LOOKUP:
+ if( access_methods->object_lookup )
+ method = access_methods->object_lookup;
+ break;
+
+ case SNMP_MSG_GET:
+ case SNMP_MSG_GETNEXT:
+ if( access_methods->get_values )
+ method = access_methods->get_values;
+ break;
+
+ case MODE_BSTEP_CHECK_VALUE:
+ if( access_methods->object_syntax_checks )
+ method = access_methods->object_syntax_checks;
+ break;
+
+ case MODE_BSTEP_ROW_CREATE:
+ if( access_methods->row_creation )
+ method = access_methods->row_creation;
+ break;
+
+ case MODE_BSTEP_UNDO_SETUP:
+ if( access_methods->undo_setup )
+ method = access_methods->undo_setup;
+ break;
+
+ case MODE_BSTEP_SET_VALUE:
+ if( access_methods->set_values )
+ method = access_methods->set_values;
+ break;
+
+ case MODE_BSTEP_CHECK_CONSISTENCY:
+ if( access_methods->consistency_checks )
+ method = access_methods->consistency_checks;
+ break;
+
+ case MODE_BSTEP_UNDO_SET:
+ if( access_methods->undo_sets )
+ method = access_methods->undo_sets;
+ break;
+
+ case MODE_BSTEP_COMMIT:
+ if( access_methods->commit )
+ method = access_methods->commit;
+ break;
+
+ case MODE_BSTEP_UNDO_COMMIT:
+ if( access_methods->undo_commit )
+ method = access_methods->undo_commit;
+ break;
+
+ case MODE_BSTEP_IRREVERSIBLE_COMMIT:
+ if( access_methods->irreversible_commit )
+ method = access_methods->irreversible_commit;
+ break;
+
+ case MODE_BSTEP_UNDO_CLEANUP:
+ if( access_methods->undo_cleanup )
+ method = access_methods->undo_cleanup;
+ break;
+
+ case MODE_BSTEP_POST_REQUEST:
+ if( access_methods->post_request )
+ method = access_methods->post_request;
+ break;
+
+ default:
+ snmp_log(LOG_ERR,"unknown mode %d\n", reqinfo->mode);
+ return SNMP_ERR_GENERR;
+ }
+
+ /*
+ * if method exists, set up handler void and call method.
+ */
+ if(NULL != method) {
+ temp_void = handler->myvoid;
+ handler->myvoid = access_methods->my_access_void;
+ rc = (*method)(handler, reginfo, reqinfo, requests);
+ handler->myvoid = temp_void;
+ }
+ else {
+ rc = SNMP_ERR_GENERR;
+ snmp_log(LOG_ERR,"baby steps multiplexer handler called for a mode "
+ "with no handler\n");
+ netsnmp_assert(NULL != method);
+ }
+
+ /*
+ * don't call any lower handlers, it will be done for us
+ * since we set MIB_HANDLER_AUTO_NEXT
+ */
+
+ return rc;
+}
+
+/*
+ * give a baby step mode, return the flag for that mode
+ */
+int
+netsnmp_baby_step_mode2flag( u_int mode )
+{
+ switch( mode ) {
+ case MODE_BSTEP_OBJECT_LOOKUP:
+ return BABY_STEP_OBJECT_LOOKUP;
+ case MODE_BSTEP_SET_VALUE:
+ return BABY_STEP_SET_VALUE;
+ case MODE_BSTEP_IRREVERSIBLE_COMMIT:
+ return BABY_STEP_IRREVERSIBLE_COMMIT;
+ case MODE_BSTEP_CHECK_VALUE:
+ return BABY_STEP_CHECK_VALUE;
+ case MODE_BSTEP_PRE_REQUEST:
+ return BABY_STEP_PRE_REQUEST;
+ case MODE_BSTEP_POST_REQUEST:
+ return BABY_STEP_POST_REQUEST;
+ case MODE_BSTEP_UNDO_SETUP:
+ return BABY_STEP_UNDO_SETUP;
+ case MODE_BSTEP_UNDO_CLEANUP:
+ return BABY_STEP_UNDO_CLEANUP;
+ case MODE_BSTEP_UNDO_SET:
+ return BABY_STEP_UNDO_SET;
+ case MODE_BSTEP_ROW_CREATE:
+ return BABY_STEP_ROW_CREATE;
+ case MODE_BSTEP_CHECK_CONSISTENCY:
+ return BABY_STEP_CHECK_CONSISTENCY;
+ case MODE_BSTEP_COMMIT:
+ return BABY_STEP_COMMIT;
+ case MODE_BSTEP_UNDO_COMMIT:
+ return BABY_STEP_UNDO_COMMIT;
+ default:
+ netsnmp_assert("unknown flag");
+ break;
+ }
+ return 0;
+}
+/** @} */
+