253 lines
8.7 KiB
C
253 lines
8.7 KiB
C
#include <net-snmp/net-snmp-config.h>
|
|
|
|
#include <net-snmp/net-snmp-features.h>
|
|
#include <net-snmp/net-snmp-includes.h>
|
|
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
|
|
|
netsnmp_feature_provide(stash_cache)
|
|
netsnmp_feature_child_of(stash_cache, mib_helpers)
|
|
#ifdef NETSNMP_FEATURE_REQUIRE_STASH_CACHE
|
|
netsnmp_feature_require(oid_stash)
|
|
netsnmp_feature_require(oid_stash_iterate)
|
|
netsnmp_feature_require(oid_stash_get_data)
|
|
#endif
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_STASH_CACHE
|
|
#include <net-snmp/agent/stash_to_next.h>
|
|
|
|
#include <net-snmp/agent/stash_cache.h>
|
|
|
|
extern NetsnmpCacheLoad _netsnmp_stash_cache_load;
|
|
extern NetsnmpCacheFree _netsnmp_stash_cache_free;
|
|
|
|
/** @defgroup stash_cache stash_cache
|
|
* Automatically caches data for certain handlers.
|
|
* This handler caches data in an optimized way which may alleviate
|
|
* the need for the lower level handlers to perform as much
|
|
* optimization. Specifically, somewhere in the lower level handlers
|
|
* must be a handler that supports the MODE_GET_STASH operation.
|
|
* Note that the table_iterator helper supports this.
|
|
* @ingroup handler
|
|
* @{
|
|
*/
|
|
|
|
netsnmp_stash_cache_info *
|
|
netsnmp_get_new_stash_cache(void)
|
|
{
|
|
netsnmp_stash_cache_info *cinfo;
|
|
|
|
cinfo = SNMP_MALLOC_TYPEDEF(netsnmp_stash_cache_info);
|
|
if (cinfo != NULL)
|
|
cinfo->cache_length = 30;
|
|
return cinfo;
|
|
}
|
|
|
|
/** returns a stash_cache handler that can be injected into a given
|
|
* handler chain (with the specified timeout and root OID values),
|
|
* but *only* if that handler chain explicitly supports stash cache processing.
|
|
*/
|
|
netsnmp_mib_handler *
|
|
netsnmp_get_timed_bare_stash_cache_handler(int timeout, oid *rootoid, size_t rootoid_len)
|
|
{
|
|
netsnmp_mib_handler *handler;
|
|
netsnmp_cache *cinfo;
|
|
|
|
cinfo = netsnmp_cache_create( timeout, _netsnmp_stash_cache_load,
|
|
_netsnmp_stash_cache_free, rootoid, rootoid_len );
|
|
|
|
if (!cinfo)
|
|
return NULL;
|
|
|
|
handler = netsnmp_cache_handler_get( cinfo );
|
|
if (!handler) {
|
|
free(cinfo);
|
|
return NULL;
|
|
}
|
|
|
|
handler->next = netsnmp_create_handler("stash_cache", netsnmp_stash_cache_helper);
|
|
if (!handler->next) {
|
|
netsnmp_handler_free(handler);
|
|
free(cinfo);
|
|
return NULL;
|
|
}
|
|
|
|
handler->myvoid = cinfo;
|
|
netsnmp_cache_handler_owns_cache(handler);
|
|
|
|
return handler;
|
|
}
|
|
|
|
/** returns a single stash_cache handler that can be injected into a given
|
|
* handler chain (with a fixed timeout), but *only* if that handler chain
|
|
* explicitly supports stash cache processing.
|
|
*/
|
|
netsnmp_mib_handler *
|
|
netsnmp_get_bare_stash_cache_handler(void)
|
|
{
|
|
return netsnmp_get_timed_bare_stash_cache_handler( 30, NULL, 0 );
|
|
}
|
|
|
|
/** returns a stash_cache handler sub-chain that can be injected into a given
|
|
* (arbitrary) handler chain, using a fixed cache timeout.
|
|
*/
|
|
netsnmp_mib_handler *
|
|
netsnmp_get_stash_cache_handler(void)
|
|
{
|
|
netsnmp_mib_handler *handler = netsnmp_get_bare_stash_cache_handler();
|
|
if (handler && handler->next) {
|
|
handler->next->next = netsnmp_get_stash_to_next_handler();
|
|
}
|
|
return handler;
|
|
}
|
|
|
|
/** returns a stash_cache handler sub-chain that can be injected into a given
|
|
* (arbitrary) handler chain, using a configurable cache timeout.
|
|
*/
|
|
netsnmp_mib_handler *
|
|
netsnmp_get_timed_stash_cache_handler(int timeout, oid *rootoid, size_t rootoid_len)
|
|
{
|
|
netsnmp_mib_handler *handler =
|
|
netsnmp_get_timed_bare_stash_cache_handler(timeout, rootoid, rootoid_len);
|
|
if (handler && handler->next) {
|
|
handler->next->next = netsnmp_get_stash_to_next_handler();
|
|
}
|
|
return handler;
|
|
}
|
|
|
|
/** extracts a pointer to the stash_cache info from the reqinfo structure. */
|
|
netsnmp_oid_stash_node **
|
|
netsnmp_extract_stash_cache(netsnmp_agent_request_info *reqinfo)
|
|
{
|
|
return (netsnmp_oid_stash_node**)netsnmp_agent_get_list_data(reqinfo, STASH_CACHE_NAME);
|
|
}
|
|
|
|
|
|
/** @internal Implements the stash_cache handler */
|
|
int
|
|
netsnmp_stash_cache_helper(netsnmp_mib_handler *handler,
|
|
netsnmp_handler_registration *reginfo,
|
|
netsnmp_agent_request_info *reqinfo,
|
|
netsnmp_request_info *requests)
|
|
{
|
|
netsnmp_cache *cache;
|
|
netsnmp_stash_cache_info *cinfo;
|
|
netsnmp_oid_stash_node *cnode;
|
|
netsnmp_variable_list *cdata;
|
|
netsnmp_request_info *request;
|
|
|
|
DEBUGMSGTL(("helper:stash_cache", "Got request\n"));
|
|
|
|
cache = netsnmp_cache_reqinfo_extract( reqinfo, reginfo->handlerName );
|
|
if (!cache) {
|
|
DEBUGMSGTL(("helper:stash_cache", "No cache structure\n"));
|
|
return SNMP_ERR_GENERR;
|
|
}
|
|
cinfo = (netsnmp_stash_cache_info *) cache->magic;
|
|
|
|
switch (reqinfo->mode) {
|
|
|
|
case MODE_GET:
|
|
DEBUGMSGTL(("helper:stash_cache", "Processing GET request\n"));
|
|
for(request = requests; request; request = request->next) {
|
|
cdata = (netsnmp_variable_list*)
|
|
netsnmp_oid_stash_get_data(cinfo->cache,
|
|
requests->requestvb->name,
|
|
requests->requestvb->name_length);
|
|
if (cdata && cdata->val.string && cdata->val_len) {
|
|
DEBUGMSGTL(("helper:stash_cache", "Found cached GET varbind\n"));
|
|
DEBUGMSGOID(("helper:stash_cache", cdata->name, cdata->name_length));
|
|
DEBUGMSG(("helper:stash_cache", "\n"));
|
|
snmp_set_var_typed_value(request->requestvb, cdata->type,
|
|
cdata->val.string, cdata->val_len);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MODE_GETNEXT:
|
|
DEBUGMSGTL(("helper:stash_cache", "Processing GETNEXT request\n"));
|
|
for(request = requests; request; request = request->next) {
|
|
cnode =
|
|
netsnmp_oid_stash_getnext_node(cinfo->cache,
|
|
requests->requestvb->name,
|
|
requests->requestvb->name_length);
|
|
if (cnode && cnode->thedata) {
|
|
cdata = (netsnmp_variable_list*)cnode->thedata;
|
|
if (cdata->val.string && cdata->name && cdata->name_length) {
|
|
DEBUGMSGTL(("helper:stash_cache", "Found cached GETNEXT varbind\n"));
|
|
DEBUGMSGOID(("helper:stash_cache", cdata->name, cdata->name_length));
|
|
DEBUGMSG(("helper:stash_cache", "\n"));
|
|
snmp_set_var_typed_value(request->requestvb, cdata->type,
|
|
cdata->val.string, cdata->val_len);
|
|
snmp_set_var_objid(request->requestvb, cdata->name,
|
|
cdata->name_length);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
cinfo->cache_valid = 0;
|
|
return netsnmp_call_next_handler(handler, reginfo, reqinfo,
|
|
requests);
|
|
}
|
|
|
|
return SNMP_ERR_NOERROR;
|
|
}
|
|
|
|
/** updates a given cache depending on whether it needs to or not.
|
|
*/
|
|
int
|
|
_netsnmp_stash_cache_load( netsnmp_cache *cache, void *magic )
|
|
{
|
|
netsnmp_mib_handler *handler = cache->cache_hint->handler;
|
|
netsnmp_handler_registration *reginfo = cache->cache_hint->reginfo;
|
|
netsnmp_agent_request_info *reqinfo = cache->cache_hint->reqinfo;
|
|
netsnmp_request_info *requests = cache->cache_hint->requests;
|
|
netsnmp_stash_cache_info *cinfo = (netsnmp_stash_cache_info*) magic;
|
|
int old_mode;
|
|
int ret;
|
|
|
|
if (!cinfo) {
|
|
cinfo = netsnmp_get_new_stash_cache();
|
|
cache->magic = cinfo;
|
|
}
|
|
|
|
/* change modes to the GET_STASH mode */
|
|
old_mode = reqinfo->mode;
|
|
reqinfo->mode = MODE_GET_STASH;
|
|
netsnmp_agent_add_list_data(reqinfo,
|
|
netsnmp_create_data_list(STASH_CACHE_NAME,
|
|
&cinfo->cache, NULL));
|
|
|
|
/* have the next handler fill stuff in and switch modes back */
|
|
ret = netsnmp_call_next_handler(handler->next, reginfo, reqinfo, requests);
|
|
reqinfo->mode = old_mode;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
_netsnmp_stash_cache_free( netsnmp_cache *cache, void *magic )
|
|
{
|
|
netsnmp_stash_cache_info *cinfo = (netsnmp_stash_cache_info*) magic;
|
|
netsnmp_oid_stash_free(&cinfo->cache,
|
|
(NetSNMPStashFreeNode *) snmp_free_var);
|
|
return;
|
|
}
|
|
|
|
/** initializes the stash_cache helper which then registers a stash_cache
|
|
* handler as a run-time injectable handler for configuration file
|
|
* use.
|
|
*/
|
|
void
|
|
netsnmp_init_stash_cache_helper(void)
|
|
{
|
|
netsnmp_register_handler_by_name("stash_cache",
|
|
netsnmp_get_stash_cache_handler());
|
|
}
|
|
/** @} */
|
|
|
|
#else /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */
|
|
netsnmp_feature_unused(stash_cache);
|
|
#endif /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */
|