Coverage Report

Created: 2026-04-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/container_list_ssll.c
Line
Count
Source
1
/*
2
 * container_list_sl.c
3
 * $Id$
4
 *
5
 */
6
#include <net-snmp/net-snmp-config.h>
7
#include <net-snmp/net-snmp-features.h>
8
9
#include <stdio.h>
10
#ifdef HAVE_STDLIB_H
11
#include <stdlib.h>
12
#endif
13
#ifdef HAVE_MALLOC_H
14
#include <malloc.h>
15
#endif
16
#include <sys/types.h>
17
#ifdef HAVE_STRING_H
18
#include <string.h>
19
#else
20
#include <strings.h>
21
#endif
22
23
#include <net-snmp/net-snmp-includes.h>
24
#include <net-snmp/types.h>
25
#include <net-snmp/library/snmp_api.h>
26
#include <net-snmp/library/container.h>
27
#include <net-snmp/library/tools.h>
28
#include <net-snmp/library/snmp_assert.h>
29
30
#include <net-snmp/library/container_list_ssll.h>
31
#include "factory.h"
32
33
netsnmp_feature_child_of(container_linked_list, container_types);
34
netsnmp_feature_child_of(container_fifo, container_types);
35
netsnmp_feature_child_of(container_lifo, container_types);
36
37
/* this is a fancy way of cleaning up ifdefs */
38
#ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_FIFO
39
netsnmp_feature_require(container_linked_list);
40
#endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_FIFO */
41
#ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_LIFO
42
netsnmp_feature_require(container_linked_list);
43
#endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_LIFO */
44
45
#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST
46
typedef struct sl_node {
47
   void           *data;
48
   struct sl_node *next;
49
} sl_node;
50
51
typedef struct sl_container_s {
52
   netsnmp_container          c;
53
   
54
   size_t                     count;      /* Index of the next free entry */
55
   sl_node                   *head;       /* head of list */
56
57
   int                        unsorted;   /* unsorted list? */
58
   int                        fifo;       /* lifo or fifo? */
59
60
} sl_container;
61
62
typedef struct ssll_iterator_s {
63
    netsnmp_iterator base;
64
 
65
    sl_node         *pos;
66
    sl_node         *last;
67
} ssll_iterator;
68
69
static netsnmp_iterator *_ssll_iterator_get(netsnmp_container *c);
70
71
72
static void *
73
_get(netsnmp_container *c, const void *key, int return_next)
74
0
{
75
0
    sl_container *sl = (sl_container *)c;
76
0
    sl_node *curr = sl->head;
77
0
    int rc = 0;
78
79
    /* If the key is NULL, return the first item in the container. */
80
0
    if (!key)
81
0
        return curr ? curr->data : NULL;
82
83
0
    for ( ; curr; curr = curr->next) {
84
0
        rc = sl->c.compare(curr->data, key);
85
0
        if (rc < 0)
86
0
            continue;
87
0
        if (rc == 0) {
88
0
            if (return_next)
89
0
                curr = curr->next;
90
0
            break;
91
0
        }
92
0
        if (!sl->unsorted) {
93
            /* If sorted, we can stop. */
94
0
            if (!return_next)
95
0
                curr = NULL;
96
0
            break;
97
0
        }
98
0
    }
99
100
0
    return curr ? curr->data : NULL;
101
0
}
102
103
/**********************************************************************
104
 *
105
 *
106
 *
107
 **********************************************************************/
