diff options
Diffstat (limited to 'agent/helpers/watcher.c')
-rw-r--r-- | agent/helpers/watcher.c | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/agent/helpers/watcher.c b/agent/helpers/watcher.c new file mode 100644 index 0000000..b35f550 --- /dev/null +++ b/agent/helpers/watcher.c @@ -0,0 +1,485 @@ +#include <net-snmp/net-snmp-config.h> + +#include <stdlib.h> +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#include <net-snmp/agent/watcher.h> +#include <net-snmp/agent/instance.h> +#include <net-snmp/agent/scalar.h> + +/** @defgroup watcher watcher + * Watch a specified variable and process it as an instance or scalar object + * @ingroup leaf + * @{ + */ +netsnmp_mib_handler * +netsnmp_get_watcher_handler(void) +{ + netsnmp_mib_handler *ret = NULL; + + ret = netsnmp_create_handler("watcher", + netsnmp_watcher_helper_handler); + if (ret) { + ret->flags |= MIB_HANDLER_AUTO_NEXT; + } + return ret; +} + +netsnmp_watcher_info * +netsnmp_create_watcher_info(void *data, size_t size, u_char type, int flags) +{ + netsnmp_watcher_info *winfo = SNMP_MALLOC_TYPEDEF(netsnmp_watcher_info); + + winfo->data = data; + winfo->data_size = size; + winfo->max_size = size; /* Probably wrong for non-fixed size data */ + winfo->type = type; + if (flags) + winfo->flags = flags; + else + winfo->flags = WATCHER_FIXED_SIZE; + + return winfo; +} + +int +netsnmp_register_watched_instance(netsnmp_handler_registration *reginfo, + netsnmp_watcher_info *watchinfo) +{ + netsnmp_mib_handler *whandler; + + whandler = netsnmp_get_watcher_handler(); + whandler->myvoid = (void *)watchinfo; + + netsnmp_inject_handler(reginfo, whandler); + return netsnmp_register_instance(reginfo); +} + +int +netsnmp_register_watched_scalar(netsnmp_handler_registration *reginfo, + netsnmp_watcher_info *watchinfo) +{ + netsnmp_mib_handler *whandler; + + whandler = netsnmp_get_watcher_handler(); + whandler->myvoid = (void *)watchinfo; + + netsnmp_inject_handler(reginfo, whandler); + return netsnmp_register_scalar(reginfo); +} + + + +int +netsnmp_watcher_helper_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + netsnmp_watcher_info *winfo = (netsnmp_watcher_info *) handler->myvoid; + u_char *old_data; + int cmp; + + DEBUGMSGTL(("helper:watcher", "Got request: %d\n", reqinfo->mode)); + cmp = snmp_oid_compare(requests->requestvb->name, + requests->requestvb->name_length, + reginfo->rootoid, reginfo->rootoid_len); + + DEBUGMSGTL(( "helper:watcher", " oid:")); + DEBUGMSGOID(("helper:watcher", requests->requestvb->name, + requests->requestvb->name_length)); + DEBUGMSG(( "helper:watcher", "\n")); + + + + switch (reqinfo->mode) { + /* + * data requests + */ + case MODE_GET: + snmp_set_var_typed_value(requests->requestvb, + winfo->type, + winfo->data, + winfo->data_size); + break; + + /* + * SET requests. Should only get here if registered RWRITE + */ + case MODE_SET_RESERVE1: + if (requests->requestvb->type != winfo->type) { + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_WRONGTYPE); + handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; + } + + if (((winfo->flags & WATCHER_MAX_SIZE) && + requests->requestvb->val_len > winfo->max_size) || + ((winfo->flags & WATCHER_FIXED_SIZE) && + requests->requestvb->val_len != winfo->data_size)) { + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_WRONGLENGTH); + handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; + } + break; + + case MODE_SET_RESERVE2: + /* + * store old info for undo later + */ + memdup(&old_data, (u_char *) winfo->data, winfo->data_size); + if (old_data == NULL) { + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_RESOURCEUNAVAILABLE); + handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; + return SNMP_ERR_NOERROR; + } + netsnmp_request_add_list_data(requests, + netsnmp_create_data_list + ("watcher", old_data, free)); + break; + + case MODE_SET_FREE: + /* + * nothing to do + */ + break; + + case MODE_SET_ACTION: + /* + * update current + */ + memcpy(winfo->data, (void *)requests->requestvb->val.string, + requests->requestvb->val_len); + break; + + case MODE_SET_UNDO: + memcpy(winfo->data, + netsnmp_request_get_list_data(requests, "watcher"), + winfo->data_size); + break; + + case MODE_SET_COMMIT: + winfo->data_size = requests->requestvb->val_len; + break; + + } + + /* next handler called automatically - 'AUTO_NEXT' */ + return SNMP_ERR_NOERROR; +} + + + /*************************** + * + * A specialised form of the above, reporting + * the sysUpTime indicated by a given timestamp + * + ***************************/ + +netsnmp_mib_handler * +netsnmp_get_watched_timestamp_handler(void) +{ + netsnmp_mib_handler *ret = NULL; + + ret = netsnmp_create_handler("watcher-timestamp", + netsnmp_watched_timestamp_handler); + if (ret) { + ret->flags |= MIB_HANDLER_AUTO_NEXT; + } + return ret; +} + +int +netsnmp_watched_timestamp_register(netsnmp_mib_handler *whandler, + netsnmp_handler_registration *reginfo, + marker_t timestamp) +{ + whandler->myvoid = (void *)timestamp; + netsnmp_inject_handler(reginfo, whandler); + return netsnmp_register_scalar(reginfo); /* XXX - or instance? */ +} + +int +netsnmp_register_watched_timestamp(netsnmp_handler_registration *reginfo, + marker_t timestamp) +{ + netsnmp_mib_handler *whandler; + + whandler = netsnmp_get_watched_timestamp_handler(); + + return netsnmp_watched_timestamp_register(whandler, reginfo, timestamp); +} + + +int +netsnmp_watched_timestamp_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + marker_t timestamp = (marker_t) handler->myvoid; + long uptime; + int cmp; + + DEBUGMSGTL(("helper:watcher:timestamp", + "Got request: %d\n", reqinfo->mode)); + cmp = snmp_oid_compare(requests->requestvb->name, + requests->requestvb->name_length, + reginfo->rootoid, reginfo->rootoid_len); + + DEBUGMSGTL(( "helper:watcher:timestamp", " oid:")); + DEBUGMSGOID(("helper:watcher:timestamp", requests->requestvb->name, + requests->requestvb->name_length)); + DEBUGMSG(( "helper:watcher:timestamp", "\n")); + + + + switch (reqinfo->mode) { + /* + * data requests + */ + case MODE_GET: + if (handler->flags & NETSNMP_WATCHER_DIRECT) + uptime = * (long*)timestamp; + else + uptime = netsnmp_marker_uptime( timestamp ); + snmp_set_var_typed_value(requests->requestvb, + ASN_TIMETICKS, + (u_char *) &uptime, + sizeof(uptime)); + break; + + /* + * Timestamps are inherently Read-Only, + * so don't need to support SET requests. + */ + case MODE_SET_RESERVE1: + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_NOTWRITABLE); + handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; + return SNMP_ERR_NOTWRITABLE; + } + + /* next handler called automatically - 'AUTO_NEXT' */ + return SNMP_ERR_NOERROR; +} + + /*************************** + * + * Another specialised form of the above, + * implementing a 'TestAndIncr' spinlock + * + ***************************/ + +netsnmp_mib_handler * +netsnmp_get_watched_spinlock_handler(void) +{ + netsnmp_mib_handler *ret = NULL; + + ret = netsnmp_create_handler("watcher-spinlock", + netsnmp_watched_spinlock_handler); + if (ret) { + ret->flags |= MIB_HANDLER_AUTO_NEXT; + } + return ret; +} + +int +netsnmp_register_watched_spinlock(netsnmp_handler_registration *reginfo, + int *spinlock) +{ + netsnmp_mib_handler *whandler; + netsnmp_watcher_info *winfo; + + whandler = netsnmp_get_watched_spinlock_handler(); + whandler->myvoid = (void *)spinlock; + winfo = netsnmp_create_watcher_info((void *)spinlock, + sizeof(int), ASN_INTEGER, WATCHER_FIXED_SIZE); + netsnmp_inject_handler(reginfo, whandler); + return netsnmp_register_watched_scalar(reginfo, winfo); +} + + +int +netsnmp_watched_spinlock_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + int *spinlock = (int *) handler->myvoid; + netsnmp_request_info *request; + int cmp; + + DEBUGMSGTL(("helper:watcher:spinlock", + "Got request: %d\n", reqinfo->mode)); + cmp = snmp_oid_compare(requests->requestvb->name, + requests->requestvb->name_length, + reginfo->rootoid, reginfo->rootoid_len); + + DEBUGMSGTL(( "helper:watcher:spinlock", " oid:")); + DEBUGMSGOID(("helper:watcher:spinlock", requests->requestvb->name, + requests->requestvb->name_length)); + DEBUGMSG(( "helper:watcher:spinlock", "\n")); + + + + switch (reqinfo->mode) { + /* + * Ensure the assigned value matches the current one + */ + case MODE_SET_RESERVE1: + for (request=requests; request; request=request->next) { + if (request->processed) + continue; + + if (*request->requestvb->val.integer != *spinlock) { + netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGVALUE); + handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; + return SNMP_ERR_WRONGVALUE; + + } + } + break; + + /* + * Everything else worked, so increment the spinlock + */ + case MODE_SET_COMMIT: + (*spinlock)++; + break; + } + + /* next handler called automatically - 'AUTO_NEXT' */ + return SNMP_ERR_NOERROR; +} + + /*************************** + * + * Convenience registration routines - modelled on + * the equivalent netsnmp_register_*_instance() calls + * + ***************************/ + +int +netsnmp_register_ulong_scalar(const char *name, + oid * reg_oid, size_t reg_oid_len, + u_long * it, + Netsnmp_Node_Handler * subhandler) +{ + return netsnmp_register_watched_scalar( + netsnmp_create_handler_registration( + name, subhandler, + reg_oid, reg_oid_len, + HANDLER_CAN_RWRITE ), + netsnmp_create_watcher_info( + (void *)it, sizeof( u_long ), + ASN_UNSIGNED, WATCHER_FIXED_SIZE )); +} + +int +netsnmp_register_read_only_ulong_scalar(const char *name, + oid * reg_oid, size_t reg_oid_len, + u_long * it, + Netsnmp_Node_Handler * subhandler) +{ + return netsnmp_register_watched_scalar( + netsnmp_create_handler_registration( + name, subhandler, + reg_oid, reg_oid_len, + HANDLER_CAN_RONLY ), + netsnmp_create_watcher_info( + (void *)it, sizeof( u_long ), + ASN_UNSIGNED, WATCHER_FIXED_SIZE )); +} + +int +netsnmp_register_long_scalar(const char *name, + oid * reg_oid, size_t reg_oid_len, + long * it, + Netsnmp_Node_Handler * subhandler) +{ + return netsnmp_register_watched_scalar( + netsnmp_create_handler_registration( + name, subhandler, + reg_oid, reg_oid_len, + HANDLER_CAN_RWRITE ), + netsnmp_create_watcher_info( + (void *)it, sizeof( long ), + ASN_INTEGER, WATCHER_FIXED_SIZE )); +} + +int +netsnmp_register_read_only_long_scalar(const char *name, + oid * reg_oid, size_t reg_oid_len, + long * it, + Netsnmp_Node_Handler * subhandler) +{ + return netsnmp_register_watched_scalar( + netsnmp_create_handler_registration( + name, subhandler, + reg_oid, reg_oid_len, + HANDLER_CAN_RONLY ), + netsnmp_create_watcher_info( + (void *)it, sizeof( long ), + ASN_INTEGER, WATCHER_FIXED_SIZE )); +} + + +int +netsnmp_register_int_scalar(const char *name, + oid * reg_oid, size_t reg_oid_len, + int * it, + Netsnmp_Node_Handler * subhandler) +{ + return netsnmp_register_watched_scalar( + netsnmp_create_handler_registration( + name, subhandler, + reg_oid, reg_oid_len, + HANDLER_CAN_RWRITE ), + netsnmp_create_watcher_info( + (void *)it, sizeof( int ), + ASN_INTEGER, WATCHER_FIXED_SIZE )); +} + +int +netsnmp_register_read_only_int_scalar(const char *name, + oid * reg_oid, size_t reg_oid_len, + int * it, + Netsnmp_Node_Handler * subhandler) +{ + return netsnmp_register_watched_scalar( + netsnmp_create_handler_registration( + name, subhandler, + reg_oid, reg_oid_len, + HANDLER_CAN_RONLY ), + netsnmp_create_watcher_info( + (void *)it, sizeof( int ), + ASN_INTEGER, WATCHER_FIXED_SIZE )); +} + + +int +netsnmp_register_read_only_counter32_scalar(const char *name, + oid * reg_oid, size_t reg_oid_len, + u_long * it, + Netsnmp_Node_Handler * subhandler) +{ + return netsnmp_register_watched_scalar( + netsnmp_create_handler_registration( + name, subhandler, + reg_oid, reg_oid_len, + HANDLER_CAN_RONLY ), + netsnmp_create_watcher_info( + (void *)it, sizeof( u_long ), + ASN_COUNTER, WATCHER_FIXED_SIZE )); +} +/** @} */ + |