summaryrefslogtreecommitdiff
path: root/agent/helpers/watcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/helpers/watcher.c')
-rw-r--r--agent/helpers/watcher.c485
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 ));
+}
+/** @} */
+