/src/net-snmp/agent/helpers/stash_cache.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <net-snmp/net-snmp-config.h> |
2 | | |
3 | | #include <net-snmp/net-snmp-features.h> |
4 | | #include <net-snmp/net-snmp-includes.h> |
5 | | #include <net-snmp/agent/net-snmp-agent-includes.h> |
6 | | |
7 | | netsnmp_feature_provide(stash_cache); |
8 | | netsnmp_feature_child_of(stash_cache, mib_helpers); |
9 | | #ifdef NETSNMP_FEATURE_REQUIRE_STASH_CACHE |
10 | | netsnmp_feature_require(oid_stash); |
11 | | netsnmp_feature_require(oid_stash_iterate); |
12 | | netsnmp_feature_require(oid_stash_get_data); |
13 | | #endif |
14 | | |
15 | | #ifndef NETSNMP_FEATURE_REMOVE_STASH_CACHE |
16 | | #include <net-snmp/agent/stash_to_next.h> |
17 | | |
18 | | #include <net-snmp/agent/stash_cache.h> |
19 | | |
20 | | extern NetsnmpCacheLoad _netsnmp_stash_cache_load; |
21 | | extern NetsnmpCacheFree _netsnmp_stash_cache_free; |
22 | | |
23 | | /** @defgroup stash_cache stash_cache |
24 | | * Automatically caches data for certain handlers. |
25 | | * This handler caches data in an optimized way which may alleviate |
26 | | * the need for the lower level handlers to perform as much |
27 | | * optimization. Specifically, somewhere in the lower level handlers |
28 | | * must be a handler that supports the MODE_GET_STASH operation. |
29 | | * Note that the table_iterator helper supports this. |
30 | | * @ingroup handler |
31 | | * @{ |
32 | | */ |
33 | | |
34 | | netsnmp_stash_cache_info * |
35 | | netsnmp_get_new_stash_cache(void) |
36 | 0 | { |
37 | 0 | netsnmp_stash_cache_info *cinfo; |
38 | |
|
39 | 0 | cinfo = SNMP_MALLOC_TYPEDEF(netsnmp_stash_cache_info); |
40 | 0 | if (cinfo != NULL) |
41 | 0 | cinfo->cache_length = 30; |
42 | 0 | return cinfo; |
43 | 0 | } |
44 | | |
45 | | /** returns a stash_cache handler that can be injected into a given |
46 | | * handler chain (with the specified timeout and root OID values), |
47 | | * but *only* if that handler chain explicitly supports stash cache processing. |
48 | | */ |
49 | | netsnmp_mib_handler * |
50 | | netsnmp_get_timed_bare_stash_cache_handler(int timeout, oid *rootoid, size_t rootoid_len) |
51 | 2.98k | { |
52 | 2.98k | netsnmp_mib_handler *handler; |
53 | 2.98k | netsnmp_cache *cinfo; |
54 | | |
55 | 2.98k | cinfo = netsnmp_cache_create( timeout, _netsnmp_stash_cache_load, |
56 | 2.98k | _netsnmp_stash_cache_free, rootoid, rootoid_len ); |
57 | | |
58 | 2.98k | if (!cinfo) |
59 | 0 | return NULL; |
60 | | |
61 | 2.98k | handler = netsnmp_cache_handler_get( cinfo ); |
62 | 2.98k | if (!handler) { |
63 | 0 | free(cinfo); |
64 | 0 | return NULL; |
65 | 0 | } |
66 | | |
67 | 2.98k | handler->next = netsnmp_create_handler("stash_cache", netsnmp_stash_cache_helper); |
68 | 2.98k | if (!handler->next) { |
69 | 0 | netsnmp_handler_free(handler); |
70 | 0 | free(cinfo); |
71 | 0 | return NULL; |
72 | 0 | } |
73 | | |
74 | 2.98k | handler->myvoid = cinfo; |
75 | 2.98k | netsnmp_cache_handler_owns_cache(handler); |
76 | | |
77 | 2.98k | return handler; |
78 | 2.98k | } |
79 | | |
80 | | /** returns a single stash_cache handler that can be injected into a given |
81 | | * handler chain (with a fixed timeout), but *only* if that handler chain |
82 | | * explicitly supports stash cache processing. |
83 | | */ |
84 | | netsnmp_mib_handler * |
85 | | netsnmp_get_bare_stash_cache_handler(void) |
86 | 2.98k | { |
87 | 2.98k | return netsnmp_get_timed_bare_stash_cache_handler( 30, NULL, 0 ); |
88 | 2.98k | } |
89 | | |
90 | | /** returns a stash_cache handler sub-chain that can be injected into a given |
91 | | * (arbitrary) handler chain, using a fixed cache timeout. |
92 | | */ |
93 | | netsnmp_mib_handler * |
94 | | netsnmp_get_stash_cache_handler(void) |
95 | 2.98k | { |
96 | 2.98k | netsnmp_mib_handler *handler = netsnmp_get_bare_stash_cache_handler(); |
97 | 2.98k | if (handler && handler->next) { |
98 | 2.98k | handler->next->next = netsnmp_get_stash_to_next_handler(); |
99 | 2.98k | } |
100 | 2.98k | return handler; |
101 | 2.98k | } |
102 | | |
103 | | /** returns a stash_cache handler sub-chain that can be injected into a given |
104 | | * (arbitrary) handler chain, using a configurable cache timeout. |
105 | | */ |
106 | | netsnmp_mib_handler * |
107 | | netsnmp_get_timed_stash_cache_handler(int timeout, oid *rootoid, size_t rootoid_len) |
108 | 0 | { |
109 | 0 | netsnmp_mib_handler *handler = |
110 | 0 | netsnmp_get_timed_bare_stash_cache_handler(timeout, rootoid, rootoid_len); |
111 | 0 | if (handler && handler->next) { |
112 | 0 | handler->next->next = netsnmp_get_stash_to_next_handler(); |
113 | 0 | } |
114 | 0 | return handler; |
115 | 0 | } |
116 | | |
117 | | /** extracts a pointer to the stash_cache info from the reqinfo structure. */ |
118 | | netsnmp_oid_stash_node ** |
119 | | netsnmp_extract_stash_cache(netsnmp_agent_request_info *reqinfo) |
120 | 0 | { |
121 | 0 | return (netsnmp_oid_stash_node**)netsnmp_agent_get_list_data(reqinfo, STASH_CACHE_NAME); |
122 | 0 | } |
123 | | |
124 | | |
125 | | /** @internal Implements the stash_cache handler */ |
126 | | int |
127 | | netsnmp_stash_cache_helper(netsnmp_mib_handler *handler, |
128 | | netsnmp_handler_registration *reginfo, |
129 | | netsnmp_agent_request_info *reqinfo, |
130 | | netsnmp_request_info *requests) |
131 | 0 | { |
132 | 0 | netsnmp_cache *cache; |
133 | 0 | netsnmp_stash_cache_info *cinfo; |
134 | 0 | netsnmp_oid_stash_node *cnode; |
135 | 0 | netsnmp_variable_list *cdata; |
136 | 0 | netsnmp_request_info *request; |
137 | |
|
138 | 0 | DEBUGMSGTL(("helper:stash_cache", "Got request\n")); |
139 | |
|
140 | 0 | cache = netsnmp_cache_reqinfo_extract( reqinfo, reginfo->handlerName ); |
141 | 0 | if (!cache) { |
142 | 0 | DEBUGMSGTL(("helper:stash_cache", "No cache structure\n")); |
143 | 0 | return SNMP_ERR_GENERR; |
144 | 0 | } |
145 | 0 | cinfo = (netsnmp_stash_cache_info *) cache->magic; |
146 | |
|
147 | 0 | switch (reqinfo->mode) { |
148 | | |
149 | 0 | case MODE_GET: |
150 | 0 | DEBUGMSGTL(("helper:stash_cache", "Processing GET request\n")); |
151 | 0 | for(request = requests; request; request = request->next) { |
152 | 0 | cdata = (netsnmp_variable_list*) |
153 | 0 | netsnmp_oid_stash_get_data(cinfo->cache, |
154 | 0 | requests->requestvb->name, |
155 | 0 | requests->requestvb->name_length); |
156 | 0 | if (cdata && cdata->val.string && cdata->val_len) { |
157 | 0 | DEBUGMSGTL(("helper:stash_cache", "Found cached GET varbind\n")); |
158 | 0 | DEBUGMSGOID(("helper:stash_cache", cdata->name, cdata->name_length)); |
159 | 0 | DEBUGMSG(("helper:stash_cache", "\n")); |
160 | 0 | snmp_set_var_typed_value(request->requestvb, cdata->type, |
161 | 0 | cdata->val.string, cdata->val_len); |
162 | 0 | } |
163 | 0 | } |
164 | 0 | break; |
165 | | |
166 | 0 | case MODE_GETNEXT: |
167 | 0 | DEBUGMSGTL(("helper:stash_cache", "Processing GETNEXT request\n")); |
168 | 0 | for(request = requests; request; request = request->next) { |
169 | 0 | cnode = |
170 | 0 | netsnmp_oid_stash_getnext_node(cinfo->cache, |
171 | 0 | requests->requestvb->name, |
172 | 0 | requests->requestvb->name_length); |
173 | 0 | if (cnode && cnode->thedata) { |
174 | 0 | cdata = (netsnmp_variable_list*)cnode->thedata; |
175 | 0 | if (cdata->val.string && cdata->name && cdata->name_length) { |
176 | 0 | DEBUGMSGTL(("helper:stash_cache", "Found cached GETNEXT varbind\n")); |
177 | 0 | DEBUGMSGOID(("helper:stash_cache", cdata->name, cdata->name_length)); |
178 | 0 | DEBUGMSG(("helper:stash_cache", "\n")); |
179 | 0 | snmp_set_var_typed_value(request->requestvb, cdata->type, |
180 | 0 | cdata->val.string, cdata->val_len); |
181 | 0 | snmp_set_var_objid(request->requestvb, cdata->name, |
182 | 0 | cdata->name_length); |
183 | 0 | } |
184 | 0 | } |
185 | 0 | } |
186 | 0 | break; |
187 | | |
188 | 0 | default: |
189 | 0 | cinfo->cache_valid = 0; |
190 | 0 | return netsnmp_call_next_handler(handler, reginfo, reqinfo, |
191 | 0 | requests); |
192 | 0 | } |
193 | | |
194 | 0 | return SNMP_ERR_NOERROR; |
195 | 0 | } |
196 | | |
197 | | /** updates a given cache depending on whether it needs to or not. |
198 | | */ |
199 | | int |
200 | | _netsnmp_stash_cache_load( netsnmp_cache *cache, void *magic ) |
201 | 0 | { |
202 | 0 | netsnmp_mib_handler *handler = cache->cache_hint->handler; |
203 | 0 | netsnmp_handler_registration *reginfo = cache->cache_hint->reginfo; |
204 | 0 | netsnmp_agent_request_info *reqinfo = cache->cache_hint->reqinfo; |
205 | 0 | netsnmp_request_info *requests = cache->cache_hint->requests; |
206 | 0 | netsnmp_stash_cache_info *cinfo = (netsnmp_stash_cache_info*) magic; |
207 | 0 | int old_mode; |
208 | 0 | int ret; |
209 | |
|
210 | 0 | if (!cinfo) { |
211 | 0 | cinfo = netsnmp_get_new_stash_cache(); |
212 | 0 | cache->magic = cinfo; |
213 | 0 | } |
214 | | |
215 | | /* change modes to the GET_STASH mode */ |
216 | 0 | old_mode = reqinfo->mode; |
217 | 0 | reqinfo->mode = MODE_GET_STASH; |
218 | 0 | netsnmp_agent_add_list_data(reqinfo, |
219 | 0 | netsnmp_create_data_list(STASH_CACHE_NAME, |
220 | 0 | &cinfo->cache, NULL)); |
221 | | |
222 | | /* have the next handler fill stuff in and switch modes back */ |
223 | 0 | ret = netsnmp_call_next_handler(handler->next, reginfo, reqinfo, requests); |
224 | 0 | reqinfo->mode = old_mode; |
225 | |
|
226 | 0 | return ret; |
227 | 0 | } |
228 | | |
229 | | void |
230 | | _netsnmp_stash_cache_free( netsnmp_cache *cache, void *magic ) |
231 | 0 | { |
232 | 0 | netsnmp_stash_cache_info *cinfo = (netsnmp_stash_cache_info*) magic; |
233 | 0 | netsnmp_oid_stash_free(&cinfo->cache, |
234 | 0 | (NetSNMPStashFreeNode *) snmp_free_var); |
235 | 0 | return; |
236 | 0 | } |
237 | | |
238 | | /** initializes the stash_cache helper which then registers a stash_cache |
239 | | * handler as a run-time injectable handler for configuration file |
240 | | * use. |
241 | | */ |
242 | | void |
243 | | netsnmp_init_stash_cache_helper(void) |
244 | 2.98k | { |
245 | 2.98k | netsnmp_register_handler_by_name("stash_cache", |
246 | 2.98k | netsnmp_get_stash_cache_handler()); |
247 | 2.98k | } |
248 | | /** @} */ |
249 | | |
250 | | #else /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */ |
251 | | netsnmp_feature_unused(stash_cache); |
252 | | #endif /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */ |