📄 cache_handler.c
字号:
int timeout, NetsnmpCacheLoad * load_hook, NetsnmpCacheFree * free_hook){ netsnmp_mib_handler *handler = NULL; handler = netsnmp_get_cache_handler(timeout, load_hook, free_hook, reginfo->rootoid, reginfo->rootoid_len); netsnmp_inject_handler(reginfo, handler); return netsnmp_register_handler(reginfo);}NETSNMP_STATIC_INLINE char *_build_cache_name(const char *name){ char *dup = malloc(strlen(name) + strlen(CACHE_NAME) + 2); if (NULL == dup) return NULL; sprintf(dup, "%s:%s", CACHE_NAME, name); return dup;}/** Insert the cache information for a given request (PDU) */voidnetsnmp_cache_reqinfo_insert(netsnmp_cache* cache, netsnmp_agent_request_info * reqinfo, const char *name){ char *cache_name = _build_cache_name(name); if (NULL == netsnmp_agent_get_list_data(reqinfo, cache_name)) { DEBUGMSGTL(("verbose:helper:cache_handler", " adding '%s' to %p\n", cache_name, reqinfo)); netsnmp_agent_add_list_data(reqinfo, netsnmp_create_data_list(cache_name, cache, NULL)); } SNMP_FREE(cache_name);}/** Extract the cache information for a given request (PDU) */netsnmp_cache *netsnmp_cache_reqinfo_extract(netsnmp_agent_request_info * reqinfo, const char *name){ netsnmp_cache *result; char *cache_name = _build_cache_name(name); result = netsnmp_agent_get_list_data(reqinfo, cache_name); SNMP_FREE(cache_name); return result;}/** Extract the cache information for a given request (PDU) */netsnmp_cache *netsnmp_extract_cache_info(netsnmp_agent_request_info * reqinfo){ return netsnmp_cache_reqinfo_extract(reqinfo, CACHE_NAME);}/** Check if the cache timeout has passed. Sets and return the expired flag. */intnetsnmp_cache_check_expired(netsnmp_cache *cache){ if(NULL == cache) return 0; if(!cache->valid || (NULL == cache->timestamp) || (-1 == cache->timeout)) cache->expired = 1; else cache->expired = atime_ready(cache->timestamp, 1000 * cache->timeout); return cache->expired;}/** Reload the cache if required */intnetsnmp_cache_check_and_reload(netsnmp_cache * cache){ if (!cache) { DEBUGMSG(("helper:cache_handler", " no cache\n")); return 0; /* ?? or -1 */ } if (!cache->valid || netsnmp_cache_check_expired(cache)) return _cache_load( cache ); else { DEBUGMSG(("helper:cache_handler", " cached (%d)\n", cache->timeout)); return 0; }}/** Is the cache valid for a given request? */intnetsnmp_cache_is_valid(netsnmp_agent_request_info * reqinfo, const char* name){ netsnmp_cache *cache = netsnmp_cache_reqinfo_extract(reqinfo, name); return (cache && cache->valid);}/** Is the cache valid for a given request? * for backwards compatability. netsnmp_cache_is_valid() is preferred. */intnetsnmp_is_cache_valid(netsnmp_agent_request_info * reqinfo){ return netsnmp_cache_is_valid(reqinfo, CACHE_NAME);}/** Implements the cache handler */intnetsnmp_cache_helper_handler(netsnmp_mib_handler * handler, netsnmp_handler_registration * reginfo, netsnmp_agent_request_info * reqinfo, netsnmp_request_info * requests){ netsnmp_cache *cache = NULL; DEBUGMSGTL(("helper:cache_handler", "Got request (%d) for %s: ", reqinfo->mode, reginfo->handlerName)); DEBUGMSGOID(("helper:cache_handler", reginfo->rootoid, reginfo->rootoid_len)); netsnmp_assert(handler->flags & MIB_HANDLER_AUTO_NEXT); cache = (netsnmp_cache *) handler->myvoid; if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CACHING) || !cache || !cache->enabled || !cache->load_cache) { DEBUGMSG(("helper:cache_handler", " caching disabled or " "cache not found, disabled or had no load method\n")); return SNMP_ERR_NOERROR; } switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: case MODE_GETBULK: case MODE_SET_RESERVE1: { netsnmp_handler_args cache_hint; /* * only touch cache once per pdu request, to prevent a cache * reload while a module is using cached data. * * XXX: this won't catch a request reloading the cache while * a previous (delegated) request is still using the cache. * maybe use a reference counter? */ if (netsnmp_cache_is_valid(reqinfo, reginfo->handlerName)) return SNMP_ERR_NOERROR; if (cache->flags & NETSNMP_CACHE_HINT_HANDLER_ARGS) { netsnmp_assert(NULL == cache->cache_hint); cache_hint.handler = handler; cache_hint.reginfo = reginfo; cache_hint.reqinfo = reqinfo; cache_hint.requests = requests; cache->cache_hint = &cache_hint; } /* * call the load hook, and update the cache timestamp. * If it's not already there, add to reqinfo */ netsnmp_cache_check_and_reload(cache); netsnmp_cache_reqinfo_insert(cache, reqinfo, reginfo->handlerName); cache->cache_hint = NULL; /** next handler called automatically - 'AUTO_NEXT' */ } return SNMP_ERR_NOERROR; case MODE_SET_RESERVE2: case MODE_SET_FREE: case MODE_SET_ACTION: case MODE_SET_UNDO: netsnmp_assert(netsnmp_cache_is_valid(reqinfo, reginfo->handlerName)); /** next handler called automatically - 'AUTO_NEXT' */ return SNMP_ERR_NOERROR; /* * A (successful) SET request wouldn't typically trigger a reload of * the cache, but might well invalidate the current contents. * Only do this on the last pass through. */ case MODE_SET_COMMIT: if (cache->valid && ! (cache->flags & NETSNMP_CACHE_DONT_INVALIDATE_ON_SET) ) { cache->free_cache(cache, cache->magic); cache->valid = 0; } /** next handler called automatically - 'AUTO_NEXT' */ return SNMP_ERR_NOERROR; default: snmp_log(LOG_WARNING, "cache_handler: Unrecognised mode (%d)\n", reqinfo->mode); netsnmp_set_all_requests_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_GENERR; } netsnmp_set_all_requests_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_GENERR; /* should never get here */}static void_cache_free( netsnmp_cache *cache ){ if (NULL != cache->free_cache) { cache->free_cache(cache, cache->magic); cache->valid = 0; }}static int_cache_load( netsnmp_cache *cache ){ int ret = -1; /* * If we've got a valid cache, then release it before reloading */ if (cache->valid && (! (cache->flags & NETSNMP_CACHE_DONT_FREE_BEFORE_LOAD))) _cache_free(cache); if ( cache->load_cache) ret = cache->load_cache(cache, cache->magic); if (ret < 0) { DEBUGMSG(("helper:cache_handler", " load failed (%d)\n", ret)); cache->valid = 0; return ret; } cache->valid = 1; cache->expired = 0; /* * If we didn't previously have any valid caches outstanding, * then schedule a pass of the auto-release routine. */ if ((!cache_outstanding_valid) && (! (cache->flags & NETSNMP_CACHE_DONT_FREE_EXPIRED))) { snmp_alarm_register(CACHE_RELEASE_FREQUENCY, 0, release_cached_resources, NULL); cache_outstanding_valid = 1; } if (cache->timestamp) atime_setMarker(cache->timestamp); else cache->timestamp = atime_newMarker(); DEBUGMSG(("helper:cache_handler", " loaded (%d)\n", cache->timeout)); return ret;}/** run regularly to automatically release cached resources. * xxx - method to prevent cache from expiring while a request * is being processed (e.g. delegated request). proposal: * set a flag, which would be cleared when request finished * (which could be acomplished by a dummy data list item in * agent req info & custom free function). */voidrelease_cached_resources(unsigned int regNo, void *clientargs){ netsnmp_cache *cache = NULL; cache_outstanding_valid = 0; DEBUGMSGTL(("helper:cache_handler", "running auto-release\n")); for (cache = cache_head; cache; cache = cache->next) { DEBUGMSGTL(("helper:cache_handler"," checking %p (flags 0x%x)\n", cache, cache->flags)); if (cache->valid && ! (cache->flags & NETSNMP_CACHE_DONT_AUTO_RELEASE)) { DEBUGMSGTL(("helper:cache_handler"," releasing %p\n", cache)); /* * Check to see if this cache has timed out. * If so, release the cached resources. * Otherwise, note that we still have at * least one active cache. */ if (netsnmp_cache_check_expired(cache)) { if(! (cache->flags & NETSNMP_CACHE_DONT_FREE_EXPIRED)) _cache_free(cache); } else { cache_outstanding_valid = 1; } } } /* * If there are any caches still valid & active, * then schedule another pass. */ if (cache_outstanding_valid) { snmp_alarm_register(CACHE_RELEASE_FREQUENCY, 0, release_cached_resources, NULL); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -