~ubuntu-branches/ubuntu/gutsy/net-snmp/gutsy-security

« back to all changes in this revision

Viewing changes to snmplib/oid_stash.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-13 12:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20040913120621-g952ntonlleihcvm
Tags: upstream-5.1.1
ImportĀ upstreamĀ versionĀ 5.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <net-snmp/net-snmp-config.h>
 
2
 
 
3
#include <string.h>
 
4
 
 
5
#include <stdlib.h>
 
6
#include <sys/types.h>
 
7
 
 
8
#if HAVE_DMALLOC_H
 
9
#include <dmalloc.h>
 
10
#endif
 
11
 
 
12
#include <net-snmp/net-snmp-includes.h>
 
13
 
 
14
/** @defgroup oid_stash Store and retrieve data referenced by an OID.
 
15
    This is essentially a way of storing data associated with a given
 
16
    OID.  It stores a bunch of data pointers within a memory tree that
 
17
    allows fairly efficient lookups with a heavily populated tree.
 
18
    @ingroup library
 
19
    @{
 
20
*/
 
21
 
 
22
/*
 
23
 * xxx-rks: when you have some spare time:
 
24
 *
 
25
 * b) basically, everything currently creates one node per sub-oid,
 
26
 *    which is less than optimal. add code to create nodes with the
 
27
 *    longest possible OID per node, and split nodes when necessary
 
28
 *    during adds.
 
29
 *
 
30
 * c) If you are feeling really ambitious, also merge split nodes if
 
31
 *    possible on a delete.
 
32
 *
 
33
 * xxx-wes: uh, right, like I *ever* have that much time.
 
34
 *
 
35
 */
 
36
 
 
37
/***************************************************************************
 
38
 *
 
39
 *
 
40
 ***************************************************************************/
 
41
 
 
42
/**
 
43
 * Create an netsnmp_oid_stash node
 
44
 *
 
45
 * @param mysize  the size of the child pointer array
 
46
 *
 
47
 * @return NULL on error, otherwise the newly allocated node
 
48
 */
 
49
netsnmp_oid_stash_node *
 
50
netsnmp_oid_stash_create_sized_node(size_t mysize)
 
51
{
 
52
    netsnmp_oid_stash_node *ret;
 
53
    ret = SNMP_MALLOC_TYPEDEF(netsnmp_oid_stash_node);
 
54
    if (!ret)
 
55
        return NULL;
 
56
    ret->children = calloc(mysize, sizeof(netsnmp_oid_stash_node *));
 
57
    if (!ret->children) {
 
58
        free(ret);
 
59
        return NULL;
 
60
    }
 
61
    ret->children_size = mysize;
 
62
    return ret;
 
63
}
 
64
 
 
65
/** Creates a netsnmp_oid_stash_node.
 
66
 * Assumes you want the default OID_STASH_CHILDREN_SIZE hash size for the node.
 
67
 * @return NULL on error, otherwise the newly allocated node
 
68
 */
 
69
NETSNMP_INLINE netsnmp_oid_stash_node *
 
70
netsnmp_oid_stash_create_node(void)
 
71
{
 
72
    return netsnmp_oid_stash_create_sized_node(OID_STASH_CHILDREN_SIZE);
 
73
}
 
74
 
 
75
/** adds data to the stash at a given oid.
 
76
 
 
77
 * @param root the top of the stash tree
 
78
 * @param lookup the oid index to store the data at.
 
79
 * @param lookup_len the length of the lookup oid.
 
80
 * @param mydata the data to store
 
81
 
 
82
 * @return SNMPERR_SUCCESS on success, SNMPERR_GENERR if data is
 
83
   already there, SNMPERR_MALLOC on malloc failures or if arguments
 
84
   passed in with NULL values.
 
85
 */
 
86
int
 
87
netsnmp_oid_stash_add_data(netsnmp_oid_stash_node **root,
 
88
                           oid * lookup, size_t lookup_len, void *mydata)
 
