Bug Summary

File:plugins/epan/mate/mate_util.c
Warning:line 1523, column 22
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior

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