blob: ff902a0ebf0345cd2a9e3592f9bf0a0798d7bebd [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Sebastien Decugis <sdecugis@freediameter.net> *
4* *
5* Copyright (c) 2015, WIDE Project and NICT *
6* All rights reserved. *
7* *
8* Redistribution and use of this software in source and binary forms, with or without modification, are *
9* permitted provided that the following conditions are met: *
10* *
11* * Redistributions of source code must retain the above *
12* copyright notice, this list of conditions and the *
13* following disclaimer. *
14* *
15* * Redistributions in binary form must reproduce the above *
16* copyright notice, this list of conditions and the *
17* following disclaimer in the documentation and/or other *
18* materials provided with the distribution. *
19* *
20* * Neither the name of the WIDE Project or NICT nor the *
21* names of its contributors may be used to endorse or *
22* promote products derived from this software without *
23* specific prior written permission of WIDE Project and *
24* NICT. *
25* *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34*********************************************************************************************************/
35
36#include "fdproto-internal.h"
37#include <inttypes.h>
38
39/* Names of the base types */
40const char * type_base_name[] = { /* must keep in sync with dict_avp_basetype */
41 "GROUPED", /* AVP_TYPE_GROUPED */
42 "OCTETSTRING", /* AVP_TYPE_OCTETSTRING */
43 "INTEGER32", /* AVP_TYPE_INTEGER32 */
44 "INTEGER64", /* AVP_TYPE_INTEGER64 */
45 "UNSIGNED32", /* AVP_TYPE_UNSIGNED32 */
46 "UNSIGNED64", /* AVP_TYPE_UNSIGNED64 */
47 "FLOAT32", /* AVP_TYPE_FLOAT32 */
48 "FLOAT64" /* AVP_TYPE_FLOAT64 */
49 };
50
51/* The number of lists in an object */
52#define NB_LISTS_PER_OBJ 3
53
54/* Some eye catchers definitions */
55#define OBJECT_EYECATCHER (0x0b13c7)
56#define DICT_EYECATCHER (0x00d1c7)
57
58/* Definition of the dictionary objects */
59struct dict_object {
60 enum dict_object_type type; /* What type of object is this? */
61 int objeyec;/* eyecatcher for this object */
62 int typeyec;/* eyecatcher for this type of object */
63 struct dictionary *dico; /* The dictionary this object belongs to */
64
65 union {
66 struct dict_vendor_data vendor; /* datastr_len = strlen(vendor_name) */
67 struct dict_application_data application; /* datastr_len = strlen(application_name) */
68 struct dict_type_data type; /* datastr_len = strlen(type_name) */
69 struct dict_enumval_data enumval; /* datastr_len = strlen(enum_name) */
70 struct dict_avp_data avp; /* datastr_len = strlen(avp_name) */
71 struct dict_cmd_data cmd; /* datastr_len = strlen(cmd_name) */
72 struct dict_rule_data rule; /* datastr_len = 0 */
73 } data; /* The data of this object */
74
75 size_t datastr_len; /* cached length of the string inside the data. Saved when the object is created. */
76
77 struct dict_object * parent; /* The parent of this object, if any */
78
79 struct fd_list list[NB_LISTS_PER_OBJ];/* used to chain objects.*/
80 /* More information about the lists :
81
82 - the use for each list depends on the type of object. See detail below.
83
84 - a sentinel for a list has its 'o' field cleared. (this is the criteria to detect end of a loop)
85
86 - The lists are always ordered. The criteria are described below. the functions to order them are referenced in dict_obj_info
87
88 - The dict_lock must be held for any list operation.
89
90 => VENDORS:
91 list[0]: list of the vendors, ordered by their id. The sentinel is g_dict_vendors (vendor with id 0)
92 list[1]: sentinel for the list of AVPs from this vendor, ordered by AVP code.
93 list[2]: sentinel for the list of AVPs from this vendor, ordered by AVP name (fd_os_cmp).
94
95 => APPLICATIONS:
96 list[0]: list of the applications, ordered by their id. The sentinel is g_dict_applications (application with id 0)
97 list[1]: not used
98 list[2]: not used.
99
100 => TYPES:
101 list[0]: list of the types, ordered by their names. The sentinel is g_list_types.
102 list[1]: sentinel for the type_enum list of this type, ordered by their constant name (fd_os_cmp).
103 list[2]: sentinel for the type_enum list of this type, ordered by their constant value.
104
105 => TYPE_ENUMS:
106 list[0]: list of the contants for a given type, ordered by the constant name (fd_os_cmp). Sentinel is a (list[1]) element of a TYPE object.
107 list[1]: list of the contants for a given type, ordered by the constant value. Sentinel is a (list[2]) element of a TYPE object.
108 list[2]: not used
109
110 => AVPS:
111 list[0]: list of the AVP from a given vendor, ordered by avp code. Sentinel is a list[1] element of a VENDOR object.
112 list[1]: list of the AVP from a given vendor, ordered by avp name (fd_os_cmp). Sentinel is a list[2] element of a VENDOR object.
113 list[2]: sentinel for the rule list that apply to this AVP.
114
115 => COMMANDS:
116 list[0]: list of the commands, ordered by their names (fd_os_cmp). The sentinel is g_list_cmd_name.
117 list[1]: list of the commands, ordered by their command code and 'R' flag. The sentinel is g_list_cmd_code.
118 list[2]: sentinel for the rule list that apply to this command.
119
120 => RULES:
121 list[0]: list of the rules for a given (grouped) AVP or Command, ordered by the AVP vendor & code to which they refer. sentinel is list[2] of a command or (grouped) avp.
122 list[1]: not used
123 list[2]: not used.
124
125 */
126
127 /* Sentinel for the dispatch callbacks */
128 struct fd_list disp_cbs;
129
130};
131
132/* Definition of the dictionary structure */
133struct dictionary {
134 int dict_eyec; /* Eye-catcher for the dictionary (DICT_EYECATCHER) */
135
136 pthread_rwlock_t dict_lock; /* The global rwlock for the dictionary */
137
138 struct dict_object dict_vendors; /* Sentinel for the list of vendors, corresponding to vendor 0 */
139 struct dict_object dict_applications; /* Sentinel for the list of applications, corresponding to app 0 */
140 struct fd_list dict_types; /* Sentinel for the list of types */
141 struct fd_list dict_cmd_name; /* Sentinel for the list of commands, ordered by names */
142 struct fd_list dict_cmd_code; /* Sentinel for the list of commands, ordered by codes */
143
144 struct dict_object dict_cmd_error; /* Special command object for answers with the 'E' bit set */
145
146 int dict_count[DICT_TYPE_MAX + 1]; /* Number of objects of each type */
147};
148
149/* Forward declarations of dump functions */
150static DECLARE_FD_DUMP_PROTOTYPE(dump_vendor_data, void * data );
151static DECLARE_FD_DUMP_PROTOTYPE(dump_application_data, void * data );
152static DECLARE_FD_DUMP_PROTOTYPE(dump_type_data, void * data );
153 /* the dump function for enum has a different prototype since it need the datatype */
154static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_data, void * data );
155static DECLARE_FD_DUMP_PROTOTYPE(dump_command_data, void * data );
156static DECLARE_FD_DUMP_PROTOTYPE(dump_rule_data, void * data );
157
158/* Forward declarations of search functions */
159static int search_vendor ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
160static int search_application ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
161static int search_type ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
162static int search_enumval ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
163static int search_avp ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
164static int search_cmd ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
165static int search_rule ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
166
167/* The following array contains lot of data about the different types of objects, for automated handling */
168static struct {
169 enum dict_object_type type; /* information for this type */
170 char * name; /* string describing this object, for debug */
171 size_t datasize; /* The size of the data structure */
172 int parent; /* 0: never; 1: may; 2: must */
173 enum dict_object_type parenttype; /* The type of the parent, when relevant */
174 int eyecatcher; /* A kind of signature for this object */
175 DECLARE_FD_DUMP_PROTOTYPE( (*dump_data), void * data ); /* The function to dump the data section */
176 int (*search_fct)(struct dictionary * dict, int criteria, const void * what, struct dict_object **result );; /* The function to search an object of this type */
177 int haslist[NB_LISTS_PER_OBJ]; /* Tell if this list is used */
178} dict_obj_info[] = { { 0, "(error)", 0, 0, 0, 0, NULL, NULL, {0, 0, 0} }
179
180 /* type name datasize parent parenttype
181 eyecatcher dump_data search_fct, haslist[] */
182
183 ,{ DICT_VENDOR, "VENDOR", sizeof(struct dict_vendor_data), 0, 0,
184 OBJECT_EYECATCHER + 1, dump_vendor_data, search_vendor, { 1, 0, 0 } }
185
186 ,{ DICT_APPLICATION, "APPLICATION", sizeof(struct dict_application_data), 1, DICT_VENDOR,
187 OBJECT_EYECATCHER + 2, dump_application_data, search_application, { 1, 0, 0 } }
188
189 ,{ DICT_TYPE, "TYPE", sizeof(struct dict_type_data), 1, DICT_APPLICATION,
190 OBJECT_EYECATCHER + 3, dump_type_data, search_type, { 1, 0, 0 } }
191
192 ,{ DICT_ENUMVAL, "ENUMVAL", sizeof(struct dict_enumval_data), 2, DICT_TYPE,
193 OBJECT_EYECATCHER + 4, NULL, search_enumval, { 1, 1, 0 } }
194
195 ,{ DICT_AVP, "AVP", sizeof(struct dict_avp_data), 1, DICT_TYPE,
196 OBJECT_EYECATCHER + 5, dump_avp_data, search_avp, { 1, 1, 0 } }
197
198 ,{ DICT_COMMAND, "COMMAND", sizeof(struct dict_cmd_data), 1, DICT_APPLICATION,
199 OBJECT_EYECATCHER + 6, dump_command_data, search_cmd, { 1, 1, 0 } }
200
201 ,{ DICT_RULE, "RULE", sizeof(struct dict_rule_data), 2, -1 /* special case: grouped avp or command */,
202 OBJECT_EYECATCHER + 7, dump_rule_data, search_rule, { 1, 0, 0 } }
203
204};
205
206/* Macro to verify a "type" value */
207#define CHECK_TYPE( type ) ( ((type) > 0) && ((type) <= DICT_TYPE_MAX) )
208
209/* Cast macro */
210#define _O( object ) ((struct dict_object *) (object))
211
212/* Get information line for a given object */
213#define _OBINFO(object) (dict_obj_info[CHECK_TYPE(_O(object)->type) ? _O(object)->type : 0])
214
215
216
217
218/*******************************************************************************************************/
219/*******************************************************************************************************/
220/* */
221/* Objects management */
222/* */
223/*******************************************************************************************************/
224/*******************************************************************************************************/
225
226/* Functions to manage the objects creation and destruction. */
227
228/* Duplicate a string inplace, save its length */
229#define DUP_string_len( str, plen ) { \
230 *(plen) = strlen((str)); \
231 str = os0dup( str, *(plen)); \
232}
233
234/* Initialize an object */
235static void init_object( struct dict_object * obj, enum dict_object_type type )
236{
237 int i;
238
239 TRACE_ENTRY("%p %d", obj, type);
240
241 /* Clean the object first */
242 memset ( obj, 0, sizeof(struct dict_object));
243
244 CHECK_PARAMS_DO( CHECK_TYPE(type), return );
245
246 obj->type = type;
247 obj->objeyec = OBJECT_EYECATCHER;
248 obj->typeyec = _OBINFO(obj).eyecatcher;
249
250 /* We don't initialize the data nor the parent here */
251
252 /* Now init the lists */
253 for (i=0; i<NB_LISTS_PER_OBJ; i++) {
254 if (_OBINFO(obj).haslist[i] != 0)
255 fd_list_init(&obj->list[i], obj);
256 else
257 fd_list_init(&obj->list[i], NULL);
258 }
259
260 fd_list_init(&obj->disp_cbs, NULL);
261}
262
263/* Initialize the "data" part of an object */
264static int init_object_data(struct dict_object * dest, void * source, enum dict_object_type type, int dupos)
265{
266 TRACE_ENTRY("%p %p %d", dest, source, type);
267 CHECK_PARAMS( dest && source && CHECK_TYPE(type) );
268
269 /* Generic: copy the full data structure */
270 memcpy( &dest->data, source, dict_obj_info[type].datasize );
271
272 /* Then strings must be duplicated, not copied */
273 /* This function might be simplified by always defining the "name" field as the first field of the structures, but... it's error-prone */
274 switch (type) {
275 case DICT_VENDOR:
276 DUP_string_len( dest->data.vendor.vendor_name, &dest->datastr_len );
277 break;
278
279 case DICT_APPLICATION:
280 DUP_string_len( dest->data.application.application_name, &dest->datastr_len );
281 break;
282
283 case DICT_TYPE:
284 DUP_string_len( dest->data.type.type_name, &dest->datastr_len );
285 break;
286
287 case DICT_ENUMVAL:
288 DUP_string_len( dest->data.enumval.enum_name, &dest->datastr_len );
289 if (dupos) {
290 // we also need to duplicate the octetstring constant value since it is a pointer.
291 dest->data.enumval.enum_value.os.data = os0dup(
292 ((struct dict_enumval_data *)source)->enum_value.os.data,
293 ((struct dict_enumval_data *)source)->enum_value.os.len
294 );
295 }
296 break;
297
298 case DICT_AVP:
299 DUP_string_len( dest->data.avp.avp_name, &dest->datastr_len );
300 break;
301
302 case DICT_COMMAND:
303 DUP_string_len( dest->data.cmd.cmd_name, &dest->datastr_len );
304 break;
305
306 default:
307 /* Nothing to do for RULES */
308 ;
309 }
310
311 return 0;
312}
313
314/* Check that an object is valid (1: OK, 0: error) */
315static int verify_object( struct dict_object * obj )
316{
317 TRACE_ENTRY("%p", obj);
318
319 CHECK_PARAMS_DO( obj
320 && (obj->objeyec == OBJECT_EYECATCHER)
321 && CHECK_TYPE(obj->type)
322 && (obj->typeyec == dict_obj_info[obj->type].eyecatcher),
323 {
324 if (obj) {
325 TRACE_DEBUG(FULL, "Invalid object: %p, obj->objeyec: %x/%x, obj->type: %d, obj->objeyec: %x/%x, obj->typeyec: %x/%x",
326 obj,
327 obj->objeyec, OBJECT_EYECATCHER,
328 obj->type,
329 obj->objeyec, OBJECT_EYECATCHER,
330 obj->typeyec, _OBINFO(obj).eyecatcher);
331 } else {
332 TRACE_DEBUG(FULL, "Invalid object : NULL pointer");
333 }
334 return 0;
335 } );
336
337 /* The object is probably valid. */
338 return 1;
339}
340
341/* Free the data associated to an object */
342static void destroy_object_data(struct dict_object * obj)
343{
344 /* TRACE_ENTRY("%p", obj); */
345
346 switch (obj->type) {
347 case DICT_VENDOR:
348 free( obj->data.vendor.vendor_name );
349 break;
350
351 case DICT_APPLICATION:
352 free( obj->data.application.application_name );
353 break;
354
355 case DICT_TYPE:
356 free( obj->data.type.type_name );
357 break;
358
359 case DICT_ENUMVAL:
360 free( obj->data.enumval.enum_name );
361 break;
362
363 case DICT_AVP:
364 free( obj->data.avp.avp_name );
365 break;
366
367 case DICT_COMMAND:
368 free( obj->data.cmd.cmd_name );
369 break;
370
371 default:
372 /* nothing to do */
373 ;
374 }
375}
376
377/* Forward declaration */
378static void destroy_object(struct dict_object * obj);
379
380/* Destroy all objects in a list - the lock must be held */
381static void destroy_list(struct fd_list * head)
382{
383 /* TRACE_ENTRY("%p", head); */
384
385 /* loop in the list */
386 while (!FD_IS_LIST_EMPTY(head))
387 {
388 /* When destroying the object, it is unlinked from the list */
389 destroy_object(_O(head->next->o));
390 }
391}
392
393/* Free an object and its sublists */
394static void destroy_object(struct dict_object * obj)
395{
396 int i;
397
398 /* TRACE_ENTRY("%p", obj); */
399
400 /* Update global count */
401 if (obj->dico)
402 obj->dico->dict_count[obj->type]--;
403
404 /* Mark the object as invalid */
405 obj->objeyec = 0xdead;
406
407 /* First, destroy the data associated to the object */
408 destroy_object_data(obj);
409
410 for (i=0; i<NB_LISTS_PER_OBJ; i++) {
411 if (_OBINFO(obj).haslist[i])
412 /* unlink the element from the list */
413 fd_list_unlink( &obj->list[i] );
414 else
415 /* This is either a sentinel or unused (=emtpy) list, let's destroy it */
416 destroy_list( &obj->list[i] );
417 }
418
419 /* Unlink all elements from the dispatch list; they will be freed when callback is unregistered */
420 CHECK_POSIX_DO( pthread_rwlock_wrlock(&fd_disp_lock), /* continue */ );
421 while (!FD_IS_LIST_EMPTY(&obj->disp_cbs)) {
422 fd_list_unlink( obj->disp_cbs.next );
423 }
424 CHECK_POSIX_DO( pthread_rwlock_unlock(&fd_disp_lock), /* continue */ );
425
426 /* Last, destroy the object */
427 free(obj);
428}
429
430/*******************************************************************************************************/
431/*******************************************************************************************************/
432/* */
433/* Compare functions */
434/* */
435/*******************************************************************************************************/
436/*******************************************************************************************************/
437
438/* Compare two values */
439#define ORDER_scalar( i1, i2 ) \
440 ((i1 < i2 ) ? -1 : ( i1 > i2 ? 1 : 0 ))
441
442
443/* Compare two vendor objects by their id (checks already performed) */
444static int order_vendor_by_id ( struct dict_object *o1, struct dict_object *o2 )
445{
446 TRACE_ENTRY("%p %p", o1, o2);
447
448 return ORDER_scalar( o1->data.vendor.vendor_id, o2->data.vendor.vendor_id );
449}
450
451/* Compare two application objects by their id (checks already performed) */
452static int order_appli_by_id ( struct dict_object *o1, struct dict_object *o2 )
453{
454 TRACE_ENTRY("%p %p", o1, o2);
455
456 return ORDER_scalar( o1->data.application.application_id, o2->data.application.application_id );
457}
458
459/* Compare two type objects by their name (checks already performed) */
460static int order_type_by_name ( struct dict_object *o1, struct dict_object *o2 )
461{
462 TRACE_ENTRY("%p %p", o1, o2);
463
464 return fd_os_cmp( o1->data.type.type_name, o1->datastr_len, o2->data.type.type_name, o2->datastr_len );
465}
466
467/* Compare two type_enum objects by their names (checks already performed) */
468static int order_enum_by_name ( struct dict_object *o1, struct dict_object *o2 )
469{
470 TRACE_ENTRY("%p %p", o1, o2);
471
472 return fd_os_cmp( o1->data.enumval.enum_name, o1->datastr_len, o2->data.enumval.enum_name, o2->datastr_len );
473}
474
475/* Compare two type_enum objects by their values (checks already performed) */
476static int order_enum_by_val ( struct dict_object *o1, struct dict_object *o2 )
477{
478 TRACE_ENTRY("%p %p", o1, o2);
479
480 /* The comparison function depends on the type of data */
481 switch ( o1->parent->data.type.type_base ) {
482 case AVP_TYPE_OCTETSTRING:
483 return fd_os_cmp( o1->data.enumval.enum_value.os.data, o1->data.enumval.enum_value.os.len,
484 o2->data.enumval.enum_value.os.data, o2->data.enumval.enum_value.os.len);
485
486 case AVP_TYPE_INTEGER32:
487 return ORDER_scalar( o1->data.enumval.enum_value.i32, o2->data.enumval.enum_value.i32 );
488
489 case AVP_TYPE_INTEGER64:
490 return ORDER_scalar( o1->data.enumval.enum_value.i64, o2->data.enumval.enum_value.i64 );
491
492 case AVP_TYPE_UNSIGNED32:
493 return ORDER_scalar( o1->data.enumval.enum_value.u32, o2->data.enumval.enum_value.u32 );
494
495 case AVP_TYPE_UNSIGNED64:
496 return ORDER_scalar( o1->data.enumval.enum_value.u64, o2->data.enumval.enum_value.u64 );
497
498 case AVP_TYPE_FLOAT32:
499 return ORDER_scalar( o1->data.enumval.enum_value.f32, o2->data.enumval.enum_value.f32 );
500
501 case AVP_TYPE_FLOAT64:
502 return ORDER_scalar( o1->data.enumval.enum_value.f64, o2->data.enumval.enum_value.f64 );
503
504 case AVP_TYPE_GROUPED:
505 default:
506 ASSERT(0);
507 }
508 return 0;
509}
510
511/* Compare two avp objects by their codes (checks already performed) */
512static int order_avp_by_code ( struct dict_object *o1, struct dict_object *o2 )
513{
514 TRACE_ENTRY("%p %p", o1, o2);
515
516 return ORDER_scalar( o1->data.avp.avp_code, o2->data.avp.avp_code );
517}
518
519/* Compare two avp objects by their names (checks already performed) */
520static int order_avp_by_name ( struct dict_object *o1, struct dict_object *o2 )
521{
522 TRACE_ENTRY("%p %p", o1, o2);
523
524 return fd_os_cmp( o1->data.avp.avp_name, o1->datastr_len, o2->data.avp.avp_name, o2->datastr_len );
525}
526
527/* Compare two command objects by their names (checks already performed) */
528static int order_cmd_by_name ( struct dict_object *o1, struct dict_object *o2 )
529{
530 TRACE_ENTRY("%p %p", o1, o2);
531
532 return fd_os_cmp( o1->data.cmd.cmd_name, o1->datastr_len, o2->data.cmd.cmd_name, o2->datastr_len );
533}
534
535/* Compare two command objects by their codes and flags (request or answer) (checks already performed) */
536static int order_cmd_by_codefl( struct dict_object *o1, struct dict_object *o2 )
537{
538 uint8_t fl1, fl2;
539 int cmp = 0;
540
541 TRACE_ENTRY("%p %p", o1, o2);
542
543 cmp = ORDER_scalar( o1->data.cmd.cmd_code, o2->data.cmd.cmd_code );
544 if (cmp)
545 return cmp;
546
547 /* Same command code, we must compare the value of the 'R' flag */
548 fl1 = o1->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST;
549 fl2 = o2->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST;
550
551 /* We want requests first, so we reverse the operators here */
552 return ORDER_scalar(fl2, fl1);
553
554}
555
556/* Compare two rule object by the AVP vendor & code that they refer (checks already performed) */
557static int order_rule_by_avpvc ( struct dict_object *o1, struct dict_object *o2 )
558{
559 TRACE_ENTRY("%p %p", o1, o2);
560
561 return ORDER_scalar(o1->data.rule.rule_avp->data.avp.avp_vendor, o2->data.rule.rule_avp->data.avp.avp_vendor)
562 ?: ORDER_scalar(o1->data.rule.rule_avp->data.avp.avp_code, o2->data.rule.rule_avp->data.avp.avp_code) ;
563}
564
565/*******************************************************************************************************/
566/*******************************************************************************************************/
567/* */
568/* Search functions */
569/* */
570/*******************************************************************************************************/
571/*******************************************************************************************************/
572
573/* Functions used to search for objects in the lists, according to some criteria */
574
575/* On a general note, if result is not NULL, ENOENT is not returned but *result is NULL. */
576
577/* The following macros assume that "what", "ret", "result" (variables), and "end" (label) exist
578in the local context where they are called. They are meant to be called only from the functions that follow. */
579
580/* For searchs of type "xxx_OF_xxx": children's parent or default parent */
581#define SEARCH_childs_parent( type_of_child, default_parent ) { \
582 struct dict_object *__child = (struct dict_object *) what; \
583 CHECK_PARAMS_DO( verify_object(__child) && \
584 (__child->type == (type_of_child)), \
585 { ret = EINVAL; goto end; } ); \
586 ret = 0; \
587 if (result) \
588 *result = (__child->parent ? __child->parent :(default_parent));\
589}
590
591/* For search of strings in lists. isindex= 1 if the string is the ordering key of the list */
592/* it is expected that object->datastr_len is the length of the datafield parameter */
593#define SEARCH_os0_l( str, len, sentinel, datafield, isindex ) { \
594 char * __str = (char *) (str); \
595 size_t __strlen = (size_t)(len); \
596 int __cmp; \
597 struct fd_list * __li; \
598 ret = 0; \
599 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \
600 __cmp = fd_os_cmp(__str, __strlen, \
601 _O(__li->o)->data. datafield, _O(__li->o)->datastr_len);\
602 if (__cmp == 0) { \
603 if (result) \
604 *result = _O(__li->o); \
605 goto end; \
606 } \
607 if ((isindex) && (__cmp < 0)) \
608 break; \
609 } \
610 if (result) \
611 *result = NULL; \
612 else \
613 ret = ENOENT; \
614}
615
616/* When len is not provided */
617#define SEARCH_os0( str, sentinel, datafield, isindex ) { \
618 char * _str = (char *) (str); \
619 size_t _strlen = strlen(_str); \
620 SEARCH_os0_l( _str, _strlen, sentinel, datafield, isindex ); \
621}
622
623
624/* For search of octetstrings in lists. */
625#define SEARCH_os( str, strlen, sentinel, osdatafield, isindex ) { \
626 uint8_t * __str = (uint8_t *) (str); \
627 size_t __strlen = (size_t)(strlen); \
628 int __cmp; \
629 struct fd_list * __li; \
630 ret = 0; \
631 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \
632 __cmp = fd_os_cmp(__str, __strlen, \
633 _O(__li->o)->data. osdatafield .data, \
634 _O(__li->o)->data. osdatafield .len); \
635 if (__cmp == 0) { \
636 if (result) \
637 *result = _O(__li->o); \
638 goto end; \
639 } \
640 if ((isindex) && (__cmp < 0)) \
641 break; \
642 } \
643 if (result) \
644 *result = NULL; \
645 else \
646 ret = ENOENT; \
647}
648
649/* For search of AVP name in rule lists -- the list is not ordered by AVP names! */
650#define SEARCH_ruleavpname( str, strlen, sentinel ) { \
651 char * __str = (char *) (str); \
652 size_t __strlen = (size_t) (strlen); \
653 int __cmp; \
654 struct fd_list * __li; \
655 ret = 0; \
656 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \
657 __cmp = fd_os_cmp(__str, __strlen, \
658 _O(__li->o)->data.rule.rule_avp->data.avp.avp_name, \
659 _O(__li->o)->data.rule.rule_avp->datastr_len); \
660 if (__cmp == 0) { \
661 if (result) \
662 *result = _O(__li->o); \
663 goto end; \
664 } \
665 } \
666 if (result) \
667 *result = NULL; \
668 else \
669 ret = ENOENT; \
670}
671
672/* For search of scalars in lists. isindex= 1 if the value is the ordering key of the list */
673#define SEARCH_scalar( value, sentinel, datafield, isindex, defaultobj ) { \
674 int __cmp; \
675 struct fd_list * __li; \
676 ret = 0; \
677 if ( ((defaultobj) != NULL) \
678 && (_O(defaultobj)->data. datafield == value)) { \
679 if (result) \
680 *result = _O(defaultobj); \
681 goto end; \
682 } \
683 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \
684 __cmp= ORDER_scalar(value, _O(__li->o)->data. datafield ); \
685 if (__cmp == 0) { \
686 if (result) \
687 *result = _O(__li->o); \
688 goto end; \
689 } \
690 if ((isindex) && (__cmp < 0)) \
691 break; \
692 } \
693 if (result) \
694 *result = NULL; \
695 else \
696 ret = ENOENT; \
697}
698
699/* For search of commands in lists by code and flag. R_flag_val = 0 or CMD_FLAG_REQUEST */
700#define SEARCH_codefl( value, R_flag_val, sentinel) { \
701 int __cmp; \
702 struct fd_list * __li; \
703 ret = 0; \
704 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \
705 __cmp = ORDER_scalar(value, \
706 _O(__li->o)->data.cmd.cmd_code ); \
707 if (__cmp == 0) { \
708 uint8_t __mask, __val; \
709 __mask = _O(__li->o)->data.cmd.cmd_flag_mask; \
710 __val = _O(__li->o)->data.cmd.cmd_flag_val; \
711 if ( ! (__mask & CMD_FLAG_REQUEST) ) \
712 continue; \
713 if ( ( __val & CMD_FLAG_REQUEST ) != R_flag_val ) \
714 continue; \
715 if (result) \
716 *result = _O(__li->o); \
717 goto end; \
718 } \
719 if (__cmp < 0) \
720 break; \
721 } \
722 if (result) \
723 *result = NULL; \
724 else \
725 ret = ENOENT; \
726}
727
728/* For searchs of type "xxx_OF_xxx": if the search object is sentinel list for the "what" object */
729#define SEARCH_sentinel( type_of_what, what_list_nr, sentinel_list_nr ) { \
730 struct dict_object *__what = (struct dict_object *) what; \
731 CHECK_PARAMS_DO( verify_object(__what) && \
732 (__what->type == (type_of_what)), \
733 { ret = EINVAL; goto end; } ); \
734 ret = 0; \
735 if (result) { \
736 /* this is similar to the "container_of" */ \
737 *result = (struct dict_object *)((char *)(__what->list[what_list_nr].head) - \
738 (size_t)&(((struct dict_object *)0)->list[sentinel_list_nr])); \
739 } \
740}
741
742
743static int search_vendor ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
744{
745 int ret = 0;
746 vendor_id_t id;
747
748 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
749
750 switch (criteria) {
751 case VENDOR_BY_ID:
752 id = *(vendor_id_t *) what;
753 SEARCH_scalar( id, &dict->dict_vendors.list[0], vendor.vendor_id, 1, &dict->dict_vendors );
754 break;
755
756 case VENDOR_BY_NAME:
757 /* "what" is a vendor name */
758 SEARCH_os0( what, &dict->dict_vendors.list[0], vendor.vendor_name, 0);
759 break;
760
761 case VENDOR_OF_APPLICATION:
762 /* "what" should be an application object */
763 SEARCH_childs_parent( DICT_APPLICATION, &dict->dict_vendors );
764 break;
765
766 case VENDOR_OF_AVP:
767 /* "what" should be an avp object */
768 SEARCH_sentinel( DICT_AVP, 0, 1 );
769 break;
770
771 default:
772 /* Invalid criteria */
773 CHECK_PARAMS( criteria = 0 );
774 }
775end:
776 return ret;
777}
778
779static int search_application ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
780{
781 int ret = 0;
782 application_id_t id;
783
784 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
785
786 switch (criteria) {
787 case APPLICATION_BY_ID:
788 id = *(application_id_t *) what;
789
790 SEARCH_scalar( id, &dict->dict_applications.list[0], application.application_id, 1, &dict->dict_applications );
791 break;
792
793 case APPLICATION_BY_NAME:
794 /* "what" is an application name */
795 SEARCH_os0( what, &dict->dict_applications.list[0], application.application_name, 0);
796 break;
797
798 case APPLICATION_OF_TYPE:
799 /* "what" should be a type object */
800 SEARCH_childs_parent( DICT_TYPE, &dict->dict_applications );
801 break;
802
803 case APPLICATION_OF_COMMAND:
804 /* "what" should be a command object */
805 SEARCH_childs_parent( DICT_COMMAND, &dict->dict_applications );
806 break;
807
808 default:
809 /* Invalid criteria */
810 CHECK_PARAMS( criteria = 0 );
811 }
812end:
813 return ret;
814}
815
816static int search_type ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
817{
818 int ret = 0;
819
820 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
821
822 switch (criteria) {
823 case TYPE_BY_NAME:
824 /* "what" is a type name */
825 SEARCH_os0( what, &dict->dict_types, type.type_name, 1);
826 break;
827
828 case TYPE_OF_ENUMVAL:
829 /* "what" should be a type_enum object */
830 SEARCH_childs_parent( DICT_ENUMVAL, NULL );
831 break;
832
833 case TYPE_OF_AVP:
834 /* "what" should be an avp object */
835 SEARCH_childs_parent( DICT_AVP, NULL );
836 break;
837
838
839 default:
840 /* Invalid criteria */
841 CHECK_PARAMS( criteria = 0 );
842 }
843end:
844 return ret;
845}
846
847static int search_enumval ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
848{
849 int ret = 0;
850
851 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
852
853 switch (criteria) {
854 case ENUMVAL_BY_STRUCT:
855 {
856 struct dict_object * parent = NULL;
857 struct dict_enumval_request * _what = (struct dict_enumval_request *) what;
858
859 CHECK_PARAMS( _what && ( _what->type_obj || _what->type_name ) );
860
861 if (_what->type_obj != NULL) {
862 parent = _what->type_obj;
863 CHECK_PARAMS( verify_object(parent) && (parent->type == DICT_TYPE) );
864 } else {
865 /* We received only the type name, we must find it first */
866 CHECK_FCT_DO( search_type( dict, TYPE_BY_NAME, _what->type_name, &parent ),
867 CHECK_PARAMS( 0 ) );
868 }
869
870 /* From here the "parent" object is valid */
871
872 if ( _what->search.enum_name != NULL ) {
873 /* We are looking for this string */
874 SEARCH_os0( _what->search.enum_name, &parent->list[1], enumval.enum_name, 1 );
875 } else {
876 /* We are looking for the value in enum_value */
877 switch (parent->data.type.type_base) {
878 case AVP_TYPE_OCTETSTRING:
879 SEARCH_os( _what->search.enum_value.os.data,
880 _what->search.enum_value.os.len,
881 &parent->list[2],
882 enumval.enum_value.os ,
883 1 );
884 break;
885
886 case AVP_TYPE_INTEGER32:
887 SEARCH_scalar( _what->search.enum_value.i32,
888 &parent->list[2],
889 enumval.enum_value.i32,
890 1,
891 (struct dict_object *)NULL);
892 break;
893
894 case AVP_TYPE_INTEGER64:
895 SEARCH_scalar( _what->search.enum_value.i64,
896 &parent->list[2],
897 enumval.enum_value.i64,
898 1,
899 (struct dict_object *)NULL);
900 break;
901
902 case AVP_TYPE_UNSIGNED32:
903 SEARCH_scalar( _what->search.enum_value.u32,
904 &parent->list[2],
905 enumval.enum_value.u32,
906 1,
907 (struct dict_object *)NULL);
908 break;
909
910 case AVP_TYPE_UNSIGNED64:
911 SEARCH_scalar( _what->search.enum_value.u64,
912 &parent->list[2],
913 enumval.enum_value.u64,
914 1,
915 (struct dict_object *)NULL);
916 break;
917
918 case AVP_TYPE_FLOAT32:
919 SEARCH_scalar( _what->search.enum_value.f32,
920 &parent->list[2],
921 enumval.enum_value.f32,
922 1,
923 (struct dict_object *)NULL);
924 break;
925
926 case AVP_TYPE_FLOAT64:
927 SEARCH_scalar( _what->search.enum_value.f64,
928 &parent->list[2],
929 enumval.enum_value.f64,
930 1,
931 (struct dict_object *)NULL);
932 break;
933
934 default:
935 /* Invalid parent type basetype */
936 CHECK_PARAMS( parent = NULL );
937 }
938 }
939
940 }
941 break;
942
943
944 default:
945 /* Invalid criteria */
946 CHECK_PARAMS( criteria = 0 );
947 }
948end:
949 return ret;
950}
951
952static int search_avp ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
953{
954 int ret = 0;
955
956 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
957
958 switch (criteria) {
959 case AVP_BY_CODE:
960 {
961 avp_code_t code;
962 code = *(avp_code_t *) what;
963
964 SEARCH_scalar( code, &dict->dict_vendors.list[1], avp.avp_code, 1, (struct dict_object *)NULL );
965 }
966 break;
967
968 case AVP_BY_NAME:
969 /* "what" is the AVP name, vendor 0 */
970 SEARCH_os0( what, &dict->dict_vendors.list[2], avp.avp_name, 1);
971 break;
972
973 case AVP_BY_CODE_AND_VENDOR:
974 case AVP_BY_NAME_AND_VENDOR:
975 {
976 struct dict_avp_request * _what = (struct dict_avp_request *) what;
977 struct dict_object * vendor = NULL;
978
979 CHECK_PARAMS( (criteria != AVP_BY_NAME_AND_VENDOR) || _what->avp_name );
980
981 /* Now look for the vendor first */
982 CHECK_FCT( search_vendor( dict, VENDOR_BY_ID, &_what->avp_vendor, &vendor ) );
983 if (vendor == NULL) {
984 if (result)
985 *result = NULL;
986 else
987 ret = ENOENT;
988 goto end;
989 }
990
991 /* We now have our vendor = head of the appropriate avp list */
992 if (criteria == AVP_BY_NAME_AND_VENDOR) {
993 SEARCH_os0( _what->avp_name, &vendor->list[2], avp.avp_name, 1);
994 } else {
995 /* AVP_BY_CODE_AND_VENDOR */
996 SEARCH_scalar( _what->avp_code, &vendor->list[1], avp.avp_code, 1, (struct dict_object *)NULL );
997 }
998 }
999 break;
1000
1001 case AVP_BY_STRUCT:
1002 {
1003 struct dict_avp_request_ex * _what = (struct dict_avp_request_ex *) what;
1004 struct dict_object * vendor = NULL;
1005
1006 CHECK_PARAMS( _what->avp_vendor.vendor || _what->avp_vendor.vendor_id || _what->avp_vendor.vendor_name );
1007 CHECK_PARAMS( _what->avp_data.avp_code || _what->avp_data.avp_name );
1008
1009 /* Now look for the vendor first */
1010 if (_what->avp_vendor.vendor) {
1011 CHECK_PARAMS( ! _what->avp_vendor.vendor_id && ! _what->avp_vendor.vendor_name );
1012 vendor = _what->avp_vendor.vendor;
1013 } else if (_what->avp_vendor.vendor_id) {
1014 CHECK_PARAMS( ! _what->avp_vendor.vendor_name );
1015 CHECK_FCT( search_vendor( dict, VENDOR_BY_ID, &_what->avp_vendor.vendor_id, &vendor ) );
1016 } else {
1017 CHECK_FCT( search_vendor( dict, VENDOR_BY_NAME, _what->avp_vendor.vendor_name, &vendor ) );
1018 }
1019
1020 if (vendor == NULL) {
1021 if (result)
1022 *result = NULL;
1023 else
1024 ret = ENOENT;
1025 goto end;
1026 }
1027
1028 /* We now have our vendor = head of the appropriate avp list */
1029 if (_what->avp_data.avp_code) {
1030 CHECK_PARAMS( ! _what->avp_data.avp_name );
1031 SEARCH_scalar( _what->avp_data.avp_code, &vendor->list[1], avp.avp_code, 1, (struct dict_object *)NULL );
1032 } else {
1033 SEARCH_os0( _what->avp_data.avp_name, &vendor->list[2], avp.avp_name, 1);
1034 }
1035 }
1036 break;
1037
1038 case AVP_BY_NAME_ALL_VENDORS:
1039 {
1040 struct fd_list * li;
1041 size_t wl = strlen((char *)what);
1042
1043 /* First, search for vendor 0 */
1044 SEARCH_os0_l( what, wl, &dict->dict_vendors.list[2], avp.avp_name, 1);
1045
1046 /* If not found, loop for all vendors, until found */
1047 for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next) {
1048 SEARCH_os0_l( what, wl, &_O(li->o)->list[2], avp.avp_name, 1);
1049 }
1050 }
1051 break;
1052
1053 default:
1054 /* Invalid criteria */
1055 CHECK_PARAMS( criteria = 0 );
1056 }
1057end:
1058 return ret;
1059}
1060
1061static int search_cmd ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
1062{
1063 int ret = 0;
1064
1065 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
1066
1067 switch (criteria) {
1068 case CMD_BY_NAME:
1069 /* "what" is a command name */
1070 SEARCH_os0( what, &dict->dict_cmd_name, cmd.cmd_name, 1);
1071 break;
1072
1073 case CMD_BY_CODE_R:
1074 case CMD_BY_CODE_A:
1075 {
1076 command_code_t code;
1077 uint8_t searchfl = 0;
1078
1079 /* The command code that we are searching */
1080 code = *(command_code_t *) what;
1081
1082 /* The flag (request or answer) of the command we are searching */
1083 if (criteria == CMD_BY_CODE_R) {
1084 searchfl = CMD_FLAG_REQUEST;
1085 }
1086
1087 /* perform the search */
1088 SEARCH_codefl( code, searchfl, &dict->dict_cmd_code );
1089 }
1090 break;
1091
1092 case CMD_ANSWER:
1093 {
1094 /* "what" is a command object of type "request" */
1095 struct dict_object * req = (struct dict_object *) what;
1096 struct dict_object * ans = NULL;
1097
1098 CHECK_PARAMS( verify_object(req)
1099 && (req->type == DICT_COMMAND)
1100 && (req->data.cmd.cmd_flag_mask & CMD_FLAG_REQUEST)
1101 && (req->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST) );
1102
1103 /* The answer is supposed to be the next element in the list, if it exists */
1104 ans = req->list[1].next->o;
1105 if ( ans == NULL ) {
1106 TRACE_DEBUG( FULL, "the request was the last element in the list" );
1107 ret = ENOENT;
1108 goto end;
1109 }
1110
1111 /* Now check that the ans element is really the correct one */
1112 if ( (ans->data.cmd.cmd_code != req->data.cmd.cmd_code)
1113 || (!(ans->data.cmd.cmd_flag_mask & CMD_FLAG_REQUEST))
1114 || ( ans->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST ) ) {
1115 TRACE_DEBUG( FULL, "the answer does not follow the request in the list" );
1116 ret = ENOENT;
1117 goto end;
1118 }
1119
1120 if (result)
1121 *result = ans;
1122 ret = 0;
1123 }
1124 break;
1125
1126 default:
1127 /* Invalid criteria */
1128 CHECK_PARAMS( criteria = 0 );
1129 }
1130end:
1131 return ret;
1132}
1133
1134static int search_rule ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
1135{
1136 int ret = 0;
1137
1138 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
1139
1140 switch (criteria) {
1141 case RULE_BY_AVP_AND_PARENT:
1142 {
1143 struct dict_object * parent = NULL;
1144 struct dict_object * avp = NULL;
1145 struct dict_rule_request * _what = (struct dict_rule_request *) what;
1146
1147 CHECK_PARAMS( _what
1148 && (parent = _what->rule_parent)
1149 && (avp = _what->rule_avp ) );
1150
1151 CHECK_PARAMS( verify_object(parent)
1152 && ((parent->type == DICT_COMMAND)
1153 || ((parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED))) );
1154
1155 CHECK_PARAMS( verify_object(avp) && (avp->type == DICT_AVP) );
1156
1157 /* Perform the search */
1158 SEARCH_ruleavpname( avp->data.avp.avp_name, avp->datastr_len, &parent->list[2]);
1159
1160 }
1161 break;
1162
1163 default:
1164 /* Invalid criteria */
1165 CHECK_PARAMS( criteria = 0 );
1166 }
1167end:
1168 return ret;
1169}
1170
1171/*******************************************************************************************************/
1172/*******************************************************************************************************/
1173/* */
1174/* Dump / debug functions */
1175/* */
1176/*******************************************************************************************************/
1177/*******************************************************************************************************/
1178/* The following functions are used to debug the module, and allow to print out the content of the dictionary */
1179static DECLARE_FD_DUMP_PROTOTYPE(dump_vendor_data, void * data )
1180{
1181 struct dict_vendor_data * vendor = (struct dict_vendor_data *)data;
1182
1183 return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-6u \"%s\"", vendor->vendor_id, vendor->vendor_name);
1184}
1185static DECLARE_FD_DUMP_PROTOTYPE(dump_application_data, void * data )
1186{
1187 struct dict_application_data * appli = (struct dict_application_data *) data;
1188 return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-6u \"%s\"", appli->application_id, appli->application_name);
1189}
1190static DECLARE_FD_DUMP_PROTOTYPE(dump_type_data, void * data )
1191{
1192 struct dict_type_data * type = ( struct dict_type_data * ) data;
1193
1194 return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-12s \"%s\"",
1195 type_base_name[type->type_base],
1196 type->type_name);
1197}
1198static DECLARE_FD_DUMP_PROTOTYPE(dump_enumval_data, struct dict_enumval_data * enumval, enum dict_avp_basetype type )
1199{
1200 const int LEN_MAX = 20;
1201 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "data: (%-12s) \"%s\" -> ", type_base_name[type], enumval->enum_name), return NULL);
1202 switch (type) {
1203 case AVP_TYPE_OCTETSTRING:
1204 {
1205 int i, n=LEN_MAX;
1206 if (enumval->enum_value.os.len < LEN_MAX)
1207 n = enumval->enum_value.os.len;
1208 for (i=0; i < n; i++)
1209 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "0x%2hhX/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i])), return NULL);
1210 if (n == LEN_MAX)
1211 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "..."), return NULL);
1212 }
1213 break;
1214
1215 case AVP_TYPE_INTEGER32:
1216 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%i", enumval->enum_value.i32), return NULL);
1217 break;
1218
1219 case AVP_TYPE_INTEGER64:
1220 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%"PRId64, enumval->enum_value.i64), return NULL);
1221 break;
1222
1223 case AVP_TYPE_UNSIGNED32:
1224 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%u", enumval->enum_value.u32), return NULL);
1225 break;
1226
1227 case AVP_TYPE_UNSIGNED64:
1228 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%"PRIu64, enumval->enum_value.u64), return NULL);
1229 break;
1230
1231 case AVP_TYPE_FLOAT32:
1232 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%f", enumval->enum_value.f32), return NULL);
1233 break;
1234
1235 case AVP_TYPE_FLOAT64:
1236 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%g", enumval->enum_value.f64), return NULL);
1237 break;
1238
1239 default:
1240 CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "??? (ERROR unknown type %d)", type), return NULL);
1241 }
1242 return *buf;
1243}
1244static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_data, void * data )
1245{
1246 struct dict_avp_data * avp = (struct dict_avp_data * ) data;
1247 return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %-6u \"%s\"",
1248 DUMP_AVPFL_val(avp->avp_flag_val),
1249 DUMP_AVPFL_val(avp->avp_flag_mask),
1250 type_base_name[avp->avp_basetype],
1251 avp->avp_code,
1252 avp->avp_name );
1253}
1254static DECLARE_FD_DUMP_PROTOTYPE(dump_command_data, void * data )
1255{
1256 struct dict_cmd_data * cmd = (struct dict_cmd_data *) data;
1257 return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %-6u \"%s\"",
1258 DUMP_CMDFL_val(cmd->cmd_flag_val), DUMP_CMDFL_val(cmd->cmd_flag_mask), cmd->cmd_code, cmd->cmd_name);
1259}
1260static DECLARE_FD_DUMP_PROTOTYPE(dump_rule_data, void * data )
1261{
1262 struct dict_rule_data * rule = (struct dict_rule_data * )data;
1263 return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: pos:%d ord:%d m/M:%2d/%2d avp:\"%s\"",
1264 rule->rule_position,
1265 rule->rule_order,
1266 rule->rule_min,
1267 rule->rule_max,
1268 rule->rule_avp->data.avp.avp_name);
1269}
1270
1271static DECLARE_FD_DUMP_PROTOTYPE(dump_object, struct dict_object * obj, int parents, int depth, int indent );
1272
1273static DECLARE_FD_DUMP_PROTOTYPE(dump_list, struct fd_list * sentinel, int parents, int depth, int indent )
1274{
1275 struct fd_list * li = sentinel;
1276 /* We don't lock here, the caller must have taken the dictionary lock for reading already */
1277 if (FD_IS_LIST_EMPTY(sentinel)) {
1278 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*s{empty list}", indent, ""), return NULL);
1279 } else {
1280 while (li->next != sentinel)
1281 {
1282 li = li->next;
1283 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
1284 CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, _O(li->o), parents, depth, indent ), return NULL);
1285 }
1286 }
1287 return *buf;
1288}
1289
1290static DECLARE_FD_DUMP_PROTOTYPE(dump_object, struct dict_object * obj, int parents, int depth, int indent )
1291{
1292 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{dictobj}(@%p): ", indent, "", obj), return NULL);
1293
1294 if (!verify_object(obj)) {
1295 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
1296 return *buf;
1297 }
1298
1299 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s p:%p ",
1300 _OBINFO(obj).name,
1301 obj->parent), return NULL);
1302
1303 if (obj->type == DICT_ENUMVAL) {
1304 CHECK_MALLOC_DO( dump_enumval_data ( FD_DUMP_STD_PARAMS, &obj->data.enumval, obj->parent->data.type.type_base ), return NULL);
1305 } else {
1306 CHECK_MALLOC_DO( _OBINFO(obj).dump_data(FD_DUMP_STD_PARAMS, &obj->data), return NULL);
1307 }
1308
1309 if (parents) {
1310 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*sparent:", indent + 1, ""), return NULL);
1311 CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, obj->parent, parents-1, 0, 0 ), return NULL);
1312 }
1313
1314 if (depth) {
1315 int i;
1316 for (i=0; i<NB_LISTS_PER_OBJ; i++) {
1317 if ((obj->list[i].o == NULL) && (obj->list[i].next != &obj->list[i])) {
1318 CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &obj->list[i], 0, depth - 1, indent + 2), return NULL);
1319 break; /* we get duplicate information sorted by another criteria otherwise, which is not very useful */
1320 }
1321 }
1322 }
1323
1324 return *buf;
1325}
1326
1327DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_object, struct dict_object * obj)
1328{
1329 FD_DUMP_HANDLE_OFFSET();
1330
1331 CHECK_MALLOC_DO( dump_object(FD_DUMP_STD_PARAMS, obj, 1, 2, 0), return NULL);
1332
1333 return *buf;
1334}
1335
1336DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump, struct dictionary * dict)
1337{
1338 int i;
1339 struct fd_list * li;
1340
1341 FD_DUMP_HANDLE_OFFSET();
1342
1343 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{dictionary}(@%p): ", dict), return NULL);
1344
1345 if ((dict == NULL) || (dict->dict_eyec != DICT_EYECATCHER)) {
1346 return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL");
1347 }
1348
1349 CHECK_POSIX_DO( pthread_rwlock_rdlock( &dict->dict_lock ), /* ignore */ );
1350
1351 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : VENDORS / AVP / RULES}\n", dict), goto error);
1352 CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, &dict->dict_vendors, 0, 3, 3 ), goto error);
1353 for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next) {
1354 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
1355 CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 3, 3 ), goto error);
1356 }
1357
1358 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : APPLICATIONS}\n", dict), goto error);
1359 CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, &dict->dict_applications, 0, 1, 3 ), goto error);
1360 for (li = dict->dict_applications.list[0].next; li != &dict->dict_applications.list[0]; li = li->next) {
1361 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
1362 CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 1, 3 ), goto error);
1363 }
1364
1365 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : TYPES / ENUMVAL}", dict), goto error);
1366 CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_types, 0, 2, 3 ), goto error);
1367
1368 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : COMMANDS / RULES}", dict), goto error);
1369 CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_cmd_code, 0, 0, 3 ), goto error);
1370
1371 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : statistics}", dict), goto error);
1372 for (i=1; i<=DICT_TYPE_MAX; i++)
1373 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n %5d: %s", dict->dict_count[i], dict_obj_info[i].name), goto error);
1374
1375 CHECK_POSIX_DO( pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */ );
1376 return *buf;
1377error:
1378 /* Free the rwlock */
1379 CHECK_POSIX_DO( pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */ );
1380 return NULL;
1381}
1382
1383/**************************** Dump AVP values ********************************/
1384
1385/* Default dump functions */
1386static DECLARE_FD_DUMP_PROTOTYPE(dump_val_os, union avp_value * value)
1387{
1388 int i;
1389
1390 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<"), return NULL);
1391 for (i = 0; i < value->os.len; i++) {
1392 if (i == 1024) { /* Dump only up to 1024 bytes of the buffer */
1393 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "[...] (len=%zd)", value->os.len), return NULL);
1394 break;
1395 }
1396 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s%02hhX", (i==0 ? "" : " "), value->os.data[i]), return NULL);
1397 }
1398 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ">"), return NULL);
1399 return *buf;
1400}
1401
1402static DECLARE_FD_DUMP_PROTOTYPE(dump_val_i32, union avp_value * value)
1403{
1404 return fd_dump_extend( FD_DUMP_STD_PARAMS, "%i (0x%x)", value->i32, value->i32);
1405}
1406
1407static DECLARE_FD_DUMP_PROTOTYPE(dump_val_i64, union avp_value * value)
1408{
1409 return fd_dump_extend( FD_DUMP_STD_PARAMS, "%" PRId64 " (0x%" PRIx64 ")", value->i64, value->i64);
1410}
1411
1412static DECLARE_FD_DUMP_PROTOTYPE(dump_val_u32, union avp_value * value)
1413{
1414 return fd_dump_extend( FD_DUMP_STD_PARAMS, "%u (0x%x)", value->u32, value->u32);
1415}
1416
1417static DECLARE_FD_DUMP_PROTOTYPE(dump_val_u64, union avp_value * value)
1418{
1419 return fd_dump_extend( FD_DUMP_STD_PARAMS, "%" PRIu64 " (0x%" PRIx64 ")", value->u64, value->u64);
1420}
1421
1422static DECLARE_FD_DUMP_PROTOTYPE(dump_val_f32, union avp_value * value)
1423{
1424 return fd_dump_extend( FD_DUMP_STD_PARAMS, "%f", value->f32);
1425}
1426
1427static DECLARE_FD_DUMP_PROTOTYPE(dump_val_f64, union avp_value * value)
1428{
1429 return fd_dump_extend( FD_DUMP_STD_PARAMS, "%g", value->f64);
1430}
1431
1432/* Get the dump function for basic dict_avp_basetype */
1433static DECLARE_FD_DUMP_PROTOTYPE((*get_default_dump_val_cb(enum dict_avp_basetype datatype)), union avp_value *)
1434{
1435 switch (datatype) {
1436 case AVP_TYPE_OCTETSTRING:
1437 return &dump_val_os;
1438
1439 case AVP_TYPE_INTEGER32:
1440 return &dump_val_i32;
1441
1442 case AVP_TYPE_INTEGER64:
1443 return &dump_val_i64;
1444
1445 case AVP_TYPE_UNSIGNED32:
1446 return &dump_val_u32;
1447
1448 case AVP_TYPE_UNSIGNED64:
1449 return &dump_val_u64;
1450
1451 case AVP_TYPE_FLOAT32:
1452 return &dump_val_f32;
1453
1454 case AVP_TYPE_FLOAT64:
1455 return &dump_val_f64;
1456
1457 case AVP_TYPE_GROUPED:
1458 TRACE_DEBUG(FULL, "error: grouped AVP with a value!");
1459 }
1460 return NULL;
1461}
1462
1463/* indent inside an object (duplicate from messages.c) */
1464#define INOBJHDR "%*s "
1465#define INOBJHDRVAL indent<0 ? 1 : indent, indent<0 ? "-" : "|"
1466
1467typedef DECLARE_FD_DUMP_PROTOTYPE((*dump_val_cb_t), union avp_value *);
1468
1469/* Formatter for the AVP value dump line */
1470static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_val, union avp_value *avp_value,
1471 dump_val_cb_t def_dump_val_cb,
1472 dump_val_cb_t dump_val_cb,
1473 enum dict_avp_basetype datatype,
1474 char * type_name,
1475 char * const_name,
1476 int indent,
1477 int header)
1478{
1479 if (header) {
1480 /* Header for all AVP values dumps: */
1481 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, INOBJHDR "value ", INOBJHDRVAL), return NULL);
1482
1483 /* If the type is provided, write it */
1484 if (type_name) {
1485 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "t: '%s' ", type_name), return NULL);
1486 }
1487
1488 /* Always give the base datatype anyway */
1489 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(%s) ", type_base_name[datatype]), return NULL);
1490
1491 /* Now, the value */
1492 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "v: "), return NULL);
1493 }
1494 if (const_name) {
1495 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s' (", const_name), return NULL);
1496 }
1497 if (dump_val_cb) {
1498 CHECK_MALLOC_DO( (*dump_val_cb)( FD_DUMP_STD_PARAMS, avp_value), fd_dump_extend( FD_DUMP_STD_PARAMS, "(dump failed)"));
1499 } else {
1500 CHECK_MALLOC_DO( (*def_dump_val_cb)( FD_DUMP_STD_PARAMS, avp_value), return NULL);
1501 }
1502 if (const_name) {
1503 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ")"), return NULL);
1504 }
1505
1506 /* Done! */
1507 return *buf;
1508}
1509
1510/* Dump the value of an AVP of known type into the returned str */
1511DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_avp_value, union avp_value *avp_value, struct dict_object * model, int indent, int header)
1512{
1513 DECLARE_FD_DUMP_PROTOTYPE((*dump_val_cb), union avp_value *avp_value) = NULL;
1514 struct dict_object * type = NULL;
1515 char * type_name = NULL;
1516 char * const_name = NULL;
1517
1518 FD_DUMP_HANDLE_OFFSET();
1519
1520 /* Handle invalid parameters */
1521 if (!avp_value) {
1522 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(avp value not set)"), return NULL);
1523 return *buf;
1524 }
1525
1526 if (!model) {
1527 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(model not set)"), return NULL);
1528 return *buf;
1529 }
1530
1531 if (! ( verify_object(model) && (model->type == DICT_AVP) )) {
1532 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model)"), return NULL);
1533 return *buf;
1534 }
1535
1536 /* Get the type definition of this AVP */
1537 type = model->parent;
1538 if (type) {
1539 struct dict_enumval_request request;
1540 struct dict_object * enumval = NULL;
1541
1542 type_name = type->data.type.type_name;
1543
1544 /* overwrite the dump function ? */
1545 if (type->data.type.type_dump)
1546 dump_val_cb = type->data.type.type_dump;
1547
1548 /* Now check if the AVP value matches a constant */
1549 memset(&request, 0, sizeof(request));
1550 request.type_obj = type;
1551 memcpy(&request.search.enum_value, avp_value, sizeof(union avp_value));
1552 /* bypass checks */
1553 if ((search_enumval( type->dico, ENUMVAL_BY_STRUCT, &request, &enumval ) == 0) && (enumval)) {
1554 /* We found a constant, get its name */
1555 const_name = enumval->data.enumval.enum_name;
1556 }
1557 }
1558
1559 /* And finally, dump the value */
1560 CHECK_MALLOC_DO( dump_avp_val(FD_DUMP_STD_PARAMS, avp_value, get_default_dump_val_cb(model->data.avp.avp_basetype), dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, header), return NULL );
1561 return *buf;
1562}
1563
1564/*******************************************************************************************************/
1565/*******************************************************************************************************/
1566/* */
1567/* Exported functions */
1568/* */
1569/*******************************************************************************************************/
1570/*******************************************************************************************************/
1571
1572/* These are the functions exported outside libfreeDiameter. */
1573
1574/* Get the data associated to an object */
1575int fd_dict_gettype ( struct dict_object * object, enum dict_object_type * type)
1576{
1577 TRACE_ENTRY("%p %p", object, type);
1578
1579 CHECK_PARAMS( type && verify_object(object) );
1580
1581 /* Copy the value and return */
1582 *type = object->type;
1583 return 0;
1584}
1585
1586int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict)
1587{
1588 TRACE_ENTRY("%p %p", object, dict);
1589
1590 CHECK_PARAMS( dict && verify_object(object) );
1591
1592 /* Copy the value and return */
1593 *dict = object->dico;
1594 return 0;
1595}
1596
1597
1598/* Get the data associated to an object */
1599int fd_dict_getval ( struct dict_object * object, void * val)
1600{
1601 TRACE_ENTRY("%p %p", object, val);
1602
1603 CHECK_PARAMS( val && verify_object(object) );
1604
1605 /* Copy the value and return */
1606 memcpy(val, &object->data, _OBINFO(object).datasize);;
1607 return 0;
1608}
1609
1610/* Add a new object in the dictionary */
1611int fd_dict_new ( struct dictionary * dict, enum dict_object_type type, void * data, struct dict_object * parent, struct dict_object **ref )
1612{
1613 int ret = 0;
1614 int dupos = 0;
1615 struct dict_object * new = NULL;
1616 struct dict_object * vendor = NULL;
1617 struct dict_object * locref = NULL;
1618
1619 TRACE_ENTRY("%p %d(%s) %p %p %p", dict, type, dict_obj_info[CHECK_TYPE(type) ? type : 0].name, data, parent, ref);
1620
1621 /* Check parameters */
1622 CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && CHECK_TYPE(type) && data );
1623
1624 /* Check the "parent" parameter */
1625 switch (dict_obj_info[type].parent) {
1626 case 0: /* parent is forbidden */
1627 CHECK_PARAMS_DO( parent == NULL, goto error_param );
1628
1629 case 1: /* parent is optional */
1630 if (parent == NULL)
1631 break;
1632
1633 case 2: /* parent is mandatory */
1634 CHECK_PARAMS_DO( verify_object(parent), goto error_param );
1635
1636 if (type == DICT_RULE ) { /* Special case : grouped AVP or Command parents are allowed */
1637 CHECK_PARAMS_DO( (parent->type == DICT_COMMAND )
1638 || ( (parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED ) ), goto error_param );
1639 } else {
1640 CHECK_PARAMS_DO( parent->type == dict_obj_info[type].parenttype, goto error_param );
1641 }
1642 }
1643
1644 /* For AVP object, we must also check that the "vendor" referenced exists */
1645 if (type == DICT_AVP) {
1646 CHECK_FCT_DO( fd_dict_search( dict, DICT_VENDOR, VENDOR_BY_ID, &(((struct dict_avp_data *)data)->avp_vendor), (void*)&vendor, ENOENT ),
1647 { TRACE_DEBUG(INFO, "Unable to find vendor '%d' referenced in the AVP data", ((struct dict_avp_data *)data)->avp_vendor); goto error_param; } );
1648
1649 /* Also check if a parent is provided, that the type are the same */
1650 if (parent) {
1651 CHECK_PARAMS_DO( parent->data.type.type_base == ((struct dict_avp_data *)data)->avp_basetype, goto error_param );
1652 }
1653 }
1654
1655 /* For RULE object, we must also check that the "avp" referenced exists */
1656 if (type == DICT_RULE) {
1657 CHECK_PARAMS_DO( verify_object(((struct dict_rule_data *)data)->rule_avp), goto error_param );
1658 CHECK_PARAMS_DO( ((struct dict_rule_data *)data)->rule_avp->type == DICT_AVP, goto error_param );
1659 }
1660
1661 /* For COMMAND object, check that the 'R' flag is fixed */
1662 if (type == DICT_COMMAND) {
1663 CHECK_PARAMS_DO( ((struct dict_cmd_data *)data)->cmd_flag_mask & CMD_FLAG_REQUEST, goto error_param );
1664 }
1665
1666 /* For ENUMVAL object, check if the parent type is an OctetString */
1667 if (type == DICT_ENUMVAL) {
1668 if (parent->data.type.type_base == AVP_TYPE_OCTETSTRING)
1669 dupos = 1;
1670 }
1671
1672 /* We have to check that the new values are not equal to the sentinels */
1673 if (type == DICT_VENDOR) {
1674 CHECK_PARAMS_DO( ((struct dict_vendor_data *)data)->vendor_id != 0, goto error_param );
1675 }
1676 if (type == DICT_APPLICATION) {
1677 CHECK_PARAMS_DO( ((struct dict_application_data *)data)->application_id != 0, goto error_param );
1678 }
1679
1680 /* Parameters are valid, create the new object */
1681 CHECK_MALLOC( new = malloc(sizeof(struct dict_object)) );
1682
1683 /* Initialize the data of the new object */
1684 init_object(new, type);
1685 init_object_data(new, data, type, dupos);
1686 new->dico = dict;
1687 new->parent = parent;
1688
1689 /* We will change the dictionary => acquire the write lock */
1690 CHECK_POSIX_DO( ret = pthread_rwlock_wrlock(&dict->dict_lock), goto error_free );
1691
1692 /* Now link the object -- this also checks that no object with same keys already exists */
1693 switch (type) {
1694 case DICT_VENDOR:
1695 /* A vendor object is linked in the g_dict_vendors.list[0], by their id */
1696 ret = fd_list_insert_ordered ( &dict->dict_vendors.list[0], &new->list[0], (int (*)(void*, void *))order_vendor_by_id, (void **)&locref );
1697 if (ret)
1698 goto error_unlock;
1699 break;
1700
1701 case DICT_APPLICATION:
1702 /* An application object is linked in the g_dict_applciations.list[0], by their id */
1703 ret = fd_list_insert_ordered ( &dict->dict_applications.list[0], &new->list[0], (int (*)(void*, void *))order_appli_by_id, (void **)&locref );
1704 if (ret)
1705 goto error_unlock;
1706 break;
1707
1708 case DICT_TYPE:
1709 /* A type object is linked in g_list_types by its name */
1710 ret = fd_list_insert_ordered ( &dict->dict_types, &new->list[0], (int (*)(void*, void *))order_type_by_name, (void **)&locref );
1711 if (ret)
1712 goto error_unlock;
1713 break;
1714
1715 case DICT_ENUMVAL:
1716 /* A type_enum object is linked in it's parent 'type' object lists 1 and 2 by its name and values */
1717 ret = fd_list_insert_ordered ( &parent->list[1], &new->list[0], (int (*)(void*, void *))order_enum_by_name, (void **)&locref );
1718 if (ret)
1719 goto error_unlock;
1720
1721 ret = fd_list_insert_ordered ( &parent->list[2], &new->list[1], (int (*)(void*, void *))order_enum_by_val, (void **)&locref );
1722 if (ret) {
1723 fd_list_unlink(&new->list[0]);
1724 goto error_unlock;
1725 }
1726 break;
1727
1728 case DICT_AVP:
1729 /* An avp object is linked in lists 1 and 2 of its vendor, by code and name */
1730 ret = fd_list_insert_ordered ( &vendor->list[1], &new->list[0], (int (*)(void*, void *))order_avp_by_code, (void **)&locref );
1731 if (ret)
1732 goto error_unlock;
1733
1734 ret = fd_list_insert_ordered ( &vendor->list[2], &new->list[1], (int (*)(void*, void *))order_avp_by_name, (void **)&locref );
1735 if (ret) {
1736 fd_list_unlink(&new->list[0]);
1737 goto error_unlock;
1738 }
1739 break;
1740
1741 case DICT_COMMAND:
1742 /* A command object is linked in g_list_cmd_name and g_list_cmd_code by its name and code */
1743 ret = fd_list_insert_ordered ( &dict->dict_cmd_code, &new->list[1], (int (*)(void*, void *))order_cmd_by_codefl, (void **)&locref );
1744 if (ret)
1745 goto error_unlock;
1746
1747 ret = fd_list_insert_ordered ( &dict->dict_cmd_name, &new->list[0], (int (*)(void*, void *))order_cmd_by_name, (void **)&locref );
1748 if (ret) {
1749 fd_list_unlink(&new->list[1]);
1750 goto error_unlock;
1751 }
1752 break;
1753
1754 case DICT_RULE:
1755 /* A rule object is linked in list[2] of its parent command or AVP by the name of the AVP it refers */
1756 ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avpvc, (void **)&locref );
1757 if (ret)
1758 goto error_unlock;
1759 break;
1760
1761 default:
1762 ASSERT(0);
1763 }
1764
1765 /* A new object has been created, increment the global counter */
1766 dict->dict_count[type]++;
1767
1768 /* Unlock the dictionary */
1769 CHECK_POSIX_DO( ret = pthread_rwlock_unlock(&dict->dict_lock), goto error_free );
1770
1771 /* Save the pointer to the new object */
1772 if (ref)
1773 *ref = new;
1774
1775 return 0;
1776
1777error_param:
1778 ret = EINVAL;
1779 goto all_errors;
1780
1781error_unlock:
1782 CHECK_POSIX_DO( pthread_rwlock_unlock(&dict->dict_lock), /* continue */ );
1783 if (ret == EEXIST) {
1784 /* We have a duplicate key in locref. Check if the pointed object is the same or not */
1785 switch (type) {
1786 case DICT_VENDOR:
1787 TRACE_DEBUG(FULL, "Vendor %s already in dictionary", new->data.vendor.vendor_name);
1788 /* if we are here, it means the two vendors id are identical */
1789 if (fd_os_cmp(locref->data.vendor.vendor_name, locref->datastr_len,
1790 new->data.vendor.vendor_name, new->datastr_len)) {
1791 TRACE_DEBUG(INFO, "Conflicting vendor name: %s", new->data.vendor.vendor_name);
1792 break;
1793 }
1794 /* Otherwise (same name), we consider the function succeeded, since the (same) object is in the dictionary */
1795 ret = 0;
1796 break;
1797
1798 case DICT_APPLICATION:
1799 TRACE_DEBUG(FULL, "Application %s already in dictionary", new->data.application.application_name);
1800 /* got same id */
1801 if (fd_os_cmp(locref->data.application.application_name, locref->datastr_len,
1802 new->data.application.application_name, new->datastr_len)) {
1803 TRACE_DEBUG(FULL, "Conflicting application name");
1804 break;
1805 }
1806 ret = 0;
1807 break;
1808
1809 case DICT_TYPE:
1810 TRACE_DEBUG(FULL, "Type %s already in dictionary", new->data.type.type_name);
1811 /* got same name */
1812 if (locref->data.type.type_base != new->data.type.type_base) {
1813 TRACE_DEBUG(FULL, "Conflicting base type");
1814 break;
1815 }
1816 /* discard new definition only it a callback is provided and different from the previous one */
1817 if ((new->data.type.type_interpret) && (locref->data.type.type_interpret != new->data.type.type_interpret)) {
1818 TRACE_DEBUG(FULL, "Conflicting interpret cb");
1819 break;
1820 }
1821 if ((new->data.type.type_encode) && (locref->data.type.type_encode != new->data.type.type_encode)) {
1822 TRACE_DEBUG(FULL, "Conflicting encode cb");
1823 break;
1824 }
1825 if ((new->data.type.type_dump) && (locref->data.type.type_dump != new->data.type.type_dump)) {
1826 TRACE_DEBUG(FULL, "Conflicting dump cb");
1827 break;
1828 }
1829 ret = 0;
1830 break;
1831
1832 case DICT_ENUMVAL:
1833 TRACE_DEBUG(FULL, "Enum %s already in dictionary", new->data.enumval.enum_name);
1834 /* got either same name or same value. We check that both are true */
1835 if (order_enum_by_name(locref, new)) {
1836 TRACE_DEBUG(FULL, "Conflicting enum name");
1837 break;
1838 }
1839 if (order_enum_by_val(locref, new)) {
1840 TRACE_DEBUG(FULL, "Conflicting enum value");
1841 break;
1842 }
1843 ret = 0;
1844 break;
1845
1846 case DICT_AVP:
1847 TRACE_DEBUG(FULL, "AVP %s already in dictionary", new->data.avp.avp_name);
1848 /* got either same name or code */
1849 if (order_avp_by_code(locref, new)) {
1850 TRACE_DEBUG(FULL, "Conflicting AVP code");
1851 break;
1852 }
1853 if (order_avp_by_name(locref, new)) {
1854 TRACE_DEBUG(FULL, "Conflicting AVP name");
1855 break;
1856 }
1857 if (locref->data.avp.avp_vendor != new->data.avp.avp_vendor) {
1858 TRACE_DEBUG(FULL, "Conflicting AVP vendor");
1859 break;
1860 }
1861 if (locref->data.avp.avp_flag_mask != new->data.avp.avp_flag_mask) {
1862 TRACE_DEBUG(FULL, "Conflicting AVP flags mask");
1863 break;
1864 }
1865 if ((locref->data.avp.avp_flag_val & locref->data.avp.avp_flag_mask) != (new->data.avp.avp_flag_val & new->data.avp.avp_flag_mask)) {
1866 TRACE_DEBUG(FULL, "Conflicting AVP flags value");
1867 break;
1868 }
1869 if (locref->data.avp.avp_basetype != new->data.avp.avp_basetype) {
1870 TRACE_DEBUG(FULL, "Conflicting AVP base type");
1871 break;
1872 }
1873 ret = 0;
1874 break;
1875
1876 case DICT_COMMAND:
1877 TRACE_DEBUG(FULL, "Command %s already in dictionary", new->data.cmd.cmd_name);
1878 /* We got either same name, or same code + R flag */
1879 if (order_cmd_by_name(locref, new)) {
1880 TRACE_DEBUG(FULL, "Conflicting command name");
1881 break;
1882 }
1883 if (locref->data.cmd.cmd_code != new->data.cmd.cmd_code) {
1884 TRACE_DEBUG(FULL, "Conflicting command code");
1885 break;
1886 }
1887 if (locref->data.cmd.cmd_flag_mask != new->data.cmd.cmd_flag_mask) {
1888 TRACE_DEBUG(FULL, "Conflicting command flags mask %hhx:%hhx", locref->data.cmd.cmd_flag_mask, new->data.cmd.cmd_flag_mask);
1889 break;
1890 }
1891 if ((locref->data.cmd.cmd_flag_val & locref->data.cmd.cmd_flag_mask) != (new->data.cmd.cmd_flag_val & new->data.cmd.cmd_flag_mask)) {
1892 TRACE_DEBUG(FULL, "Conflicting command flags value");
1893 break;
1894 }
1895 ret = 0;
1896 break;
1897
1898 case DICT_RULE:
1899 /* Both rules point to the same AVPs (code & vendor) */
1900 if (locref->data.rule.rule_position != new->data.rule.rule_position) {
1901 TRACE_DEBUG(FULL, "Conflicting rule position");
1902 break;
1903 }
1904 if ( ((locref->data.rule.rule_position == RULE_FIXED_HEAD) ||
1905 (locref->data.rule.rule_position == RULE_FIXED_TAIL))
1906 && (locref->data.rule.rule_order != new->data.rule.rule_order)) {
1907 TRACE_DEBUG(FULL, "Conflicting rule order");
1908 break;
1909 }
1910 if (locref->data.rule.rule_min != new->data.rule.rule_min) {
1911 int r1 = locref->data.rule.rule_min;
1912 int r2 = new->data.rule.rule_min;
1913 int p = locref->data.rule.rule_position;
1914 if ( ((r1 != -1) && (r2 != -1)) /* none of the definitions contains the "default" value */
1915 || ((p == RULE_OPTIONAL) && (r1 != 0) && (r2 != 0)) /* the other value is not 0 for an optional rule */
1916 || ((r1 != 1) && (r2 != 1)) /* the other value is not 1 for another rule */
1917 ) {
1918 TRACE_DEBUG(FULL, "Conflicting rule min");
1919 break;
1920 }
1921 }
1922 if (locref->data.rule.rule_max != new->data.rule.rule_max) {
1923 TRACE_DEBUG(FULL, "Conflicting rule max");
1924 break;
1925 }
1926 ret = 0;
1927 break;
1928 }
1929 if (!ret) {
1930 TRACE_DEBUG(FULL, "An existing object with the same data was found, ignoring the error...");
1931 }
1932 if (ref)
1933 *ref = locref;
1934 }
1935all_errors:
1936 if (ret != 0) {
1937 char * buf = NULL;
1938 size_t len = 0, offset=0;
1939
1940 if (type == DICT_ENUMVAL) {
1941 CHECK_MALLOC( dump_enumval_data ( &buf, &len, &offset, data, parent->data.type.type_base ));
1942 } else {
1943 CHECK_MALLOC( dict_obj_info[CHECK_TYPE(type) ? type : 0].dump_data(&buf, &len, &offset, data) );
1944 }
1945
1946 TRACE_DEBUG(INFO, "An error occurred while adding the following data in the dictionary: %s", buf);
1947
1948 if (ret == EEXIST) {
1949 offset=0;
1950 CHECK_MALLOC( dump_object(&buf, &len, &offset, locref, 0, 0, 0) );
1951 TRACE_DEBUG(INFO, "Conflicting entry in the dictionary: %s", buf);
1952 }
1953 free(buf);
1954 }
1955error_free:
1956 free(new);
1957 return ret;
1958}
1959
1960
1961int fd_dict_delete(struct dict_object * obj)
1962{
1963 int i;
1964 struct dictionary * dict;
1965 int ret=0;
1966
1967 /* check params */
1968 CHECK_PARAMS( verify_object(obj) && obj->dico);
1969 dict = obj->dico;
1970
1971 /* Lock the dictionary for change */
1972 CHECK_POSIX( pthread_rwlock_wrlock(&dict->dict_lock) );
1973
1974 /* check the object is not sentinel for another list */
1975 for (i=0; i<NB_LISTS_PER_OBJ; i++) {
1976 if (!_OBINFO(obj).haslist[i] && !(FD_IS_LIST_EMPTY(&obj->list[i]))) {
1977 /* There are children, this is not good */
1978 ret = EINVAL;
1979 TRACE_DEBUG (FULL, "Cannot delete object, list %d not empty:", i);
1980 #if 0
1981 dump_list(&obj->list[i], 0,0,0);
1982 #endif
1983 break;
1984 }
1985 }
1986
1987 /* ok, now destroy the object */
1988 if (!ret)
1989 destroy_object(obj);
1990
1991 /* Unlock */
1992 CHECK_POSIX( pthread_rwlock_unlock(&dict->dict_lock) );
1993
1994 return ret;
1995}
1996
1997
1998int fd_dict_search ( struct dictionary * dict, enum dict_object_type type, int criteria, const void * what, struct dict_object **result, int retval )
1999{
2000 int ret = 0;
2001
2002 TRACE_ENTRY("%p %d(%s) %d %p %p %d", dict, type, dict_obj_info[CHECK_TYPE(type) ? type : 0].name, criteria, what, result, retval);
2003
2004 /* Check param */
2005 CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && CHECK_TYPE(type) );
2006
2007 /* Lock the dictionary for reading */
2008 CHECK_POSIX( pthread_rwlock_rdlock(&dict->dict_lock) );
2009
2010 /* Now call the type-specific search function */
2011 ret = dict_obj_info[type].search_fct (dict, criteria, what, result);
2012
2013 /* Unlock */
2014 CHECK_POSIX( pthread_rwlock_unlock(&dict->dict_lock) );
2015
2016 /* Update the return value as needed */
2017 if ((result != NULL) && (*result == NULL))
2018 ret = retval;
2019
2020 return ret;
2021}
2022
2023/* Function to retrieve list of objects in the dictionary. Use with care (read only).
2024
2025All returned list must be accessed like this:
2026
2027 for (li = sentinel->next; li != sentinel; li=li->next) {
2028 struct dict_object * obj = li->o;
2029 ...
2030 }
2031
2032The following criteria are allowed, with corresponding parent.
2033The parent is either struct dictionary * or struct dict_object *
2034
2035VENDOR_BY_ID : (parent = dictionary) returns list of vendors ordered by ID
2036APPLICATION_BY_ID : (parent = dictionary) returns list of applications ordered by ID
2037 ** for these two lists, the Vendor with id 0 and applciation with id 0 are excluded.
2038 You must resolve them separatly with dict_search.
2039
2040TYPE_BY_NAME : (parent = dictionary) returns list of types ordered by name (osstring order)
2041ENUMVAL_BY_NAME : (parent = type object) return list of constants for this type ordered by name (osstring order)
2042ENUMVAL_BY_VALUE : (parent = type object) return list of constants for this type ordered by values
2043AVP_BY_NAME : (parent = vendor object) return list of AVP for this vendor ordered by name (osstring order)
2044AVP_BY_CODE : (parent = vendor object) return list of AVP for this vendor ordered by code
2045CMD_BY_NAME : (parent = dictionary) returns list of commands ordered by name (osstring order)
2046CMD_BY_CODE_R : (parent = dictionary) returns list of commands ordered by code
2047RULE_BY_AVP_AND_PARENT: (parent = command or grouped AVP object) return list of rules for this object ordered by AVP vendor/code
2048
2049All other criteria are rejected.
2050 */
2051int fd_dict_getlistof(int criteria, void * parent, struct fd_list ** sentinel)
2052{
2053 struct dictionary * dict = parent;
2054 struct dict_object * obj_parent = parent;
2055
2056 TRACE_ENTRY("%i %p %p", criteria, parent, sentinel);
2057
2058 CHECK_PARAMS(sentinel && parent);
2059
2060 switch(criteria) {
2061 case VENDOR_BY_ID: /* parent must be the dictionary */
2062 CHECK_PARAMS(dict->dict_eyec == DICT_EYECATCHER);
2063 *sentinel = &dict->dict_vendors.list[0];
2064 break;
2065
2066 case APPLICATION_BY_ID: /* parent must be the dictionary */
2067 CHECK_PARAMS(dict->dict_eyec == DICT_EYECATCHER);
2068 *sentinel = &dict->dict_applications.list[0];
2069 break;
2070
2071 case TYPE_BY_NAME: /* parent must be the dictionary */
2072 CHECK_PARAMS(dict->dict_eyec == DICT_EYECATCHER);
2073 *sentinel = &dict->dict_types;
2074 break;
2075
2076 case ENUMVAL_BY_NAME: /* parent must be a type object */
2077 CHECK_PARAMS(verify_object(obj_parent) && (obj_parent->type == DICT_TYPE));
2078 *sentinel = &obj_parent->list[1];
2079 break;
2080
2081 case ENUMVAL_BY_VALUE: /* parent must be a type object */
2082 CHECK_PARAMS(verify_object(obj_parent) && (obj_parent->type == DICT_TYPE));
2083 *sentinel = &obj_parent->list[2];
2084 break;
2085
2086 case AVP_BY_NAME: /* parent must be a VENDOR object */
2087 CHECK_PARAMS(verify_object(obj_parent) && (obj_parent->type == DICT_VENDOR));
2088 *sentinel = &obj_parent->list[2];
2089 break;
2090
2091 case AVP_BY_CODE: /* parent must be a VENDOR object */
2092 CHECK_PARAMS(verify_object(obj_parent) && (obj_parent->type == DICT_VENDOR));
2093 *sentinel = &obj_parent->list[1];
2094 break;
2095
2096 case CMD_BY_NAME: /* parent must be the dictionary */
2097 CHECK_PARAMS(dict->dict_eyec == DICT_EYECATCHER);
2098 *sentinel = &dict->dict_cmd_name;
2099 break;
2100
2101 case CMD_BY_CODE_R: /* parent must be the dictionary */
2102 CHECK_PARAMS(dict->dict_eyec == DICT_EYECATCHER);
2103 *sentinel = &dict->dict_cmd_code;
2104 break;
2105
2106 case RULE_BY_AVP_AND_PARENT: /* parent must be command or grouped AVP */
2107 CHECK_PARAMS(verify_object(obj_parent));
2108 CHECK_PARAMS( (obj_parent->type == DICT_COMMAND) ||
2109 ((obj_parent->type == DICT_AVP)
2110 && (obj_parent->data.avp.avp_basetype == AVP_TYPE_GROUPED)) );
2111 *sentinel = &obj_parent->list[2];
2112 break;
2113
2114 default:
2115 CHECK_PARAMS(0);
2116 }
2117
2118 return 0;
2119}
2120
2121/*******************************************************************************************************/
2122/*******************************************************************************************************/
2123/* */
2124/* The init/fini functions */
2125/* */
2126/*******************************************************************************************************/
2127/*******************************************************************************************************/
2128
2129/* Initialize the dictionary */
2130int fd_dict_init ( struct dictionary ** dict)
2131{
2132 struct dictionary * new = NULL;
2133
2134 TRACE_ENTRY("%p", dict);
2135
2136 /* Sanity checks */
2137 ASSERT( (sizeof(type_base_name) / sizeof(type_base_name[0])) == (AVP_TYPE_MAX + 1) );
2138 ASSERT( (sizeof(dict_obj_info) / sizeof(dict_obj_info[0])) == (DICT_TYPE_MAX + 1) );
2139 CHECK_PARAMS(dict);
2140
2141 /* Allocate the memory for the dictionary */
2142 CHECK_MALLOC( new = malloc(sizeof(struct dictionary)) );
2143 memset(new, 0, sizeof(struct dictionary));
2144
2145 new->dict_eyec = DICT_EYECATCHER;
2146
2147 /* Initialize the lock for the dictionary */
2148 CHECK_POSIX( pthread_rwlock_init(&new->dict_lock, NULL) );
2149
2150 /* Initialize the sentinel for vendors and AVP lists */
2151 init_object( &new->dict_vendors, DICT_VENDOR );
2152 #define NO_VENDOR_NAME "(no vendor)"
2153 new->dict_vendors.data.vendor.vendor_name = NO_VENDOR_NAME;
2154 new->dict_vendors.datastr_len = CONSTSTRLEN(NO_VENDOR_NAME);
2155 /* new->dict_vendors.list[0].o = NULL; *//* overwrite since element is also sentinel for this list. */
2156 new->dict_vendors.dico = new;
2157
2158 /* Initialize the sentinel for applications */
2159 init_object( &new->dict_applications, DICT_APPLICATION );
2160 #define APPLICATION_0_NAME "Diameter Common Messages"
2161 new->dict_applications.data.application.application_name = APPLICATION_0_NAME;
2162 new->dict_applications.datastr_len = CONSTSTRLEN(APPLICATION_0_NAME);
2163 /* new->dict_applications.list[0].o = NULL; *//* overwrite since since element is also sentinel for this list. */
2164 new->dict_applications.dico = new;
2165
2166 /* Initialize the sentinel for types */
2167 fd_list_init ( &new->dict_types, NULL );
2168
2169 /* Initialize the sentinels for commands */
2170 fd_list_init ( &new->dict_cmd_name, NULL );
2171 fd_list_init ( &new->dict_cmd_code, NULL );
2172
2173 /* Initialize the error command object */
2174 init_object( &new->dict_cmd_error, DICT_COMMAND );
2175 #define GENERIC_ERROR_NAME "(generic error format)"
2176 new->dict_cmd_error.data.cmd.cmd_name = GENERIC_ERROR_NAME;
2177 new->dict_cmd_error.datastr_len = CONSTSTRLEN(GENERIC_ERROR_NAME);
2178 new->dict_cmd_error.data.cmd.cmd_flag_mask=CMD_FLAG_ERROR | CMD_FLAG_REQUEST | CMD_FLAG_RETRANSMIT;
2179 new->dict_cmd_error.data.cmd.cmd_flag_val =CMD_FLAG_ERROR;
2180 new->dict_cmd_error.dico = new;
2181
2182 *dict = new;
2183
2184 /* Done */
2185 return 0;
2186}
2187
2188/* Destroy a dictionary */
2189int fd_dict_fini ( struct dictionary ** dict)
2190{
2191 int i;
2192
2193 TRACE_ENTRY("");
2194 CHECK_PARAMS( dict && *dict && ((*dict)->dict_eyec == DICT_EYECATCHER) );
2195
2196 /* Acquire the write lock to make sure no other operation is ongoing */
2197 CHECK_POSIX( pthread_rwlock_wrlock(&(*dict)->dict_lock) );
2198
2199 /* Empty all the lists, free the elements */
2200 destroy_list ( &(*dict)->dict_cmd_error.list[2] );
2201 destroy_list ( &(*dict)->dict_cmd_code );
2202 destroy_list ( &(*dict)->dict_cmd_name );
2203 destroy_list ( &(*dict)->dict_types );
2204 for (i=0; i< NB_LISTS_PER_OBJ; i++) {
2205 destroy_list ( &(*dict)->dict_applications.list[i] );
2206 destroy_list ( &(*dict)->dict_vendors.list[i] );
2207 }
2208
2209 /* Dictionary is empty, now destroy the lock */
2210 CHECK_POSIX( pthread_rwlock_unlock(&(*dict)->dict_lock) );
2211 CHECK_POSIX( pthread_rwlock_destroy(&(*dict)->dict_lock) );
2212
2213 free(*dict);
2214 *dict = NULL;
2215
2216 return 0;
2217}
2218
2219/*******************************************************************************************************/
2220/*******************************************************************************************************/
2221/* */
2222/* Other functions */
2223/* */
2224/*******************************************************************************************************/
2225/*******************************************************************************************************/
2226
2227/* Iterate a callback on the rules for an object */
2228int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) )
2229{
2230 int ret = 0;
2231 struct fd_list * li;
2232
2233 TRACE_ENTRY("%p %p %p", parent, data, cb);
2234
2235 /* Check parameters */
2236 CHECK_PARAMS( verify_object(parent) );
2237 CHECK_PARAMS( (parent->type == DICT_COMMAND)
2238 || ((parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED)) );
2239 TRACE_DEBUG (FULL, "Iterating on rules of %s: '%s'.",
2240 _OBINFO(parent).name,
2241 parent->type == DICT_COMMAND ?
2242 parent->data.cmd.cmd_name
2243 : parent->data.avp.avp_name);
2244
2245 /* Acquire the read lock */
2246 CHECK_POSIX( pthread_rwlock_rdlock(&parent->dico->dict_lock) );
2247
2248 /* go through the list and call the cb on each rule data */
2249 for (li = &(parent->list[2]); li->next != &(parent->list[2]); li = li->next) {
2250 ret = (*cb)(data, &(_O(li->next->o)->data.rule));
2251 if (ret != 0)
2252 break;
2253 }
2254
2255 /* Release the lock */
2256 CHECK_POSIX( pthread_rwlock_unlock(&parent->dico->dict_lock) );
2257
2258 return ret;
2259}
2260
2261/* Create the list of vendors. Returns a 0-terminated array, that must be freed after use. Returns NULL on error. */
2262uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict)
2263{
2264 uint32_t * ret = NULL;
2265 int i = 0;
2266 struct fd_list * li;
2267
2268 TRACE_ENTRY();
2269
2270 /* Acquire the read lock */
2271 CHECK_POSIX_DO( pthread_rwlock_rdlock(&dict->dict_lock), return NULL );
2272
2273 /* Allocate an array to contain all the elements */
2274 CHECK_MALLOC_DO( ret = calloc( dict->dict_count[DICT_VENDOR] + 1, sizeof(uint32_t) ), goto out );
2275
2276 /* Copy the vendors IDs */
2277 for (li = dict->dict_vendors.list[0].next; li != &(dict->dict_vendors.list[0]); li = li->next) {
2278 ret[i] = _O(li->o)->data.vendor.vendor_id;
2279 i++;
2280 ASSERT( i <= dict->dict_count[DICT_VENDOR] );
2281 }
2282out:
2283 /* Release the lock */
2284 CHECK_POSIX_DO( pthread_rwlock_unlock(&dict->dict_lock), return NULL );
2285
2286 return ret;
2287}
2288
2289/* Return the location of the cb list for an object, after checking its type */
2290int fd_dict_disp_cb(enum dict_object_type type, struct dict_object *obj, struct fd_list ** cb_list)
2291{
2292 TRACE_ENTRY("%d %p %p", type, obj, cb_list);
2293 CHECK_PARAMS( verify_object(obj) );
2294 CHECK_PARAMS( _OBINFO(obj).type == type );
2295 CHECK_PARAMS( cb_list );
2296 *cb_list = &obj->disp_cbs;
2297 return 0;
2298}
2299
2300int fd_dict_get_error_cmd(struct dictionary * dict, struct dict_object **obj)
2301{
2302 TRACE_ENTRY("%p %p", dict, obj);
2303 CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && obj );
2304 *obj = &dict->dict_cmd_error;
2305 return 0;
2306}