diff options
Diffstat (limited to 'agent/helpers/baby_steps.c')
-rw-r--r-- | agent/helpers/baby_steps.c | 518 |
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; +} +/** @} */ + |