Bug Summary

File:plugins/epan/mate/mate_util.c
Warning:line 143, column 9
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate_util.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-20/lib/clang/20 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D PLUGIN_VERSION="1.0.1" -D WS_DEBUG -D WS_DEBUG_UTF_8 -D mate_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/plugins/epan/mate -I /builds/wireshark/wireshark/build/plugins/epan/mate -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-09-10-100354-3933-1 -x c /builds/wireshark/wireshark/plugins/epan/mate/mate_util.c
1/* mate_util.c
2 * MATE -- Meta Analysis Tracing Engine
3 * Utility Library: Single Copy Strings and Attribute Value Pairs
4 *
5 * Copyright 2004, Luis E. Garcia Ontanon <[email protected]>
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <[email protected]>
9 * Copyright 1998 Gerald Combs
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
14#include "config.h"
15
16#include "mate.h"
17#include "mate_util.h"
18
19#include <errno(*__errno_location ()).h>
20#include <wsutil/file_util.h>
21
22
23/***************************************************************************
24* dbg_print
25***************************************************************************
26* This is the debug facility of the thing.
27***************************************************************************/
28
29/* dbg_print:
30 * which: a pointer to the current level of debugging for a feature
31 * how: the level over which this message should be printed out
32 * where: the file on which to print (ws_message if null)
33 * fmt, ...: what to print
34 */
35
36void dbg_print(const int* which, int how, FILE* where, const char* fmt, ... ) {
37 static char debug_buffer[DEBUG_BUFFER_SIZE4096];
38 va_list list;
39
40 if ( ! which || *which < how ) return;
41
42 va_start( list, fmt )__builtin_va_start(list, fmt);
43 vsnprintf(debug_buffer,DEBUG_BUFFER_SIZE4096,fmt,list);
44 va_end( list )__builtin_va_end(list);
45
46 if (! where) {
47 ws_message("%s", debug_buffer)do { if (1) { ws_log_full("MATE", LOG_LEVEL_MESSAGE, ((void*)
0), -1, ((void*)0), "%s", debug_buffer); } } while (0)
;
48 } else {
49 fputs(debug_buffer,where);
50 fputs("\n",where);
51 }
52
53}
54
55/***************************************************************************
56 * single copy strings
57 ***************************************************************************
58 * Strings repeat more often than don't. In order to save memory
59 * we'll keep only one copy of each as key to a hash with a count of
60 * subscribers as value. Each string is truncated to be no more than
61 * SCS_HUGE_SIZE.
62 * XXX - GLib 2.58 adds reference counted strings, use that?
63 ***************************************************************************/
64
65/**
66 * scs_init:
67 *
68 * Initializes the scs hash.
69 **/
70
71struct _scs_collection {
72 GHashTable* hash; /* key: a string value: unsigned number of subscribers */
73};
74
75/*
76 * XXX: AFAIKT destroy_scs_collection() might be called only when reading a
77 * mate config file. Since reading a new config file can apparently currently
78 * only be done once after starting Wireshark, in theory this fcn
79 * currently should never be called since there will never be an existing
80 * scs_collection to be destroyed.
81 */
82static void destroy_scs_collection(SCS_collection* c) {
83 if (c->hash) g_hash_table_destroy(c->hash);
84}
85
86/* The same djb2 hash used in g_str_hash, except that it stops after
87 * SCS_HUGE_SIZE bytes. */
88static unsigned scs_hash(const void *v)
89{
90 const signed char *p;
91 uint32_t h = 5381;
92 size_t i = 0;
93
94 for (p = v; *p != '\0' && i++ < SCS_HUGE_SIZE65535; p++) {
95 h = (h << 5) + h + *p;
96 }
97
98 return h;
99}
100
101/* Compare the first SCS_HUGE_SIZE bytes for equality. */
102static gboolean scs_equal(const void *a, const void *b)
103{
104 const char *str1 = a;
105 const char *str2 = b;
106
107 return strncmp(str1, str2, SCS_HUGE_SIZE65535) == 0;
108}
109
110static SCS_collection* scs_init(void) {
111 SCS_collection* c = g_new(SCS_collection, 1)((SCS_collection *) g_malloc_n ((1), sizeof (SCS_collection))
)
;
112
113 c->hash = g_hash_table_new_full(scs_hash, scs_equal, g_free, g_free);
114
115 return c;
116}
117
118
119/**
120 * subscribe:
121 * @param c the scs hash
122 * @param s a string
123 *
124 * Checks if the given string exists already and if so it increases the count of
125 * subsscribers and returns a pointer to the stored string. If not it will copy
126 * the given string, store it in the hash, and return the pointer to the copy.
127 * Remember, containment is handled internally, take care of your own strings.
128 *
129 * Return value: a pointer to the subscribed string.
130 **/
131char* scs_subscribe(SCS_collection* c, const char* s) {
132 char* orig = NULL((void*)0);
133 unsigned* ip = NULL((void*)0);
134 size_t len = 0;
135
136 g_hash_table_lookup_extended(c->hash,(const void *)s,(void * *)&orig,(void * *)&ip);
137
138 if (ip) {
25
Assuming 'ip' is null
26
Taking false branch
139 (*ip)++;
140 } else {
141 ip = g_new0(unsigned, 1)((unsigned *) g_malloc0_n ((1), sizeof (unsigned)));
142
143 len = strlen(s);
27
Null pointer passed to 1st parameter expecting 'nonnull'
144
145 if(G_LIKELY(len <= SCS_HUGE_SIZE)(len <= 65535)) {
146 orig = g_strdup(s)g_strdup_inline (s);
147 } else {
148 ws_warning("mate SCS: string truncated due to huge size")do { if (1) { ws_log_full("MATE", LOG_LEVEL_WARNING, "plugins/epan/mate/mate_util.c"
, 148, __func__, "mate SCS: string truncated due to huge size"
); } } while (0)
;
149 orig = g_strndup(s, SCS_HUGE_SIZE65535);
150 }
151
152 g_hash_table_insert(c->hash, orig, ip);
153 }
154
155 return orig;
156}
157
158/**
159 * unsubscribe:
160 * @param c the scs hash
161 * @param s a string.
162 *
163 * decreases the count of subscribers, if zero frees the internal copy of
164 * the string.
165 **/
166void scs_unsubscribe(SCS_collection* c, char* s) {
167 char* orig = NULL((void*)0);
168 unsigned* ip = NULL((void*)0);
169
170 if (g_hash_table_lookup_extended(c->hash,(const void *)s,(void **)&orig,(void **)&ip)) {
171 if (*ip == 0) {
172 g_hash_table_remove(c->hash,orig);
173 }
174 else {
175 (*ip)--;
176 }
177 } else {
178 ws_warning("mate SCS: not subscribed")do { if (1) { ws_log_full("MATE", LOG_LEVEL_WARNING, "plugins/epan/mate/mate_util.c"
, 178, __func__, "mate SCS: not subscribed"); } } while (0)
;
179 }
180}
181
182/**
183 * scs_subscribe_printf:
184 * @param fmt a format string ...
185 *
186 * Formats the input and subscribes it.
187 *
188 * Return value: the stored copy of the formatted string.
189 *
190 **/
191char* scs_subscribe_printf(SCS_collection* c, char* fmt, ...) {
192 va_list list;
193 char *buf, *ret;
194
195 va_start( list, fmt )__builtin_va_start(list, fmt);
196 buf = g_strdup_vprintf(fmt, list);
197 va_end( list )__builtin_va_end(list);
198
199 ret = scs_subscribe(c, buf);
200 g_free(buf);
201
202 return ret;
203}
204
205/***************************************************************************
206* AVPs & Co.
207***************************************************************************
208* The Thing operates mainly on avps, avpls and loals
209* - attribute value pairs (two strings: the name and the value and an operator)
210* - avp lists a somehow sorted list of avps
211* - loal (list of avp lists) an arbitrarily sorted list of avpls
212*
213*
214***************************************************************************/
215
216
217typedef union _any_avp_type {
218 AVP avp;
219 AVPN avpn;
220 AVPL avpl;
221 LoAL loal;
222 LoALnode loaln;
223} any_avp_type;
224
225
226static SCS_collection* avp_strings;
227
228#ifdef _AVP_DEBUGGING
229static FILE* dbg_fp;
230
231static int dbg_level;
232static int* dbg = &dbg_level;
233
234static int dbg_avp_level;
235static int* dbg_avp = &dbg_avp_level;
236
237static int dbg_avp_op_level;
238static int* dbg_avp_op = &dbg_avp_op_level;
239
240static int dbg_avpl_level;
241static int* dbg_avpl = &dbg_avpl_level;
242
243static int dbg_avpl_op_level;
244static int* dbg_avpl_op = &dbg_avpl_op_level;
245
246/**
247 * setup_avp_debug:
248 * @param fp the file in which to send debugging output.
249 * @param general a pointer to the level of debugging of facility "general"
250 * @param avp a pointer to the level of debugging of facility "avp"
251 * @param avp_op a pointer to the level of debugging of facility "avp_op"
252 * @param avpl a pointer to the level of debugging of facility "avpl"
253 * @param avpl_op a pointer to the level of debugging of facility "avpl_op"
254 *
255 * If enabled sets up the debug facilities for the avp library.
256 *
257 **/
258extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op) {
259 dbg_fp = fp;
260 dbg = general;
261 dbg_avp = avp;
262 dbg_avp_op = avp_op;
263 dbg_avpl = avpl;
264 dbg_avpl_op = avpl_op;
265}
266
267#endif /* _AVP_DEBUGGING */
268
269/**
270 * avp_init:
271 *
272 * (Re)Initializes the avp library.
273 *
274 **/
275extern void avp_init(void) {
276
277 if (avp_strings) destroy_scs_collection(avp_strings);
278 avp_strings = scs_init();
279
280}
281
282/**
283 * new_avp_from_finfo:
284 * @param name the name the avp will have.
285 * @param finfo the field_info from which to fetch the data.
286 *
287 * Creates an avp from a field_info record.
288 *
289 * Return value: a pointer to the newly created avp.
290 *
291 **/
292extern AVP* new_avp_from_finfo(const char* name, field_info* finfo) {
293 AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type)));
294 char* value;
295 char* repr;
296
297 new_avp_val->n = scs_subscribe(avp_strings, name);
298
299 repr = fvalue_to_string_repr(NULL((void*)0), finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display);
300
301 if (repr) {
302 value = scs_subscribe(avp_strings, repr);
303 wmem_free(NULL((void*)0), repr);
304#ifdef _AVP_DEBUGGING
305 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from string: %s",value);
306#endif
307 } else {
308#ifdef _AVP_DEBUGGING
309 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: a proto: %s",finfo->hfinfo->abbrev);
310#endif
311 value = scs_subscribe(avp_strings, "");
312 }
313
314 new_avp_val->v = value;
315
316 new_avp_val->o = '=';
317
318#ifdef _AVP_DEBUGGING
319 dbg_print (dbg_avp,1,dbg_fp,"new_avp_from_finfo: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v);
320#endif
321
322 return new_avp_val;
323}
324
325
326/**
327 * new_avp:
328 * @param name the name the avp will have.
329 * @param value the value the avp will have.
330 * @param o the operator of this avp.
331 *
332 * Creates an avp given every parameter.
333 *
334 * Return value: a pointer to the newly created avp.
335 *
336 **/
337extern AVP* new_avp(const char* name, const char* value, char o) {
338 AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type)));
339
340 new_avp_val->n = scs_subscribe(avp_strings, name);
341 new_avp_val->v = scs_subscribe(avp_strings, value);
342 new_avp_val->o = o;
343
344#ifdef _AVP_DEBUGGING
345 dbg_print(dbg_avp,1,dbg_fp,"new_avp_val: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v);
346#endif
347 return new_avp_val;
348}
349
350
351/**
352* delete_avp:
353 * @param avp the avp to delete.
354 *
355 * Destroys an avp and releases the resources it uses.
356 *
357 **/
358extern void delete_avp(AVP* avp) {
359#ifdef _AVP_DEBUGGING
360 dbg_print(dbg_avp,1,dbg_fp,"delete_avp: %p %s%c%s;",avp,avp->n,avp->o,avp->v);
361#endif
362
363 scs_unsubscribe(avp_strings, avp->n);
364 scs_unsubscribe(avp_strings, avp->v);
365 g_slice_free(any_avp_type,(any_avp_type*)avp)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)avp)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)avp
)); } while (0)
;
366}
367
368
369/**
370* avp_copy:
371 * @param from the avp to be copied.
372 *
373 * Creates an avp whose name op and value are copies of the given one.
374 *
375 * Return value: a pointer to the newly created avp.
376 *
377 **/
378extern AVP* avp_copy(AVP* from) {
379 AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type)));
380
381 new_avp_val->n = scs_subscribe(avp_strings, from->n);
23
Passing null pointer value via 2nd parameter 's'
24
Calling 'scs_subscribe'
382 new_avp_val->v = scs_subscribe(avp_strings, from->v);
383 new_avp_val->o = from->o;
384
385#ifdef _AVP_DEBUGGING
386 dbg_print(dbg_avp,1,dbg_fp,"copy_avp: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v);
387#endif
388
389 return new_avp_val;
390}
391
392/**
393 * new_avpl:
394 * @param name the name the avpl will have.
395 *
396 * Creates an empty avpl.
397 *
398 * Return value: a pointer to the newly created avpl.
399 *
400 **/
401extern AVPL* new_avpl(const char* name) {
402 AVPL* new_avpl_p = (AVPL*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type)));
403
404#ifdef _AVP_DEBUGGING
405 dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpl_p: %p name=%s",new_avpl_p,name);
406#endif
407
408 new_avpl_p->name = name ? scs_subscribe(avp_strings, name) : scs_subscribe(avp_strings, "");
409 new_avpl_p->len = 0;
410 new_avpl_p->null.avp = NULL((void*)0);
411 new_avpl_p->null.next = &new_avpl_p->null;
412 new_avpl_p->null.prev = &new_avpl_p->null;
413
414
415 return new_avpl_p;
416}
417
418extern void rename_avpl(AVPL* avpl, char* name) {
419 scs_unsubscribe(avp_strings,avpl->name);
420 avpl->name = scs_subscribe(avp_strings,name);
421}
422
423/**
424 * insert_avp_before_node:
425 * @param avpl the avpl in which to insert.
426 * @param next_node the next node before which the new avpn has to be inserted.
427 * @param avp the avp to be inserted.
428 * @param copy_avp whether the original AVP or a copy thereof must be inserted.
429 *
430 * Pre-condition: the avp is sorted before before_avp and does not already exist
431 * in the avpl.
432 */
433static void insert_avp_before_node(AVPL* avpl, AVPN* next_node, AVP *avp, bool_Bool copy_avp) {
434 AVPN* new_avp_val = (AVPN*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type)));
435
436 new_avp_val->avp = copy_avp
20.1
'copy_avp' is true
? avp_copy(avp) : avp;
21
'?' condition is true
22
Calling 'avp_copy'
437
438#ifdef _AVP_DEBUGGING
439 dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpn: %p",new_avp_val);
440 dbg_print(dbg_avpl,5,dbg_fp,"insert_avp: inserting %p in %p before %p;",avp,avpl,next_node);
441#endif
442
443 new_avp_val->next = next_node;
444 new_avp_val->prev = next_node->prev;
445 next_node->prev->next = new_avp_val;
446 next_node->prev = new_avp_val;
447
448 avpl->len++;
449
450#ifdef _AVP_DEBUGGING
451 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len);
452#endif
453}
454
455/**
456 * insert_avp:
457 * @param avpl the avpl in which to insert.
458 * @param avp the avp to be inserted.
459 *
460 * Inserts the given AVP into the given AVPL if an identical one isn't yet there.
461 *
462 * Return value: whether it was inserted or not.
463 *
464 * BEWARE: Check the return value, you might need to delete the avp if
465 * it is not inserted.
466 **/
467extern bool_Bool insert_avp(AVPL* avpl, AVP* avp) {
468 AVPN* c;
469
470#ifdef _AVP_DEBUGGING
471 dbg_print(dbg_avpl_op,4,dbg_fp,"insert_avp: %p %p %s%c%s;",avpl,avp,avp->n,avp->o,avp->v);
472#endif
473
474 /* get to the insertion point */
475 for (c=avpl->null.next; c->avp; c = c->next) {
476 int name_diff = strcmp(avp->n, c->avp->n);
477
478 if (name_diff == 0) {
479 int value_diff = strcmp(avp->v, c->avp->v);
480
481 if (value_diff < 0) {
482 break;
483 }
484
485 if (value_diff == 0) {
486 // ignore duplicate values, prevents (a=1, a=1)
487 // note that this is also used to insert
488 // conditions AVPs, so really check if the name,
489 // value and operator are all equal.
490 if (c->avp->o == avp->o && avp->o == AVP_OP_EQUAL'=') {
491 return false0;
492 }
493 }
494 }
495
496 if (name_diff < 0) {
497 break;
498 }
499 }
500
501 insert_avp_before_node(avpl, c, avp, false0);
502
503 return true1;
504}
505
506/**
507 * get_avp_by_name:
508 * @param avpl the avpl from which to try to get the avp.
509 * @param name the name of the avp we are looking for.
510 * @param cookie variable in which to store the state between calls.
511 *
512 * Gets pointer to the next avp whose name is given; uses cookie to store its
513 * state between calls.
514 *
515 * Return value: a pointer to the next matching avp if there's one, else NULL.
516 *
517 **/
518extern AVP* get_avp_by_name(AVPL* avpl, char* name, void** cookie) {
519 AVPN* curr;
520 AVPN* start = (AVPN*) *cookie;
521
522#ifdef _AVP_DEBUGGING
523 dbg_print(dbg_avpl_op,7,dbg_fp,"get_avp_by_name: entering: %p %s %p",avpl,name,*cookie);
524#endif
525
526 name = scs_subscribe(avp_strings, name);
527
528 if (!start) start = avpl->null.next;
529
530 for ( curr = start; curr->avp; curr = curr->next ) {
531 if ( curr->avp->n == name ) {
532 break;
533 }
534 }
535
536 *cookie = curr;
537
538#ifdef _AVP_DEBUGGING
539 dbg_print(dbg_avpl_op,5,dbg_fp,"get_avp_by_name: got avp: %p",curr);
540#endif
541
542 scs_unsubscribe(avp_strings, name);
543
544 return curr->avp;
545}
546
547/**
548 * extract_avp_by_name:
549 * @param avpl the avpl from which to try to extract the avp.
550 * @param name the name of the avp we are looking for.
551 *
552 * Extracts from the avpl the next avp whose name is given;
553 *
554 * Return value: a pointer to extracted avp if there's one, else NULL.
555 *
556 **/
557extern AVP* extract_avp_by_name(AVPL* avpl, char* name) {
558 AVPN* curr;
559 AVP* avp = NULL((void*)0);
560
561#ifdef _AVP_DEBUGGING
562 dbg_print(dbg_avpl_op,7,dbg_fp,"extract_avp_by_name: entering: %p %s",avpl,name);
563#endif
564
565 name = scs_subscribe(avp_strings, name);
566
567 for ( curr = avpl->null.next; curr->avp; curr = curr->next ) {
568 if ( curr->avp->n == name ) {
569 break;
570 }
571 }
572
573 scs_unsubscribe(avp_strings, name);
574
575 if( ! curr->avp ) return NULL((void*)0);
576
577 curr->next->prev = curr->prev;
578 curr->prev->next = curr->next;
579
580 avp = curr->avp;
581
582 g_slice_free(any_avp_type,(any_avp_type*)curr)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)curr)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)curr
)); } while (0)
;
583
584 (avpl->len)--;
585
586#ifdef _AVP_DEBUGGING
587 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len);
588#endif
589
590#ifdef _AVP_DEBUGGING
591 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_avp_by_name: got avp: %p",avp);
592#endif
593
594 return avp;
595}
596
597
598/**
599 * extract_first_avp:
600 * @param avpl the avpl from which to try to extract the avp.
601 *
602 * Extracts the first avp from the avpl.
603 *
604 * Return value: a pointer to extracted avp if there's one, else NULL.
605 *
606 **/
607extern AVP* extract_first_avp(AVPL* avpl) {
608 AVP* avp;
609 AVPN* node;
610
611#ifdef _AVP_DEBUGGING
612 dbg_print(dbg_avpl_op,7,dbg_fp,"extract_first_avp: %p",avpl);
613#endif
614
615 node = avpl->null.next;
616
617 avpl->null.next->prev = &avpl->null;
618 avpl->null.next = node->next;
619
620 avp = node->avp;
621
622 if (avp) {
623 g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node
)); } while (0)
;
624 (avpl->len)--;
625#ifdef _AVP_DEBUGGING
626 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len);
627#endif
628 }
629
630#ifdef _AVP_DEBUGGING
631 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_first_avp: got avp: %p",avp);
632#endif
633
634 return avp;
635
636}
637
638
639/**
640 * extract_last_avp:
641 * @param avpl the avpl from which to try to extract the avp.
642 *
643 * Extracts the last avp from the avpl.
644 *
645 * Return value: a pointer to extracted avp if there's one, else NULL.
646 *
647 **/
648extern AVP* extract_last_avp(AVPL* avpl) {
649 AVP* avp;
650 AVPN* node;
651
652 node = avpl->null.prev;
653
654 avpl->null.prev->next = &avpl->null;
655 avpl->null.prev = node->prev;
656
657 avp = node->avp;
658
659 if (avp) {
660 g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node
)); } while (0)
;
661 (avpl->len)--;
662#ifdef _AVP_DEBUGGING
663 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len);
664#endif
665 }
666
667#ifdef _AVP_DEBUGGING
668 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %p",avp);
669#endif
670
671 return avp;
672
673}
674
675
676/**
677 * delete_avpl:
678 * @param avpl the avpl from which to try to extract the avp.
679 * @param avps_too whether or not it should delete the avps as well.
680 *
681 * Destroys an avpl and releases the resources it uses. If told to do
682 * so releases the avps as well.
683 *
684 **/
685extern void delete_avpl(AVPL* avpl, bool_Bool avps_too) {
686 AVP* avp;
687#ifdef _AVP_DEBUGGING
688 dbg_print(dbg_avpl,3,dbg_fp,"delete_avpl: %p",avpl);
689#endif
690
691 while(( avp = extract_last_avp(avpl))) {
692 if (avps_too) {
693 delete_avp(avp);
694 }
695 }
696
697 scs_unsubscribe(avp_strings,avpl->name);
698 g_slice_free(any_avp_type,(any_avp_type*)avpl)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)avpl)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)avpl
)); } while (0)
;
699}
700
701
702
703/**
704 * get_next_avp:
705 * @param avpl the avpl from which to try to get the avps.
706 * @param cookie variable in which to store the state between calls.
707 *
708 * Iterates on an avpl to get its avps.
709 *
710 * Return value: a pointer to the next avp if there's one, else NULL.
711 *
712 **/
713extern AVP* get_next_avp(AVPL* avpl, void** cookie) {
714 AVPN* node;
715
716#ifdef _AVP_DEBUGGING
717 dbg_print(dbg_avpl_op,5,dbg_fp,"get_next_avp: avpl: %p avpn: %p",avpl,*cookie);
718#endif
719
720 if (*cookie) {
721 node = (AVPN*) *cookie;
722 } else {
723 node = avpl->null.next;
724 }
725
726 *cookie = node->next;
727
728#ifdef _AVP_DEBUGGING
729 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %p",node->avp);
730#endif
731
732 return node->avp;
733}
734
735/**
736 * avpl_to_str:
737 * @param avpl the avpl to represent.
738 *
739 * Creates a newly allocated string containing a representation of an avpl.
740 *
741 * Return value: a pointer to the newly allocated string.
742 *
743 **/
744char* avpl_to_str(AVPL* avpl) {
745 AVPN* c;
746 GString* s = g_string_new("");
747 char* avp_s;
748 char* r;
749
750 for(c=avpl->null.next; c->avp; c = c->next) {
751 avp_s = avp_to_str(c->avp)(wmem_strdup_printf(((void*)0), "%s%c%s",c->avp->n,c->
avp->o,c->avp->v))
;
752 g_string_append_printf(s," %s;",avp_s);
753 g_free(avp_s);
754 }
755
756 r = g_string_free(s,FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((s), (
(0))) : g_string_free_and_steal (s)) : (g_string_free) ((s), (
(0))))
;
757
758 /* g_strchug(r); ? */
759 return r;
760}
761
762extern char* avpl_to_dotstr(AVPL* avpl) {
763 AVPN* c;
764 GString* s = g_string_new("");
765 char* avp_s;
766 char* r;
767
768 for(c=avpl->null.next; c->avp; c = c->next) {
769 avp_s = avp_to_str(c->avp)(wmem_strdup_printf(((void*)0), "%s%c%s",c->avp->n,c->
avp->o,c->avp->v))
;
770 g_string_append_printf(s," .%s;",avp_s);
771 g_free(avp_s);
772 }
773
774 r = g_string_free(s,FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((s), (
(0))) : g_string_free_and_steal (s)) : (g_string_free) ((s), (
(0))))
;
775
776 /* g_strchug(r); ? */
777 return r;
778}
779
780/**
781* merge_avpl:
782 * @param dst the avpl in which to merge the avps.
783 * @param src the avpl from which to get the avps.
784 * @param copy_avps whether avps should be copied instead of referenced.
785 *
786 * Adds the avps of src that are not existent in dst into dst.
787 *
788 **/
789extern void merge_avpl(AVPL* dst, AVPL* src, bool_Bool copy_avps) {
790 AVPN* cd = NULL((void*)0);
791 AVPN* cs = NULL((void*)0);
792
793#ifdef _AVP_DEBUGGING
794 dbg_print(dbg_avpl_op,3,dbg_fp,"merge_avpl: %p %p",dst,src);
795#endif
796
797 cs = src->null.next;
798 cd = dst->null.next;
799
800 while (cs->avp && cd->avp) {
801
802 int name_diff = strcmp(cd->avp->n, cs->avp->n);
803
804 if (name_diff < 0) {
805 // dest < source, advance dest to find a better place to insert
806 cd = cd->next;
807 } else if (name_diff > 0) {
808 // dest > source, so it can be definitely inserted here.
809 insert_avp_before_node(dst, cd, cs->avp, copy_avps);
810 cs = cs->next;
811 } else {
812 // attribute names are equal. Ignore duplicate values but ensure that other values are sorted.
813 int value_diff = strcmp(cd->avp->v, cs->avp->v);
814
815 if (value_diff < 0) {
816 // dest < source, do not insert it yet
817 cd = cd->next;
818 } else if (value_diff > 0) {
819 // dest > source, insert AVP before the current dest AVP
820 insert_avp_before_node(dst, cd, cs->avp, copy_avps);
821 cs = cs->next;
822 } else {
823 // identical AVPs, do not create a duplicate.
824 cs = cs->next;
825 }
826 }
827 }
828
829 // if there are remaining source AVPs while there are no more destination
830 // AVPs (cd now represents the NULL item, after the last item), append
831 // all remaining source AVPs to the end
832 while (cs->avp) {
833 insert_avp_before_node(dst, cd, cs->avp, copy_avps);
834 cs = cs->next;
835 }
836
837#ifdef _AVP_DEBUGGING
838 dbg_print(dbg_avpl_op,8,dbg_fp,"merge_avpl: done");
839#endif
840
841 return;
842}
843
844
845/**
846 * new_avpl_from_avpl:
847 * @param name the name of the new avpl.
848 * @param avpl the avpl from which to get the avps.
849 * @param copy_avps whether avps should be copied instead of referenced.
850 *
851 * Creates a new avpl containing the same avps as the given avpl
852 * It will either reference or copy the avps.
853 *
854 * Return value: a pointer to the newly allocated string.
855 *
856 **/
857extern AVPL* new_avpl_from_avpl(const char* name, AVPL* avpl, bool_Bool copy_avps) {
858 AVPL* newavpl = new_avpl(name);
859 void* cookie = NULL((void*)0);
860 AVP* avp;
861 AVP* copy;
862
863#ifdef _AVP_DEBUGGING
864 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_from_avpl: %p from=%p name='%s'",newavpl,avpl,name);
865#endif
866
867 while(( avp = get_next_avp(avpl,&cookie) )) {
868 if (copy_avps) {
869 copy = avp_copy(avp);
870 if ( ! insert_avp(newavpl,copy) ) {
871 delete_avp(copy);
872 }
873 } else {
874 insert_avp(newavpl,avp);
875 }
876 }
877
878#ifdef _AVP_DEBUGGING
879 dbg_print(dbg_avpl_op,8,dbg_fp,"new_avpl_from_avpl: done");
880#endif
881
882 return newavpl;
883}
884
885/**
886* match_avp:
887 * @param src an src to be compared against an "op" avp
888 * @param op the "op" avp that will be matched against the src avp
889 *
890 * Checks whether or not two avp's match.
891 *
892 * Return value: a pointer to the src avp if there's a match.
893 *
894 **/
895extern AVP* match_avp(AVP* src, AVP* op) {
896 char** splited;
897 int i;
898 char* p;
899 unsigned ls;
900 unsigned lo;
901 double fs = 0.0;
902 double fo = 0.0;
903 bool_Bool lower = false0;
904
905#ifdef _AVP_DEBUGGING
906 dbg_print(dbg_avpl_op,3,dbg_fp,"match_avp: %s%c%s; vs. %s%c%s;",src->n,src->o,src->v,op->n,op->o,op->v);
907#endif
908
909 if ( src->n != op->n ) {
910 return NULL((void*)0);
911 }
912
913 switch (op->o) {
914 case AVP_OP_EXISTS'?':
915 return src;
916 case AVP_OP_EQUAL'=':
917 return src->v == op->v ? src : NULL((void*)0);
918 case AVP_OP_NOTEQUAL'!':
919 return !( src->v == op->v) ? src : NULL((void*)0);
920 case AVP_OP_STARTS'^':
921 return strncmp(src->v,op->v,strlen(op->v)) == 0 ? src : NULL((void*)0);
922 case AVP_OP_ONEOFF'|':
923 splited = g_strsplit(op->v,"|",0);
924 if (splited) {
925 for (i=0;splited[i];i++) {
926 if(g_str_equal(splited[i],src->v)(strcmp ((const char *) (splited[i]), (const char *) (src->
v)) == 0)
) {
927 g_strfreev(splited);
928 return src;
929 }
930 }
931 g_strfreev(splited);
932 }
933 return NULL((void*)0);
934
935 case AVP_OP_LOWER'<':
936 lower = true1;
937 /* FALLTHRU */
938 case AVP_OP_HIGHER'>':
939
940 fs = g_ascii_strtod(src->v, NULL((void*)0));
941 fo = g_ascii_strtod(op->v, NULL((void*)0));
942
943 if (lower) {
944 if (fs<fo) return src;
945 else return NULL((void*)0);
946 } else {
947 if (fs>fo) return src;
948 else return NULL((void*)0);
949 }
950 case AVP_OP_ENDS'$':
951 /* does this work? */
952 ls = (unsigned) strlen(src->v);
953 lo = (unsigned) strlen(op->v);
954
955 if ( ls < lo ) {
956 return NULL((void*)0);
957 } else {
958 p = src->v + ( ls - lo );
959 return g_str_equal(p,op->v)(strcmp ((const char *) (p), (const char *) (op->v)) == 0) ? src : NULL((void*)0);
960 }
961
962 /* case AVP_OP_TRANSF: */
963 /* return do_transform(src,op); */
964 case AVP_OP_CONTAINS'~':
965 return g_strrstr(src->v, op->v) ? src : NULL((void*)0);
966 }
967 /* will never get here */
968 return NULL((void*)0);
969}
970
971
972
973/**
974 * new_avpl_loose_match:
975 * @param name the name of the resulting avpl
976 * @param src the data AVPL to be matched against a condition AVPL
977 * @param op the conditions AVPL that will be matched against the data AVPL
978 * @param copy_avps whether the avps in the resulting avpl should be copied
979 *
980 * Creates a new AVP list containing all data AVPs that matched any of the
981 * conditions AVPs. If there are no matches, an empty list will be returned.
982 *
983 * Note: Loose will always be considered a successful match, it matches zero or
984 * more conditions.
985 */
986extern AVPL* new_avpl_loose_match(const char* name,
987 AVPL* src,
988 AVPL* op,
989 bool_Bool copy_avps) {
990
991 AVPL* newavpl = new_avpl(scs_subscribe(avp_strings, name));
992 AVPN* co = NULL((void*)0);
993 AVPN* cs = NULL((void*)0);
994
995#ifdef _AVP_DEBUGGING
996 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_loose_match: %p src=%p op=%p name='%s'",newavpl,src,op,name);
997#endif
998
999
1000 cs = src->null.next;
1001 co = op->null.next;
1002 while (cs->avp && co->avp) {
1003 int name_diff = strcmp(co->avp->n, cs->avp->n);
1004
1005 if (name_diff < 0) {
1006 // op < source, op is not matching
1007 co = co->next;
1008 } else if (name_diff > 0) {
1009 // op > source, source is not matching
1010 cs = cs->next;
1011 } else {
1012 // attribute match found, let's see if there is any condition (op) that accepts this data AVP.
1013 AVPN *cond = co;
1014 do {
1015 if (match_avp(cs->avp, cond->avp)) {
1016 insert_avp_before_node(newavpl, newavpl->null.prev->next, cs->avp, copy_avps);
1017 break;
1018 }
1019 cond = cond->next;
1020 } while (cond->avp && cond->avp->n == cs->avp->n);
1021 cs = cs->next;
1022 }
1023 }
1024
1025 // return matches (possible none)
1026 return newavpl;
1027}
1028
1029/**
1030* new_avpl_pairs_match:
1031 * @param name the name of the resulting avpl
1032 * @param src the data AVPL to be matched against a condition AVPL
1033 * @param op the conditions AVPL that will be matched against the data AVPL
1034 * @param strict true if every condition must have a matching data AVP, false if
1035 * it is also acceptable that only one of the condition AVPs for the same
1036 * attribute is matching.
1037 * @param copy_avps whether the avps in the resulting avpl should be copied
1038 *
1039 * Creates an AVP list by matching pairs of conditions and data AVPs, returning
1040 * the data AVPs. If strict is true, then each condition must be paired with a
1041 * matching data AVP. If strict is false, then some conditions are allowed to
1042 * fail when other conditions for the same attribute do have a match. Note that
1043 * if the condition AVPL is empty, the result will be a match (an empty list).
1044 *
1045 * Return value: a pointer to the newly created avpl containing the
1046 * matching avps or NULL if there is no match.
1047 */
1048extern AVPL* new_avpl_pairs_match(const char* name, AVPL* src, AVPL* op, bool_Bool strict, bool_Bool copy_avps) {
1049 AVPL* newavpl;
1050 AVPN* co = NULL((void*)0);
1051 AVPN* cs = NULL((void*)0);
1052 const char *last_match = NULL((void*)0);
1053 bool_Bool matched = true1;
1054
1055 newavpl = new_avpl(scs_subscribe(avp_strings, name));
1056
1057#ifdef _AVP_DEBUGGING
1058 dbg_print(dbg_avpl_op,3,dbg_fp,"%s: %p src=%p op=%p name='%s'",G_STRFUNC((const char*) (__func__)),newavpl,src,op,name);
1059#endif
1060
1061 cs = src->null.next;
1062 co = op->null.next;
1063 while (cs->avp
13.1
Field 'avp' is non-null
&& co->avp) {
5
Assuming field 'avp' is non-null
6
Loop condition is true. Entering loop body
13
Taking false branch
14
Loop condition is true. Entering loop body
1064 int name_diff = g_strcmp0(co->avp->n, cs->avp->n);
1065 const char *failed_match = NULL((void*)0);
1066
1067 if (name_diff < 0) {
7
Assuming 'name_diff' is >= 0
8
Taking false branch
15
Assuming 'name_diff' is >= 0
16
Taking false branch
1068 // op < source, op has no data avp with same attribute.
1069 failed_match = co->avp->n;
1070 co = co->next;
1071 } else if (name_diff > 0) {
9
Assuming 'name_diff' is <= 0
10
Taking false branch
17
Assuming 'name_diff' is <= 0
18
Taking false branch
1072 // op > source, the source avp is not matched by any condition
1073 cs = cs->next;
1074 } else {
1075 // Matching attributes found, now try to find a matching data AVP for the condition.
1076 if (match_avp(cs->avp, co->avp)) {
11
Taking false branch
19
Taking true branch
1077 insert_avp_before_node(newavpl, newavpl->null.prev->next, cs->avp, copy_avps);
20
Calling 'insert_avp_before_node'
1078 last_match = co->avp->n;
1079 cs = cs->next;
1080 } else {
1081 failed_match = co->avp->n;
1082 }
1083 co = co->next;
1084 }
1085
1086 // condition did not match, check if we can continue matching.
1087 if (failed_match) {
12
Assuming 'failed_match' is null
1088 if (strict) {
1089 matched = false0;
1090 break;
1091 } else if (last_match != failed_match) {
1092 // None of the conditions so far matched the attribute, check for other candidates
1093 if (!co->avp || co->avp->n != last_match) {
1094 matched = false0;
1095 break;
1096 }
1097 }
1098 }
1099 }
1100
1101 // if there are any conditions remaining, then those could not be matched
1102 if (matched && strict && co->avp) {
1103 matched = false0;
1104 }
1105
1106 if (matched) {
1107 // there was a match, accept it
1108 return newavpl;
1109 } else {
1110 // no match, only delete AVPs too if they were copied
1111 delete_avpl(newavpl, copy_avps);
1112 return NULL((void*)0);
1113 }
1114}
1115
1116
1117/**
1118 * new_avpl_from_match:
1119 * @param mode The matching method, one of AVPL_STRICT, AVPL_LOOSE, AVPL_EVERY.
1120 * @param name the name of the resulting avpl
1121 * @param src the data AVPL to be matched against a condition AVPL
1122 * @param op the conditions AVPL that will be matched against the data AVPL
1123 *
1124 * Matches the conditions AVPL against the original AVPL according to the mode.
1125 * If there is no match, NULL is returned. If there is actually a match, then
1126 * the matching AVPs (a subset of the data) are returned.
1127 */
1128extern AVPL* new_avpl_from_match(avpl_match_mode mode, const char* name,AVPL* src, AVPL* op, bool_Bool copy_avps) {
1129 AVPL* avpl = NULL((void*)0);
1130
1131 switch (mode) {
3
Control jumps to 'case AVPL_EVERY:' at line 1138
1132 case AVPL_STRICT:
1133 avpl = new_avpl_pairs_match(name, src, op, true1, copy_avps);
1134 break;
1135 case AVPL_LOOSE:
1136 avpl = new_avpl_loose_match(name,src,op,copy_avps);
1137 break;
1138 case AVPL_EVERY:
1139 avpl = new_avpl_pairs_match(name, src, op, false0, copy_avps);
4
Calling 'new_avpl_pairs_match'
1140 break;
1141 case AVPL_NO_MATCH:
1142 // XXX this seems unused
1143 avpl = new_avpl_from_avpl(name,src,copy_avps);
1144 merge_avpl(avpl, op, copy_avps);
1145 break;
1146 }
1147
1148 return avpl;
1149}
1150
1151/**
1152 * delete_avpl_transform:
1153 * @param op a pointer to the avpl transformation object
1154 *
1155 * Destroys an avpl transformation object and releases all the resources it
1156 * uses.
1157 *
1158 **/
1159extern void delete_avpl_transform(AVPL_Transf* op) {
1160 AVPL_Transf* next;
1161
1162 for (; op ; op = next) {
1163 next = op->next;
1164
1165 g_free(op->name);
1166
1167 if (op->match) {
1168 delete_avpl(op->match,true1);
1169 }
1170
1171 if (op->replace) {
1172 delete_avpl(op->replace,true1);
1173 }
1174
1175 g_free(op);
1176 }
1177
1178}
1179
1180
1181/**
1182 * avpl_transform:
1183 * @param src the source avpl for the transform operation.
1184 * @param op a pointer to the avpl transformation object to apply.
1185 *
1186 * Applies the "op" transformation to an avpl, matches it and eventually
1187 * replaces or inserts the transformed avps.
1188 *
1189 * Return value: whether the transformation was performed or not.
1190 **/
1191extern void avpl_transform(AVPL* src, AVPL_Transf* op) {
1192 AVPL* avpl = NULL((void*)0);
1193 AVPN* cs;
1194 AVPN* cm;
1195 AVPN* n;
1196
1197#ifdef _AVP_DEBUGGING
1198 dbg_print(dbg_avpl_op,3,dbg_fp,"avpl_transform: src=%p op=%p",src,op);
1199#endif
1200
1201 for ( ; op ; op = op->next) {
1
Loop condition is true. Entering loop body
1202
1203 avpl = new_avpl_from_match(op->match_mode, src->name,src, op->match, true1);
2
Calling 'new_avpl_from_match'
1204
1205 if (avpl) {
1206 switch (op->replace_mode) {
1207 case AVPL_NO_REPLACE:
1208 delete_avpl(avpl,true1);
1209 return;
1210 case AVPL_INSERT:
1211 merge_avpl(src,op->replace,true1);
1212 delete_avpl(avpl,true1);
1213 return;
1214 case AVPL_REPLACE:
1215 cs = src->null.next;
1216 cm = avpl->null.next;
1217 // Removes AVPs from the source which are in the matched data.
1218 // Assume that the matched set is a subset of the source.
1219 while (cs->avp && cm->avp) {
1220 if (cs->avp->n == cm->avp->n && cs->avp->v == cm->avp->v) {
1221 n = cs->next;
1222
1223 cs->prev->next = cs->next;
1224 cs->next->prev = cs->prev;
1225
1226 if (cs->avp)
1227 delete_avp(cs->avp);
1228 g_slice_free(any_avp_type,(any_avp_type*)cs)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)cs)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)cs)
); } while (0)
;
1229
1230 cs = n;
1231 cm = cm->next;
1232 } else {
1233 // Current matched AVP is not equal to the current
1234 // source AVP. Since there must be a source AVP for
1235 // each matched AVP, advance current source and not
1236 // the match AVP.
1237 cs = cs->next;
1238 }
1239 }
1240
1241 merge_avpl(src,op->replace,true1);
1242 delete_avpl(avpl,true1);
1243 return;
1244 }
1245 }
1246 }
1247}
1248
1249
1250/**
1251 * new_loal:
1252 * @param name the name the loal will take.
1253 *
1254 * Creates an empty list of avp lists.
1255 *
1256 * Return value: a pointer to the newly created loal.
1257 **/
1258extern LoAL* new_loal(const char* name) {
1259 LoAL* new_loal_p = (LoAL*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type)));
1260
1261 if (! name) {
1262 name = "anonymous";
1263 }
1264
1265#ifdef _AVP_DEBUGGING
1266 dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_p: %p name=%s",new_loal_p,name);
1267#endif
1268
1269 new_loal_p->name = scs_subscribe(avp_strings,name);
1270 new_loal_p->null.avpl = NULL((void*)0);
1271 new_loal_p->null.next = &new_loal_p->null;
1272 new_loal_p->null.prev = &new_loal_p->null;
1273 new_loal_p->len = 0;
1274 return new_loal_p;
1275}
1276
1277/**
1278 * loal_append:
1279 * @param loal the loal on which to operate.
1280 * @param avpl the avpl to append.
1281 *
1282 * Appends an avpl to a loal.
1283 *
1284 **/
1285extern void loal_append(LoAL* loal, AVPL* avpl) {
1286 LoALnode* node = (LoALnode*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type)));
1287
1288#ifdef _AVP_DEBUGGING
1289 dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_node: %p",node);
1290#endif
1291
1292 node->avpl = avpl;
1293 node->next = &loal->null;
1294 node->prev = loal->null.prev;
1295
1296 loal->null.prev->next = node;
1297 loal->null.prev = node;
1298 loal->len++;
1299}
1300
1301
1302/**
1303 * extract_first_avpl:
1304 * @param loal the loal on which to operate.
1305 *
1306 * Extracts the first avpl contained in a loal.
1307 *
1308 * Return value: a pointer to the extracted avpl.
1309 *
1310 **/
1311extern AVPL* extract_first_avpl(LoAL* loal) {
1312 LoALnode* node;
1313 AVPL* avpl;
1314
1315#ifdef _AVP_DEBUGGING
1316 dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: from: %s",loal->name);
1317#endif
1318
1319 node = loal->null.next;
1320
1321 loal->null.next->next->prev = &loal->null;
1322 loal->null.next = node->next;
1323
1324 loal->len--;
1325
1326 avpl = node->avpl;
1327
1328 if ( avpl ) {
1329 g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node
)); } while (0)
;
1330
1331#ifdef _AVP_DEBUGGING
1332 dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: got %s",avpl->name);
1333 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %p",node);
1334#endif
1335 }
1336
1337 return avpl;
1338}
1339
1340/**
1341* extract_first_avpl:
1342 * @param loal the loal on which to operate.
1343 *
1344 * Extracts the last avpl contained in a loal.
1345 *
1346 * Return value: a pointer to the extracted avpl.
1347 *
1348 **/
1349extern AVPL* extract_last_avpl(LoAL* loal){
1350 LoALnode* node;
1351 AVPL* avpl;
1352
1353 node = loal->null.prev;
1354
1355 loal->null.prev->prev->next = &loal->null;
1356 loal->null.prev = node->prev;
1357
1358 loal->len--;
1359
1360 avpl = node->avpl;
1361
1362 if ( avpl ) {
1363 g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node
)); } while (0)
;
1364#ifdef _AVP_DEBUGGING
1365 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %p",node);
1366#endif
1367 }
1368
1369 return avpl;
1370}
1371
1372/**
1373 * extract_first_avpl:
1374 * @param loal the loal on which to operate.
1375 * @param cookie pointer to the pointer variable to contain the state between calls
1376 *
1377 * At each call will return the following avpl from a loal. The given cookie
1378 * will be used to manatain the state between calls.
1379 *
1380 * Return value: a pointer to the next avpl.
1381 *
1382 **/
1383extern AVPL* get_next_avpl(LoAL* loal,void** cookie) {
1384 LoALnode* node;
1385
1386#ifdef _AVP_DEBUGGING
1387 dbg_print(dbg_avpl_op,3,dbg_fp,"get_next_avpl: loal=%p node=%p",loal,*cookie);
1388#endif
1389
1390 if (*cookie) {
1391 node = (LoALnode*) *cookie;
1392 } else {
1393 node = loal->null.next;
1394 }
1395
1396 *cookie = node->next;
1397
1398 return node->avpl;
1399}
1400
1401/**
1402 * delete_loal:
1403 * @param loal the loal to be deleted.
1404 * @param avpls_too whether avpls contained by the loal should be deleted as well
1405 * @param avps_too whether avps contained by the avpls should be also deleted
1406 *
1407 * Destroys a loal and eventually desstroys avpls and avps.
1408 *
1409 **/
1410extern void delete_loal(LoAL* loal, bool_Bool avpls_too, bool_Bool avps_too) {
1411 AVPL* avpl;
1412
1413#ifdef _AVP_DEBUGGING
1414 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal: %p",loal);
1415#endif
1416
1417 while(( avpl = extract_last_avpl(loal) )) {
1418 if (avpls_too) {
1419 delete_avpl(avpl,avps_too);
1420 }
1421 }
1422
1423 scs_unsubscribe(avp_strings,loal->name);
1424 g_slice_free(any_avp_type,(any_avp_type*)loal)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type
*)loal)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)loal
)); } while (0)
;
1425}
1426
1427
1428
1429/****************************************************************************
1430 ******************* the following are used in load_loal_from_file
1431 ****************************************************************************/
1432
1433/**
1434 * load_loal_error:
1435 * Used by loal_from_file to handle errors while loading.
1436 **/
1437static LoAL* load_loal_error(FILE* fp, LoAL* loal, AVPL* curr, int linenum, const char* fmt, ...) {
1438 va_list list;
1439 char* desc;
1440 LoAL* ret = NULL((void*)0);
1441 char* err;
1442
1443 va_start( list, fmt )__builtin_va_start(list, fmt);
1444 desc = ws_strdup_vprintf(fmt, list)wmem_strdup_vprintf(((void*)0), fmt, list);
1445 va_end( list )__builtin_va_end(list);
1446
1447 if (loal) {
1448 err = ws_strdup_printf("Error Loading LoAL from file: in %s at line: %i, %s",loal->name,linenum,desc)wmem_strdup_printf(((void*)0), "Error Loading LoAL from file: in %s at line: %i, %s"
,loal->name,linenum,desc)
;
1449 } else {
1450 err = ws_strdup_printf("Error Loading LoAL at line: %i, %s",linenum,desc)wmem_strdup_printf(((void*)0), "Error Loading LoAL at line: %i, %s"
,linenum,desc)
;
1451 }
1452 ret = new_loal(err);
1453
1454 g_free(desc);
1455 g_free(err);
1456
1457 if (fp) fclose(fp);
1458 if (loal) delete_loal(loal,true1,true1);
1459 if (curr) delete_avpl(curr,true1);
1460
1461 return ret;
1462}
1463
1464
1465/* the maximum length allowed for a line */
1466#define MAX_ITEM_LEN8192 8192
1467
1468/* this two ugly things are used for tokenizing */
1469#define AVP_OP_CHAR'=': case '^': case '$': case '~': case '<': case '>': case
'?': case '|': case '&' : case '!'
'=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!'
1470
1471#define AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G'
: case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case
'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T'
:case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case
'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g'
: case 'h': case 'i': case 'j': case 'k': case 'l': case 'm':
case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case
't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z'
: case '_': case '0': case '1': case '2': case '3': case '4':
case '5': case '6':case '7': case '8': case '9': case '.'
'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':\
1472case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':\
1473case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':\
1474case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':\
1475case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':\
1476case 'y': case 'z': case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':\
1477case '7': case '8': case '9': case '.'
1478
1479
1480/**
1481 * loal_from_file:
1482 * @param filename the file containing a loals text representation.
1483 *
1484 * Given a filename it will attempt to load a loal containing a copy of
1485 * the avpls represented in the file.
1486 *
1487 * Return value: if successful a pointer to the new populated loal, else NULL.
1488 *
1489 **/
1490extern LoAL* loal_from_file(char* filename) {
1491 FILE *fp = NULL((void*)0);
1492 char c;
1493 int i = 0;
1494 uint32_t linenum = 1;
1495 char *linenum_buf;
1496 char *name;
1497 char *value;
1498 char op = '?';
1499 LoAL *loal_error, *loal = new_loal(filename);
1500 AVPL* curr = NULL((void*)0);
1501 AVP* avp;
1502
1503 enum _load_loal_states {
1504 START,
1505 BEFORE_NAME,
1506 IN_NAME,
1507 IN_VALUE,
1508 MY_IGNORE
1509 } state;
1510
1511 linenum_buf = (char*)g_malloc(MAX_ITEM_LEN8192);
1512 name = (char*)g_malloc(MAX_ITEM_LEN8192);
1513 value = (char*)g_malloc(MAX_ITEM_LEN8192);
1514#ifndef _WIN32
1515 if (! getuid()) {
1516 loal_error = load_loal_error(fp,loal,curr,linenum,"MATE Will not run as root");
1517 goto error;
1518 }
1519#endif
1520
1521 state = START;
1522
1523 if (( fp = ws_fopenfopen(filename,"r") )) {
1524 while(( c = (char) fgetc(fp) )){
1525
1526 if ( feof(fp) ) {
1527 if ( ferror(fp) ) {
1528 report_read_failure(filename,errno(*__errno_location ()));
1529 loal_error = load_loal_error(fp,loal,curr,linenum,"Error while reading '%f'",filename);
1530 goto error;
1531 }
1532 break;
1533 }
1534
1535 if ( c == '\n' ) {
1536 linenum++;
1537 }
1538
1539 if ( i >= MAX_ITEM_LEN8192 - 1 ) {
1540 loal_error = load_loal_error(fp,loal,curr,linenum,"Maximum item length exceeded");
1541 goto error;
1542 }
1543
1544 switch(state) {
1545 case MY_IGNORE:
1546 switch (c) {
1547 case '\n':
1548 state = START;
1549 i = 0;
1550 continue;
1551 default:
1552 continue;
1553 }
1554 case START:
1555 switch (c) {
1556 case ' ': case '\t':
1557 /* ignore whitespace at line start */
1558 continue;
1559 case '\n':
1560 /* ignore empty lines */
1561 i = 0;
1562 continue;
1563 case AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G'
: case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case
'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T'
:case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case
'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g'
: case 'h': case 'i': case 'j': case 'k': case 'l': case 'm':
case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case
't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z'
: case '_': case '0': case '1': case '2': case '3': case '4':
case '5': case '6':case '7': case '8': case '9': case '.'
:
1564 state = IN_NAME;
1565 i = 0;
1566 name[i++] = c;
1567 name[i] = '\0';
1568 snprintf(linenum_buf,MAX_ITEM_LEN8192,"%s:%u",filename,linenum);
1569 curr = new_avpl(linenum_buf);
1570 continue;
1571 case '#':
1572 state = MY_IGNORE;
1573 continue;
1574 default:
1575 loal_error = load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
1576 goto error;
1577 }
1578 case BEFORE_NAME:
1579 i = 0;
1580 name[0] = '\0';
1581 switch (c) {
1582 case '\\':
1583 c = (char) fgetc(fp);
1584 if (c != '\n') ungetc(c,fp);
1585 continue;
1586 case ' ':
1587 case '\t':
1588 continue;
1589 case AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G'
: case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case
'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T'
:case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case
'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g'
: case 'h': case 'i': case 'j': case 'k': case 'l': case 'm':
case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case
't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z'
: case '_': case '0': case '1': case '2': case '3': case '4':
case '5': case '6':case '7': case '8': case '9': case '.'
:
1590 state = IN_NAME;
1591
1592 name[i++] = c;
1593 name[i] = '\0';
1594 continue;
1595 case '\n':
1596 loal_append(loal,curr);
1597 curr = NULL((void*)0);
1598 state = START;
1599 continue;
1600 default:
1601 loal_error = load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
1602 goto error;
1603 }
1604 case IN_NAME:
1605 switch (c) {
1606 case ';':
1607 state = BEFORE_NAME;
1608
1609 op = '?';
1610 name[i] = '\0';
1611 value[0] = '\0';
1612 i = 0;
1613
1614 avp = new_avp(name,value,op);
1615
1616 if (! insert_avp(curr,avp) ) {
1617 delete_avp(avp);
1618 }
1619
1620 continue;
1621 case AVP_OP_CHAR'=': case '^': case '$': case '~': case '<': case '>': case
'?': case '|': case '&' : case '!'
:
1622 name[i] = '\0';
1623 i = 0;
1624 op = c;
1625 state = IN_VALUE;
1626 continue;
1627 case AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G'
: case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case
'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T'
:case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case
'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g'
: case 'h': case 'i': case 'j': case 'k': case 'l': case 'm':
case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case
't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z'
: case '_': case '0': case '1': case '2': case '3': case '4':
case '5': case '6':case '7': case '8': case '9': case '.'
:
1628 name[i++] = c;
1629 continue;
1630 case '\n':
1631 loal_error = load_loal_error(fp,loal,curr,linenum,"operator expected found new line");
1632 goto error;
1633 default:
1634 loal_error = load_loal_error(fp,loal,curr,linenum,"name or match operator expected found '%c'",c);
1635 goto error;
1636 }
1637 case IN_VALUE:
1638 switch (c) {
1639 case '\\':
1640 value[i++] = (char) fgetc(fp);
1641 continue;
1642 case ';':
1643 state = BEFORE_NAME;
1644
1645 value[i] = '\0';
1646 i = 0;
1647
1648 avp = new_avp(name,value,op);
1649
1650 if (! insert_avp(curr,avp) ) {
1651 delete_avp(avp);
1652 }
1653 continue;
1654 case '\n':
1655 loal_error = load_loal_error(fp,loal,curr,linenum,"';' expected found new line");
1656 goto error;
1657 default:
1658 value[i++] = c;
1659 continue;
1660 }
1661 }
1662 }
1663 fclose (fp);
1664
1665 if (curr) {
1666 // Premature EOF? It could just be a file that doesn't
1667 // end in a newline, but hard to say without checking
1668 // state. Error, discard, add to existing loal?
1669 delete_avpl(curr,true1);
1670 }
1671
1672 g_free(linenum_buf);
1673 g_free(name);
1674 g_free(value);
1675
1676 return loal;
1677
1678 } else {
1679 report_open_failure(filename,errno(*__errno_location ()),false0);
1680 loal_error = load_loal_error(NULL((void*)0),loal,NULL((void*)0),0,"Cannot Open file '%s'",filename);
1681 }
1682
1683error:
1684 g_free(linenum_buf);
1685 g_free(name);
1686 g_free(value);
1687
1688 return loal_error;
1689}