89
{
 
90
    netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
 
91
    unsigned int    i;
 
92
 
 
93
    if (!root || !lookup || lookup_len == 0)
 
94
        return SNMPERR_GENERR;
 
95
 
 
96
    if (!*root) {
 
97
        *root = netsnmp_oid_stash_create_node();
 
98
        if (!*root)
 
99
            return SNMPERR_MALLOC;
 
100
    }
 
101
    tmpp = NULL;
 
102
    for (curnode = *root, i = 0; i < lookup_len; i++) {
 
103
        tmpp = curnode->children[lookup[i] % curnode->children_size];
 
104
        if (!tmpp) {
 
105
            /*
 
106
             * no child in array at all 
 
107
             */
 
108
            tmpp = curnode->children[lookup[i] % curnode->children_size] =
 
109
                netsnmp_oid_stash_create_node();
 
110
            tmpp->value = lookup[i];
 
111
            tmpp->parent = curnode;
 
112
        } else {
 
113
            for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
 
114
                if (loopp->value == lookup[i])
 
115
                    break;
 
116
            }
 
117
            if (loopp) {
 
118
                tmpp = loopp;
 
119
            } else {
 
120
                /*
 
121
                 * none exists.  Create it 
 
122
                 */
 
123
                loopp = netsnmp_oid_stash_create_node();
 
124
                loopp->value = lookup[i];
 
125
                loopp->next_sibling = tmpp;
 
126
                loopp->parent = curnode;
 
127
                tmpp->prev_sibling = loopp;
 
128
                curnode->children[lookup[i] % curnode->children_size] =
 
129
                    loopp;
 
130
                tmpp = loopp;
 
131
            }
 
132
            /*
 
133
             * tmpp now points to the proper node 
 
134
             */
 
135
        }
 
136
        curnode = tmpp;
 
137
    }
 
138
    /*
 
139
     * tmpp now points to the exact match 
 
140
     */
 
141
    if (curnode->thedata)
 
142
        return SNMPERR_GENERR;
 
143
    if (NULL == tmpp)
 
144
        return SNMPERR_GENERR;
 
145
    tmpp->thedata = mydata;
 
146
    return SNMPERR_SUCCESS;
 
147
}
 
148
 
 
149
/** returns a node associated with a given OID.
 
150
 * @param root the top of the stash tree
 
151
 * @param lookup the oid to look up a node for.
 
152
 * @param lookup_len the length of the lookup oid
 
153
 */
 
154
netsnmp_oid_stash_node *
 
155
netsnmp_oid_stash_get_node(netsnmp_oid_stash_node *root,
 
156
                           oid * lookup, size_t lookup_len)
 
157
{
 
158
    netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
 
159
    unsigned int    i;
 
160
 
 
161
    if (!root)
 
162
        return NULL;
 
163
    tmpp = NULL;
 
164
    for (curnode = root, i = 0; i < lookup_len; i++) {
 
165
        tmpp = curnode->children[lookup[i] % curnode->children_size];
 
166
        if (!tmpp) {
 
167
            return NULL;
 
168
        } else {
 
169
            for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
 
170
                if (loopp->value == lookup[i])
 
171
                    break;
 
172
            }
 
173
            if (loopp) {
 
174
                tmpp = loopp;
 
175
            } else {
 
176
                return NULL;
 
177
            }
 
178
        }
 
179
        curnode = tmpp;
 
180
    }
 
181
    return tmpp;
 
182
}
 
183
 
 
184
/** returns the next node associated with a given OID. INCOMPLETE.
 
185
    This is equivelent to a GETNEXT operation.
 
186
 * @internal
 
187
 * @param root the top of the stash tree
 
188
 * @param lookup the oid to look up a node for.
 
189
 * @param lookup_len the length of the lookup oid
 
190
 */
 
191
netsnmp_oid_stash_node *
 
192
netsnmp_oid_stash_getnext_node(netsnmp_oid_stash_node *root,
 
193
                               oid * lookup, size_t lookup_len)
 
194
{
 
195
    netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
 
196
    unsigned int    i, j, bigger_than = 0, do_bigger = 0;
 
197
 
 
198
    if (!root)
 
199
        return NULL;
 
200
    tmpp = NULL;
 
201
 
 
202
    /* get closest matching node */
 
203
    for (curnode = root, i = 0; i < lookup_len; i++) {
 
204
        tmpp = curnode->children[lookup[i] % curnode->children_size];
 
205
        if (!tmpp) {
 
206
            break;
 
207
        } else {
 
208
            for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
 
209
                if (loopp->value == lookup[i])
 
210
                    break;
 
211
            }
 
212
            if (loopp) {
 
213
                tmpp = loopp;
 
214
            } else {
 
215
                break;
 
216
            }
 
217
        }
 
218
        curnode = tmpp;
 
219
    }
 
220
 
 
221
    /* find the *next* node lexographically greater */
 
222
    if (!curnode)
 
223
        return NULL; /* ack! */
 
224
 
 
225
    if (i+1 < lookup_len) {
 
226
        bigger_than = lookup[i+1];
 
227
        do_bigger = 1;
 
228
    }
 