108
static int
109
_ssll_free(netsnmp_container *c)
110
3.46k
{
111
3.46k
    if(c) {
112
3.46k
        free(c);
113
3.46k
    }
114
3.46k
    return 0;
115
3.46k
}
116
117
static void *
118
_ssll_find(netsnmp_container *c, const void *data)
119
0
{
120
0
    if((NULL == c) || (NULL == data))
121
0
        return NULL;
122
123
0
    return _get(c, data, 0);
124
0
}
125
126
static void *
127
_ssll_find_next(netsnmp_container *c, const void *data)
128
0
{
129
0
    if(NULL == c)
130
0
        return NULL;
131
132
0
    return _get(c, data, 1);
133
0
}
134
135
static int
136
_ssll_insert(netsnmp_container *c, const void *data)
137
167
{
138
167
    sl_container *sl = (sl_container*)c;
139
167
    sl_node  *new_node, *curr;
140
    
141
167
    if (c == NULL)
142
0
        return -1;
143
144
167
    curr = sl->head;
145
146
167
    new_node = SNMP_MALLOC_TYPEDEF(sl_node);
147
167
    if (new_node == NULL)
148
0
        return -1;
149
167
    new_node->data = NETSNMP_REMOVE_CONST(void *, data);
150
167
    ++sl->count;
151
167
    ++c->sync;
152
153
    /*
154
     * first node?
155
     */
156
167
    if(NULL == sl->head) {
157
16
        sl->head = new_node;
158
16
        return 0;
159
16
    }
160
161
    /*
162
     * sorted or unsorted insert?
163
     */
164
151
    if (1 == sl->unsorted) {
165
        /*
166
         * unsorted: fifo, or lifo?
167
         */
168
151
        if (1 == sl->fifo) {
169
            /*
170
             * fifo: insert at tail
171
             */
172
3.46k
            while(NULL != curr->next)
173
3.31k
                curr = curr->next;
174
151
            curr->next = new_node;
175
151
        }
176
0
        else {
177
            /*
178
             * lifo: insert at head
179
             */
180
0
            new_node->next = sl->head;
181
0
            sl->head = new_node;
182
0
        }
183
151
    }
184
0
    else {
185
        /*
186
         * sorted
187
         */
188
0
        sl_node *last = NULL;
189
0
        for( ; curr; last = curr, curr = curr->next) {
190
0
            if(sl->c.compare(curr->data, data) > 0)
191
0
                break;
192
0
        }
193
0
        if(NULL == last) {
194
0
            new_node->next = sl->head;
195
0
            sl->head = new_node;
196
0
        }
197
0
        else {
198
0
            new_node->next = last->next;
199
0
            last->next = new_node;
200
0
        }
201
0
    }
202
    
203
151
    return 0;
204
167
}
205
206
static int
207
_ssll_remove(netsnmp_container *c, const void *data)
208
0
{
209
0
    sl_container *sl = (sl_container*)c;
210
0
    sl_node  *curr;
211
    
212
0
    if (c == NULL)
213
0
        return -1;
214
215
0
    curr = sl->head;
216
0
    if (curr == NULL)
217
0
        return -1;
218
219
    /*
220
     * special case for NULL data, act like stack
221
     */
222
0
    if ((NULL == data) ||
223
0
        (sl->c.compare(sl->head->data, data) == 0)) {
224
0
        curr = sl->head;
225
0
        sl->head = sl->head->next;
226
0
    }
227
0
    else {
228
0
        sl_node *last = sl->head;
229
0
        int rc;
230
0
        for(curr = sl->head->next ; curr; last = curr, curr = curr->next) {
231
0
            rc = sl->c.compare(curr->data, data);
232
0
            if (rc == 0) {
233
0
                last->next = curr->next;
234
0
                break;
235
0
            }
236
0
            else if ((rc > 0) && (0 == sl->unsorted)) {
237
                /*
238
                 * if sorted and rc > 0, didn't find entry
239
                 */
240
0
                curr = NULL;
241
0
                break;
242
0
            }
243
0
        }
244
0
    }
245
246
0
    if(NULL == curr)
247
0
        return -2;
248
    
249
    /*
250
     * free our node structure, but not the data
251
     */
252
0
    free(curr);
253
0
    --sl->count;
254
0
    ++c->sync;
255
    
256
0
    return 0;
257
0
}
258
259
static size_t
260
_ssll_size(netsnmp_container *c)
261
0
{
262
0
    sl_container *sl = (sl_container*)c;
263
    
264
0
    if(NULL == c)
265
0
        return 0;
266
267
0
    return sl->count;
268
0
}
269
270
static void
271
_ssll_for_each(netsnmp_container *c, netsnmp_container_obj_func *f,
272
             void *context)
273
0
{
274
0
    sl_container *sl = (sl_container*)c;
275
0
    sl_node  *curr;
276
    
277
0
    if(NULL == c)
278
0
        return;
279
    
280
0
    for(curr = sl->head; curr; curr = curr->next)
281
0
        (*f) ((void *)curr->data, context);
282
0
}
283
284
static void
285
_ssll_clear(netsnmp_container *c, netsnmp_container_obj_func *f,
286
             void *context)
