Coverage Report

Created: 2023-06-07 06:43

/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 */