229
 
 
230
    do {
 
231
        /* check the children first */
 
232
        tmpp = NULL;
 
233
        /* next child must be (next) greater than our next search node */
 
234
        /* XXX: should start this loop at best_nums[i]%... and wrap */
 
235
        for(j = 0; j < curnode->children_size; j++) {
 
236
            for (loopp = curnode->children[j];
 
237
                 loopp; loopp = loopp->next_sibling) {
 
238
                if ((!do_bigger || loopp->value > bigger_than) &&
 
239
                    (!tmpp || tmpp->value > loopp->value)) {
 
240
                    tmpp = loopp;
 
241
                    /* XXX: can do better and include min_nums[i] */
 
242
                    if (tmpp->value <= curnode->children_size-1) {
 
243
                        /* best we can do. */
 
244
                        goto done_this_loop;
 
245
                    }
 
246
                }
 
247
            }
 
248
        }
 
249
 
 
250
      done_this_loop:
 
251
        if (tmpp && tmpp->thedata)
 
252
            /* found a node with data.  Go with it. */
 
253
            return tmpp;
 
254
 
 
255
        if (tmpp) {
 
256
            /* found a child node without data, maybe find a grandchild? */
 
257
            do_bigger = 0;
 
258
            curnode = tmpp;
 
259
        } else {
 
260
            /* no respectable children (the bums), we'll have to go up.
 
261
               But to do so, they must be better than our current best_num + 1.
 
262
            */
 
263
            do_bigger = 1;
 
264
            bigger_than = curnode->value;
 
265
            curnode = curnode->parent;
 
266
        }
 
267
    } while (curnode);
 
268
 
 
269
    /* fell off the top */
 
270
    return NULL;
 
271
}
 
272
 
 
273
/** returns a data pointer associated with a given OID.
 
274
 
 
275
    This is equivelent to netsnmp_oid_stash_get_node, but returns only
 
276
    the data not the entire node.
 
277
 
 
278
 * @param root the top of the stash
 
279
 * @param oid the oid to search for
 
280
 * @param the length of the search oid.
 
281
 */
 
282
void           *
 
283
netsnmp_oid_stash_get_data(netsnmp_oid_stash_node *root,
 
284
                           oid * lookup, size_t lookup_len)
 
285
{
 
286
    netsnmp_oid_stash_node *ret;
 
287
    ret = netsnmp_oid_stash_get_node(root, lookup, lookup_len);
 
288
    if (ret)
 
289
        return ret->thedata;
 
290
    return NULL;
 
291
}
 
292
 
 
293
/** a wrapper around netsnmp_oid_stash_store for use with a snmp_alarm.
 
294
 * when calling snmp_alarm, you can list this as a callback.  The
 
295
 * clientarg should be a pointer to a netsnmp_oid_stash_save_info
 
296
 * pointer.  It can also be called directly, of course.  The last
 
297
 * argument (clientarg) is the only one that is used.  The rest are
 
298
 * ignored by the function.
 
299
 * @param clientarg A pointer to a netsnmp_oid_stash_save_info structure.
 
300
 */
 
301
int
 
302
netsnmp_oid_stash_store_all(int majorID, int minorID,
 
303
                            void *serverarg, void *clientarg) {
 
304
    oid oidbase[MAX_OID_LEN];
 
305
    netsnmp_oid_stash_save_info *sinfo;
 
306
    
 
307
    if (!clientarg)
 
308
        return SNMP_ERR_NOERROR;
 
309
    
 
310
    sinfo = clientarg;
 
311
    netsnmp_oid_stash_store(*(sinfo->root), sinfo->token, sinfo->dumpfn,
 
312
                            oidbase,0);
 
313
    return SNMP_ERR_NOERROR;
 
314
}
 
315
 
 
316
/** stores data in a starsh tree to peristent storage.
 
317
 
 
318
    This function can be called to save all data in a stash tree to
 
319
    Net-SNMP's percent storage.  Make sure you register a parsing
 
320
    function with the read_config system to re-incorperate your saved
 
321
    data into future trees.
 
322
 
 
323
    @param root the top of the stash to store.
 
324
    @param tokenname the file token name to save in (passing "snmpd" will
 
325
    save things into snmpd.conf).
 
326
    @param dumpfn A function which can dump the data stored at a particular
 
327
    node into a char buffer.
 
328
    @param curoid must be a pointer to a OID array of length MAX_OID_LEN.
 
329
    @param curoid_len must be 0 for the top level call.
 
330
*/
 
331
void
 