287
3.46k
{
288
3.46k
    sl_container *sl = (sl_container*)c;
289
3.46k
    sl_node  *curr, *next;
290
    
291
3.46k
    if(NULL == c)
292
0
        return;
293
    
294
3.55k
    for(curr = sl->head; curr; curr = next) {
295
296
94
        next = curr->next;
297
298
94
        if( NULL != f ) {
299
94
            curr->next = NULL;
300
94
            (*f) ((void *)curr->data, context);
301
94
        }
302
303
        /*
304
         * free our node structure, but not the data
305
         */
306
94
        free(curr);
307
94
    }
308
3.46k
    sl->head = NULL;
309
3.46k
    sl->count = 0;
310
3.46k
    ++c->sync;
311
3.46k
}
312
313
static netsnmp_container *netsnmp_container_get_ssll(void);
314
315
static netsnmp_container *
316
_ssll_duplicate(netsnmp_container *c, void *ctx, u_int flags)
317
0
{
318
0
    netsnmp_transport_config *item;
319
0
    netsnmp_container *dup;
320
0
    netsnmp_iterator *iter;
321
322
0
    if (flags) {
323
0
        snmp_log(LOG_ERR, "%s does not support flags yet\n", __func__);
324
0
        return NULL;
325
0
    }
326
327
0
    dup = netsnmp_container_get_ssll();
328
0
    if (!dup) {
329
0
        snmp_log(LOG_ERR, "%s: out of memory\n", __func__);
330
0
        return NULL;
331
0
    }
332
333
    /*
334
     * deal with container stuff
335
     */
336
0
    if (netsnmp_container_data_dup(dup, c) != 0)
337
0
        goto fail;
338
339
    /* deep copy */
340
0
    iter = CONTAINER_ITERATOR(c);
341
0
    for (item = ITERATOR_FIRST(iter); item; item = ITERATOR_NEXT(iter))
342
0
        CONTAINER_INSERT(dup, netsnmp_transport_create_config(item->key,
343
0
                                                              item->value));
344
0
    ITERATOR_RELEASE(iter);
345
346
0
    return dup;
347
348
0
fail:
349
0
    _ssll_free(dup);
350
0
    return NULL;
351
0
}
352
353
354
/**********************************************************************
355
 *
356
 *
357
 *
358
 **********************************************************************/
359
static netsnmp_container *
360
netsnmp_container_get_ssll(void)
361
3.46k
{
362
    /*
363
     * allocate memory
364
     */
365
3.46k
    sl_container *sl = SNMP_MALLOC_TYPEDEF(sl_container);
366
3.46k
    if (NULL==sl) {
367
0
        snmp_log(LOG_ERR, "couldn't allocate memory\n");
368
0
        return NULL;
369
0
    }
370
371
3.46k
    netsnmp_init_container((netsnmp_container *)sl, NULL, _ssll_free,
372
3.46k
                           _ssll_size, NULL, _ssll_insert, _ssll_remove,
373
3.46k
                           _ssll_find);
374
3.46k
    sl->c.find_next = _ssll_find_next;
375
3.46k
    sl->c.get_subset = NULL;
376
3.46k
    sl->c.get_iterator =_ssll_iterator_get;
377
3.46k
    sl->c.for_each = _ssll_for_each;
378
3.46k
    sl->c.clear = _ssll_clear;
379
3.46k
    sl->c.duplicate = _ssll_duplicate;
380
381
3.46k
    return &sl->c;
382
3.46k
}
383
384
netsnmp_container *
385
netsnmp_container_get_usll(void)
386
3.46k
{
387
    /*
388
     * allocate memory
389
     */
390
3.46k
    sl_container *sl = (sl_container *)netsnmp_container_get_ssll();
391
3.46k
    if (NULL==sl)
392
0
        return NULL; /* msg already logged */
393
394
3.46k
    sl->unsorted = 1;
395
396
3.46k
    return (netsnmp_container*)sl;
397
3.46k
}
398
399
netsnmp_container *
400
netsnmp_container_get_singly_linked_list(int fifo)
401
3.46k
{
402
3.46k
    sl_container *sl = (sl_container *)netsnmp_container_get_usll();
403
3.46k
    if (NULL == sl)
404
0
        return NULL; /* error already logged */
405
406
3.46k
    sl->fifo = fifo;
407
408
3.46k
    return (netsnmp_container *)sl;
409
3.46k
}
410
411
netsnmp_container *
412
netsnmp_container_get_fifo(void)
413
3.46k
{
414
3.46k
    return netsnmp_container_get_singly_linked_list(1);
415
3.46k
}
416
417
void
418
netsnmp_container_ssll_init(void)
419
3.44k
{
420
3.44k
    static netsnmp_factory ssll = {
421
3.44k
        "sorted_singly_linked_list",
422
3.44k
        netsnmp_container_get_ssll
423
3.44k
    };
424
3.44k
    static netsnmp_factory usll = {
425
3.44k
        "unsorted_singly_linked_list-lifo",
426
3.44k
        netsnmp_container_get_usll
427
3.44k
    };
428
3.44k
    static netsnmp_factory fifo = {
429
3.44k
        "unsorted_singly_linked_list-fifo",
430
3.44k
        netsnmp_container_get_fifo
431
3.44k
    };
432
433
3.44k
    netsnmp_container_register("sorted_singly_linked_list", &ssll);
434
3.44k
    netsnmp_container_register("unsorted_singly_linked_list", &usll);
435
3.44k
    netsnmp_container_register("lifo", &usll);
436
3.44k
    netsnmp_container_register("fifo", &fifo);
437
3.44k
}
438
439
440
/**********************************************************************
441
 *
442
 * iterator
443
 *
444
 */
