1 /* Portions of this file are subject to the following copyright(s).  See
2  * the Net-SNMP's COPYING file for more details and other copyrights
3  * that may apply:
4  */
5 /*
6  * Portions of this file are copyrighted by:
7  * Copyright (C) 2007 Apple, Inc. All rights reserved.
8  * Use is subject to license terms specified in the COPYING file
9  * distributed with the Net-SNMP package.
10  *
11  * Portions of this file are copyrighted by:
12  * Copyright (c) 2016 VMware, Inc. All rights reserved.
13  * Use is subject to license terms specified in the COPYING file
14  * distributed with the Net-SNMP package.
15  */
16 #ifndef NETSNMP_CONTAINER_H
17 #define NETSNMP_CONTAINER_H
18 
19 /*
20  * $Id$
21  *
22  * WARNING: This is a recently created file, and all of it's contents are
23  *          subject to change at any time.
24  *
25  * A basic container template. A generic way for code to store and
26  * retrieve data. Allows for interchangable storage algorithms.
27  */
28 #ifndef NET_SNMP_CONFIG_H
29 #error "Please include <net-snmp/net-snmp-config.h> before this file"
30 #endif
31 
32 #include <stdlib.h> /* free() */
33 #include <net-snmp/types.h>
34 #include <net-snmp/library/factory.h>
35 #include <net-snmp/library/snmp_logging.h>
36 #include <net-snmp/library/tools.h>
37 
38 #ifdef  __cplusplus
39 extern "C" {
40 #endif
41 
42     /*************************************************************************
43      *
44      * function pointer definitions
45      *
46      *************************************************************************/
47     struct netsnmp_iterator_s; /** forward declare */
48     struct netsnmp_container_s; /** forward declare */
49 
50     /*
51      * function for performing an operation on a container which
52      * returns (maybe the same) container.
53      */
54     typedef struct netsnmp_container_s* (netsnmp_container_mod_op)
55         (struct netsnmp_container_s *, void *context, u_int flags);
56 
57     /*
58      * function for setting an option on a container
59      */
60     typedef int (netsnmp_container_option)(struct netsnmp_container_s *,
61                                            int set, u_int flags);
62 
63     /*
64      * function returning an int for an operation on a container
65      */
66     typedef int (netsnmp_container_rc)(struct netsnmp_container_s *);
67 
68     /*
69      * function returning an iterator for a container
70      */
71     typedef struct netsnmp_iterator_s * (netsnmp_container_it)
72         (struct netsnmp_container_s *);
73 
74     /*
75      * function returning a size_t for an operation on a container
76      */
77     typedef size_t (netsnmp_container_size)(struct netsnmp_container_s *);
78 
79     /*
80      * function returning an int for an operation on an object and
81      * a container
82      */
83     typedef int (netsnmp_container_op)(struct netsnmp_container_s *,
84                                        const void *data);
85 
86     /*
87      * function returning an int for an operation on an object at a given
88      * position in a container (for containers supporting direct access)
89      */
90     typedef int (netsnmp_container_da_op)(struct netsnmp_container_s *,
91                                           size_t pos, void *data);
92 
93     /*
94      * function returning an int and an object at a given position in a
95      * container (for containers supporting direct access)
96      */
97     typedef int (netsnmp_container_da_op_rtn)(struct netsnmp_container_s *,
98                                           size_t pos,
99                                           void **data);
100 
101     /*
102      * function returning an oject for an operation on an object and a
103      * container
104      */
105     typedef void * (netsnmp_container_rtn)(struct netsnmp_container_s *,
106                                            const void *data);
107 
108     /*
109      * function with no return which acts on an object
110      */
111     typedef void (netsnmp_container_obj_func)(void *data, void *context);
112 
113     /*
114      * function with no return which calls a function on an object
115      */
116     typedef void (netsnmp_container_func)(struct netsnmp_container_s *,
117                                           netsnmp_container_obj_func *,
118                                           void *context);
119 
120     /*
121      * function returning an array of objects for an operation on an
122      * ojbect and a container
123      */
124     typedef netsnmp_void_array * (netsnmp_container_set)
125         (struct netsnmp_container_s *, void *data);
126 
127     /*
128      * function returning an int for a comparison between two objects
129      */
130     typedef int (netsnmp_container_compare)(const void *lhs,
131                                             const void *rhs);
132 
133     /*************************************************************************
134      *
135      * Basic container
136      *
137      *************************************************************************/
138     typedef struct netsnmp_container_s {
139 
140        /*
141         * pointer for container implementation
142         */
143        void *         container_data;
144 
145        /*
146         * returns the number of items in a container
147         */
148        netsnmp_container_size  *get_size;
149 
150        /*
151         * initialize a container
152         */
153        netsnmp_container_rc    *init;
154 
155        /*
156         * release memory used by a container.
157         *
158         * Note: if your data structures contained allocated
159         * memory, you are responsible for releasing that
160         * memory before calling this function!
161         */
162        netsnmp_container_rc    *cfree;
163 
164        /*
165         * add an entry to the container
166         */
167        netsnmp_container_op    *insert;
168 
169        /*
170         * add an entry to the container at a given position
171         */
172        netsnmp_container_da_op *insert_before;
173        netsnmp_container_da_op *insert_after;
174 
175        /*
176         * remove an entry from the container
177         */
178        netsnmp_container_op    *remove;
179 
180        /*
181         * remove an entry from the container at a given position
182         */
183        netsnmp_container_da_op_rtn *remove_at;
184 
185        /*
186         * release memory for an entry from the container
187         */
188        netsnmp_container_op    *release; /* NOTE: deprecated. Use free_item */
189        netsnmp_container_obj_func *free_item;
190 
191        /*
192         * find the entry in the container with the same key
193         *
194         * Note: do not change the key!  If you need to
195         * change a key, remove the entry, change the key,
196         * and the re-add the entry.
197         */
198        netsnmp_container_rtn   *find;
199 
200        /*
201         * find the entry in the container with the next highest key
202         *
203         * If the key is NULL, return the first item in the container.
204         */
205        netsnmp_container_rtn   *find_next;
206 
207        /*
208         * get entry at the given index (for containers supporting direct access
209         */
210        netsnmp_container_da_op_rtn *get_at;
211 
212        /*
213         * find all entries in the container which match the partial key
214         * returns allocated memory (netsnmp_void_array). User is responsible
215         * for releasing this memory (free(array->array), free(array)).
216         * DO NOT FREE ELEMENTS OF THE ARRAY, because they are the same pointers
217         * stored in the container.
218         */
219        netsnmp_container_set            *get_subset;
220 
221        /*
222         * function to return an iterator for the container
223         */
224        netsnmp_container_it           *get_iterator;
225 
226        /*
227         * function to call another function for each object in the container
228         */
229        netsnmp_container_func         *for_each;
230 
231        /*
232         * specialized version of for_each used to optimize cleanup.
233         * clear the container, optionally calling a function for each item.
234         */
235        netsnmp_container_func         *clear;
236 
237        /*
238         * OPTIONAL function to filter inserts to the container
239         *  (intended for a secondary container, which only wants
240         *   a sub-set of the objects in the primary/parent container)
241         * Returns:
242         *   1 : filter matched (don't insert)
243         *   0 : no match (insert)
244         */
245        netsnmp_container_op    *insert_filter;
246 
247         /*
248          * OPTIONAL function to duplicate a container. Defaults to a shallow
249          * copy. Only the specified container is copied (i.e. sub-containers
250          * not included).
251          */
252         netsnmp_container_mod_op *duplicate;
253 
254 
255        /*
256         * function to compare two object stored in the container.
257         *
258         * Returns:
259         *
260         *   -1  LHS < RHS
261         *    0  LHS = RHS
262         *    1  LHS > RHS
263         */
264        netsnmp_container_compare        *compare;
265 
266        /*
267         * same as compare, but RHS will be a partial key
268         */
269        netsnmp_container_compare        *ncompare;
270 
271        /*
272         * function to set container options
273         */
274        netsnmp_container_option         *options;
275 
276        /*
277         * unique name for finding a particular container in a list
278         */
279        char *container_name;
280 
281        /*
282         * sort count, for iterators to track (insert/delete
283         * bumps counter, invalidates iterator)
284         */
285        u_long                          sync;
286 
287        /*
288         * flags
289         */
290        u_int                           flags;
291 
292        /*
293         * containers can contain other containers (additional indexes)
294         */
295        struct netsnmp_container_s *next, *prev;
296 
297     } netsnmp_container;
298 
299     /*
300      * initialize/free a container of container factories. used by
301      * netsnmp_container_find* functions.
302      */
303     NETSNMP_IMPORT
304     void netsnmp_container_init_list(void);
305     NETSNMP_IMPORT
306     void netsnmp_container_free_list(void);
307 
308     /*
309      * register a new container factory
310      */
311     int netsnmp_container_register_with_compare(const char* name,
312                                                 netsnmp_factory *f,
313                                                 netsnmp_container_compare *c);
314     int netsnmp_container_register(const char* name, netsnmp_factory *f);
315 
316     /*
317      * search for and create a container from a list of types or a
318      * specific type.
319      */
320     NETSNMP_IMPORT
321     netsnmp_container * netsnmp_container_find(const char *type_list);
322     netsnmp_container * netsnmp_container_get(const char *type);
323 
324     /*
325      * utility routines
326      */
327     NETSNMP_IMPORT
328     void netsnmp_container_add_index(netsnmp_container *primary,
329                                      netsnmp_container *new_index);
330 
331 
332     netsnmp_factory *netsnmp_container_get_factory(const char *type);
333 
334     /*
335      * common comparison routines
336      */
337     /** first data element is a 'netsnmp_index' */
338     NETSNMP_IMPORT
339     int netsnmp_compare_netsnmp_index(const void *lhs, const void *rhs);
340     NETSNMP_IMPORT
341     int netsnmp_ncompare_netsnmp_index(const void *lhs, const void *rhs);
342 
343     /** first data element is a 'char *' */
344     int netsnmp_compare_cstring(const void * lhs, const void * rhs);
345     int netsnmp_ncompare_cstring(const void * lhs, const void * rhs);
346 
347     /** useful for octet strings */
348     NETSNMP_IMPORT
349     int netsnmp_compare_mem(const char * lhs, size_t lhs_len,
350                             const char * rhs, size_t rhs_len);
351 
352     /** no structure, just 'char *' pointers */
353     int netsnmp_compare_direct_cstring(const void * lhs, const void * rhs);
354 
355     int netsnmp_compare_long(const void * lhs, const void * rhs);
356     int netsnmp_compare_ulong(const void * lhs, const void * rhs);
357     int netsnmp_compare_int32(const void * lhs, const void * rhs);
358     int netsnmp_compare_uint32(const void * lhs, const void * rhs);
359 
360     /** for_each callback to call free on data item */
361     NETSNMP_IMPORT
362     void  netsnmp_container_simple_free(void *data, void *context);
363 
364 /*
365  * container optionflags
366  */
367 #define CONTAINER_KEY_ALLOW_DUPLICATES             0x00000001
368 #define CONTAINER_KEY_UNSORTED                     0x00000002
369     /* ... */
370 #define CONTAINER_FLAG_INTERNAL_1                  0x80000000
371 
372 #define CONTAINER_SET_OPTIONS(x,o,rc)  do {                             \
373         if (NULL==(x)->options)                                         \
374             rc = -1;                                                    \
375         else {                                                          \
376             rc = (x)->options(x, 1, o);                                 \
377             if (rc != -1 )                                              \
378                 (x)->flags |= o;                                        \
379         }                                                               \
380     } while(0)
381 
382 #define CONTAINER_CHECK_OPTION(x,o,rc)    do {                          \
383         rc = x->flags & 0;                                              \
384     } while(0)
385 
386 
387     /*
388      * useful macros (x = container; k = key; c = user context)
389      */
390 #define CONTAINER_FIRST(x)          (x)->find_next(x,NULL)
391 #define CONTAINER_FIND(x,k)         (x)->find(x,k)
392 #define CONTAINER_NEXT(x,k)         (x)->find_next(x,k)
393 /*
394  * GET_SUBSET returns allocated memory (netsnmp_void_array). User is responsible
395  * for releasing this memory (free(array->array), free(array)).
396  * DO NOT FREE ELEMENTS OF THE ARRAY, because they are the same pointers
397  * stored in the container.
398  */
399 #define CONTAINER_GET_SUBSET(x,k)   (x)->get_subset(x,k)
400 #define CONTAINER_SIZE(x)           (x)->get_size(x)
401 #define CONTAINER_ITERATOR(x)       (x)->get_iterator(x)
402 #define CONTAINER_COMPARE(x,l,r)    (x)->compare(l,r)
403 #define CONTAINER_FOR_EACH(x,f,c)   (x)->for_each(x,f,c)
404 
405     /*
406      * if you are getting multiple definitions of these three
407      * inline functions, you most likely have optimizations turned off.
408      * Either turn them back on, or define NETSNMP_NO_INLINE
409      */
410     /*
411      * insert k into all containers
412      */
413     NETSNMP_IMPORT
414     int CONTAINER_INSERT(netsnmp_container *x, const void *k);
415 
416     /*
417      * insert item before given position
418      */
419     NETSNMP_IMPORT
420     int CONTAINER_INSERT_BEFORE(netsnmp_container *x, size_t pos, void *k);
421 
422     /*
423      * remove k from all containers
424      */
425     NETSNMP_IMPORT
426     int CONTAINER_REMOVE(netsnmp_container *x, const void *k);
427 
428     /*
429      * remove item at given position
430      */
431     NETSNMP_IMPORT
432     int CONTAINER_REMOVE_AT(netsnmp_container *x, size_t pos, void **k);
433 
434     /*
435      * get item at given position
436      */
437     NETSNMP_IMPORT
438     int CONTAINER_GET_AT(netsnmp_container *x, size_t pos, void **k);
439 
440     /*
441      * duplicate container
442      */
443     NETSNMP_IMPORT
444     netsnmp_container *CONTAINER_DUP(netsnmp_container *x, void *ctx,
445                                      u_int flags);
446 
447     /*
448      * clear all containers. When clearing the *first* container, and
449      * *only* the first container, call the function f for each item.
450      * After calling this function, all containers should be empty.
451      */
452     NETSNMP_IMPORT
453     void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f,
454                         void *c);
455 
456     /*
457      * clear all containers. When clearing the *first* container, and
458      * *only* the first container, call the free_item function for each item.
459      * After calling this function, all containers should be empty.
460      */
461     NETSNMP_IMPORT
462     void CONTAINER_FREE_ALL(netsnmp_container *x, void *c);
463 
464     /*
465      * free all containers
466      */
467     NETSNMP_IMPORT
468     int CONTAINER_FREE(netsnmp_container *x);
469 
470     NETSNMP_IMPORT
471     netsnmp_container *SUBCONTAINER_FIND(netsnmp_container *x,
472                                          const char* name);
473 
474     /*
475      * INTERNAL utility routines for container implementations
476      */
477     void netsnmp_init_container(netsnmp_container         *c,
478                                 netsnmp_container_rc      *init,
479                                 netsnmp_container_rc      *cfree,
480                                 netsnmp_container_size    *size,
481                                 netsnmp_container_compare *cmp,
482                                 netsnmp_container_op      *ins,
483                                 netsnmp_container_op      *rem,
484                                 netsnmp_container_rtn     *fnd);
485     /** Duplicate container meta-data. */
486     int netsnmp_container_data_dup(netsnmp_container *dup,
487                                    netsnmp_container *c);
488 
489 
490     /*************************************************************************
491      *
492      * container iterator
493      *
494      *************************************************************************/
495     /*
496      * function returning an int for an operation on an iterator
497      */
498     typedef int (netsnmp_iterator_rc)(struct netsnmp_iterator_s *);
499 
500     /*
501      * function returning an oject for an operation on an iterator
502      */
503     typedef void * (netsnmp_iterator_rtn)(struct netsnmp_iterator_s *);
504 
505 
506     /*
507      * iterator structure
508      */
509     typedef struct netsnmp_iterator_s {
510 
511        netsnmp_container              *container;
512 
513         /*
514          * sync from container when iterator created. used to invalidate
515          * the iterator when the container changes.
516          */
517        u_long                          sync;
518 
519         /*
520          * reset iterator position to beginning of container.
521          */
522        netsnmp_iterator_rc           *reset;
523 
524         /*
525          * release iterator and memory it uses
526          */
527        netsnmp_iterator_rc           *release;
528 
529         /*
530          * first, last and current DO NOT advance the iterator
531          */
532        netsnmp_iterator_rtn          *first;
533        netsnmp_iterator_rtn          *curr;
534        netsnmp_iterator_rtn          *last;
535 
536        netsnmp_iterator_rtn          *next;
537 
538         /*
539          * remove will remove the item at the current position, then back up
540          * the iterator to the previous item. That way next will move to the
541          * item (the one that replaced the removed item.
542          */
543        netsnmp_iterator_rc           *remove;
544 
545     } netsnmp_iterator;
546 
547 
548 #define ITERATOR_FIRST(x)  x->first(x)
549 #define ITERATOR_NEXT(x)   x->next(x)
550 #define ITERATOR_LAST(x)   x->last(x)
551 #define ITERATOR_REMOVE(x) x->remove(x)
552 #define ITERATOR_RELEASE(x) do { x->release(x); x = NULL; } while(0)
553 
554 #ifdef  __cplusplus
555 }
556 #endif
557 
558 #endif /** NETSNMP_CONTAINER_H */
559