332
netsnmp_oid_stash_store(netsnmp_oid_stash_node *root,
 
333
                        const char *tokenname, NetSNMPStashDump *dumpfn,
 
334
                        oid *curoid, size_t curoid_len) {
 
335
 
 
336
    char buf[SNMP_MAXBUF];
 
337
    netsnmp_oid_stash_node *tmpp;
 
338
    char *cp;
 
339
    char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
 
340
                                          NETSNMP_DS_LIB_APPTYPE);
 
341
    int i;
 
342
    
 
343
    if (!tokenname || !root || !curoid || !dumpfn)
 
344
        return;
 
345
 
 
346
    for (i = 0; i < (int)root->children_size; i++) {
 
347
        if (root->children[i]) {
 
348
            for (tmpp = root->children[i]; tmpp; tmpp = tmpp->next_sibling) {
 
349
                curoid[curoid_len] = tmpp->value;
 
350
                if (tmpp->thedata) {
 
351
                    snprintf(buf, sizeof(buf), "%s ", tokenname);
 
352
                    cp = read_config_save_objid(buf+strlen(buf), curoid,
 
353
                                                curoid_len+1);
 
354
                    *cp++ = ' ';
 
355
                    *cp = '\0';
 
356
                    if ((*dumpfn)(cp, sizeof(buf) - strlen(buf),
 
357
                                  tmpp->thedata, tmpp))
 
358
                        read_config_store(appname, buf);
 
359
                }
 
360
                netsnmp_oid_stash_store(tmpp, tokenname, dumpfn,
 
361
                                        curoid, curoid_len+1);
 
362
            }
 
363
        }
 
364
    }
 
365
}
 
366
 
 
367
/** For debugging: dump the netsnmp_oid_stash tree to stdout
 
368
    @param root The top of the tree
 
369
    @param prefix a character string prefix printed to the beginning of each line.
 
370
*/
 
371
void 
 
372
oid_stash_dump(netsnmp_oid_stash_node *root, char *prefix)
 
373
{
 
374
    char            myprefix[MAX_OID_LEN * 4];
 
375
    netsnmp_oid_stash_node *tmpp;
 
376
    int             prefix_len = strlen(prefix) + 1;    /* actually it's +2 */
 
377
    unsigned int    i;
 
378
 
 
379
    memset(myprefix, ' ', MAX_OID_LEN * 4);
 
380
    myprefix[prefix_len] = '\0';
 
381
 
 
382
    for (i = 0; i < root->children_size; i++) {
 
383
        if (root->children[i]) {
 
384
            for (tmpp = root->children[i]; tmpp; tmpp = tmpp->next_sibling) {
 
385
                printf("%s%ld@%d: %s\n", prefix, tmpp->value, i,
 
386
                       (tmpp->thedata) ? "DATA" : "");
 
387
                oid_stash_dump(tmpp, myprefix);
 
388
            }
 
389
        }
 
390
    }
 
391
}
 
392
 
 
393
/** Frees the contents of a netsnmp_oid_stash tree.
 
394
    @param root the top of the tree (or branch to be freed)
 
395
    @param freefn The function to be called on each data (void *)
 
396
    pointer.  If left NULL the system free() function will be called
 
397
*/
 
398
void
 
399
netsnmp_oid_stash_free(netsnmp_oid_stash_node **root,
 
400
                       NetSNMPStashFreeNode *freefn) {
 
401
 
 
402
    netsnmp_oid_stash_node *curnode, *tmpp;
 
403
    unsigned int    i;
 
404
 
 
405
    if (!root || !*root)
 
406
        return;
 
407
 
 
408
    /* loop through all our children and free each node */
 
409
    for (i = 0; i < (*root)->children_size; i++) {
 
410
        if ((*root)->children[i]) {
 
411
            for(tmpp = (*root)->children[i]; tmpp; tmpp = curnode) {
 
412
                if (tmpp->thedata) {
 
413
                    if (freefn)
 
414
                        (*freefn)(tmpp->thedata);
 
415
                    else
 
416
                        free(tmpp->thedata);
 
417
                }
 
418
                curnode = tmpp->next_sibling;
 
419
                netsnmp_oid_stash_free(&tmpp, freefn);
 
420
            }
 
421
        }
 
422
    }
 
423
    free((*root)->children);
 
424
    free (*root);
 
425
    *root = NULL;
 
426
}
 
427
 
 
428
void
 
429
netsnmp_oid_stash_no_free(void *bogus)
 
430
{
 
431
    /* noop */
 
432
}
 
433
 
 
434
/** @} */