445
NETSNMP_STATIC_INLINE sl_container *
446
_ssll_it2cont(ssll_iterator *it)
447
0
{
448
0
    if(NULL == it) {
449
0
        netsnmp_assert(NULL != it);
450
0
        return NULL;
451
0
    }
452
453
0
    if(NULL == it->base.container) {
454
0
        netsnmp_assert(NULL != it->base.container);
455
0
        return NULL;
456
0
    }
457
458
0
    if(it->base.container->sync != it->base.sync) {
459
0
        DEBUGMSGTL(("container:iterator", "out of sync\n"));
460
0
        return NULL;
461
0
    }
462
463
0
    return (sl_container *)it->base.container;
464
0
}
465
466
static void *
467
_ssll_iterator_curr(netsnmp_iterator *p)
468
0
{
469
0
    ssll_iterator *it = (void *)p;
470
0
    sl_container *t = _ssll_it2cont(it);
471
0
    if ((NULL == t) || (NULL == it->pos))
472
0
        return NULL;
473
474
0
    return it->pos->data;
475
0
}
476
477
static void *
478
_ssll_iterator_first(netsnmp_iterator *p)
479
0
{
480
0
    ssll_iterator *it = (void *)p;
481
0
    sl_container *t = _ssll_it2cont(it);
482
0
    if ((NULL == t) || (NULL == t->head))
483
0
        return NULL;
484
485
0
    return t->head->data;
486
0
}
487
488
static void *
489
_ssll_iterator_next(netsnmp_iterator *p)
490
0
{
491
0
    ssll_iterator *it = (void *)p;
492
0
    sl_container *t = _ssll_it2cont(it);
493
0
    if ((NULL == t) || (NULL == it->pos))
494
0
        return NULL;
495
496
0
    it->pos = it->pos->next;
497
0
    if (NULL == it->pos)
498
0
        return NULL;
499
500
0
    return it->pos->data;
501
0
}
502
503
static void *
504
_ssll_iterator_last(netsnmp_iterator *p)
505
0
{
506
0
    ssll_iterator *it = (void *)p;
507
0
    sl_node      *n;
508
0
    sl_container *t = _ssll_it2cont(it);
509
0
    if(NULL == t)
510
0
        return NULL;
511
    
512
0
    if (it->last)
513
0
        return it->last;
514
515
0
    n = it->pos ? it->pos : t->head;
516
0
    if (NULL == n)
517
0
        return NULL;
518
519
0
    while (n->next)
520
0
        n = n->next;
521
522
0
    it->last = n;
523
524
0
    return it->last->data;
525
0
}
526
527
static int
528
_ssll_iterator_reset(netsnmp_iterator *p)
529
0
{
530
0
    ssll_iterator *it = (void *)p;
531
0
    sl_container *t;
532
533
    /** can't use it2conf cuz we might be out of sync */
534
0
    if(NULL == it) {
535
0
        netsnmp_assert(NULL != it);
536
0
        return 0;
537
0
    }
538
539
0
    if(NULL == it->base.container) {
540
0
        netsnmp_assert(NULL != it->base.container);
541
0
        return 0;
542
0
    }
543
0
    t = (sl_container *)it->base.container;
544
0
    if(NULL == t)
545
0
        return -1;
546
547
0
    it->last = NULL;
548
0
    it->pos = t->head;
549
550
    /*
551
     * save sync count, to make sure container doesn't change while
552
     * iterator is in use.
553
     */
554
0
    it->base.sync = it->base.container->sync;
555
556
0
    return 0;
557
0
}
558
559
static int
560
_ssll_iterator_release(netsnmp_iterator *it)
561
0
{
562
0
    free(it);
563
564
0
    return 0;
565
0
}
566
567
static netsnmp_iterator *
568
_ssll_iterator_get(netsnmp_container *c)
569
0
{
570
0
    ssll_iterator* it;
571
572
0
    if(NULL == c)
573
0
        return NULL;
574
575
0
    it = SNMP_MALLOC_TYPEDEF(ssll_iterator);
576
0
    if(NULL == it)
577
0
        return NULL;
578
579
0
    it->base.container = c;
580
    
581
0
    it->base.first = _ssll_iterator_first;
582
0
    it->base.next = _ssll_iterator_next;
583
0
    it->base.curr = _ssll_iterator_curr;
584
0
    it->base.last = _ssll_iterator_last;
585
0
    it->base.reset = _ssll_iterator_reset;
586
0
    it->base.release = _ssll_iterator_release;
587
588
0
    (void)_ssll_iterator_reset(&it->base);
589
590
0
    return &it->base;
591
0
}
592
#else /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */
593
netsnmp_feature_unused(container_linked_list);
594
#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */