comparison libfreeDiameter/dictionary.c @ 1:bafb831ba688

Fix names to proper case for freeDiameter
author Sebastien Decugis <sdecugis@nict.go.jp>
date Mon, 31 Aug 2009 11:31:10 +0900
parents libfreediameter/dictionary.c@13530e1f02e3
children e5af94b04946
comparison
equal deleted inserted replaced
0:13530e1f02e3 1:bafb831ba688
1 /*********************************************************************************************************
2 * Software License Agreement (BSD License) *
3 * Author: Sebastien Decugis <sdecugis@nict.go.jp> *
4 * *
5 * Copyright (c) 2009, 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 "libfD.h"
37
38 /* Names of the base types */
39 const char * type_base_name[] = { /* must keep in sync with dict_avp_basetype */
40 "GROUPED", /* AVP_TYPE_GROUPED */
41 "OCTETSTRING", /* AVP_TYPE_OCTETSTRING */
42 "INTEGER32", /* AVP_TYPE_INTEGER32 */
43 "INTEGER64", /* AVP_TYPE_INTEGER64 */
44 "UNSIGNED32", /* AVP_TYPE_UNSIGNED32 */
45 "UNSIGNED64", /* AVP_TYPE_UNSIGNED64 */
46 "FLOAT32", /* AVP_TYPE_FLOAT32 */
47 "FLOAT64" /* AVP_TYPE_FLOAT64 */
48 };
49
50 /* The number of lists in an object */
51 #define NB_LISTS_PER_OBJ 3
52
53 /* Some eye catchers definitions */
54 #define OBJECT_EYECATCHER (0x0b13c7)
55 #define DICT_EYECATCHER (0x00d1c7)
56
57 /* Definition of the dictionary objects */
58 struct dict_object {
59 enum dict_object_type type; /* What type of object is this? */
60 int objeyec;/* eyecatcher for this object */
61 int typeyec;/* eyecatcher for this type of object */
62 struct dictionary *dico; /* The dictionary this object belongs to */
63
64 union {
65 struct dict_vendor_data vendor;
66 struct dict_application_data application;
67 struct dict_type_data type;
68 struct dict_enumval_data enumval;
69 struct dict_avp_data avp;
70 struct dict_cmd_data cmd;
71 struct dict_rule_data rule;
72 } data; /* The data of this object */
73
74 struct dict_object * parent; /* The parent of this object, if any */
75
76 struct fd_list list[NB_LISTS_PER_OBJ];/* used to chain objects.*/
77 /* More information about the lists :
78
79 - the use for each list depends on the type of object. See detail bellow.
80
81 - a sentinel for a list has its 'o' field cleared. (this is the criteria to detect end of a loop)
82
83 - The lists are always ordered. The criteria are described bellow. the functions to order them are referenced in dict_obj_info
84
85 - The dict_lock must be held for any list operation.
86
87 => VENDORS:
88 list[0]: list of the vendors, ordered by their id. The sentinel is g_dict_vendors (vendor with id 0)
89 list[1]: sentinel for the list of AVPs from this vendor, ordered by AVP code.
90 list[2]: sentinel for the list of AVPs from this vendor, ordered by AVP name.
91
92 => APPLICATIONS:
93 list[0]: list of the applications, ordered by their id. The sentinel is g_dict_applications (application with id 0)
94 list[1]: not used
95 list[2]: not used.
96
97 => TYPES:
98 list[0]: list of the types, ordered by their names. The sentinel is g_list_types.
99 list[1]: sentinel for the type_enum list of this type, ordered by their constant name.
100 list[2]: sentinel for the type_enum list of this type, ordered by their constant value.
101
102 => TYPE_ENUMS:
103 list[0]: list of the contants for a given type, ordered by the constant name. Sentinel is a (list[1]) element of a TYPE object.
104 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.
105 list[2]: not used
106
107 => AVPS:
108 list[0]: list of the AVP from a given vendor, ordered by avp code. Sentinel is a list[1] element of a VENDOR object.
109 list[1]: list of the AVP from a given vendor, ordered by avp name. Sentinel is a list[2] element of a VENDOR object.
110 list[2]: sentinel for the rule list that apply to this AVP.
111
112 => COMMANDS:
113 list[0]: list of the commands, ordered by their names. The sentinel is g_list_cmd_name.
114 list[1]: list of the commands, ordered by their command code and 'R' flag. The sentinel is g_list_cmd_code.
115 list[2]: sentinel for the rule list that apply to this command.
116
117 => RULES:
118 list[0]: list of the rules for a given (grouped) AVP or Command, ordered by the AVP name to which they refer. sentinel is list[2] of a command or (grouped) avp.
119 list[1]: not used
120 list[2]: not used.
121
122 */
123
124 /* Sentinel for the dispatch callbacks */
125 struct fd_list disp_cbs;
126
127 };
128
129 /* Definition of the dictionary structure */
130 struct dictionary {
131 int dict_eyec; /* Eye-catcher for the dictionary (DICT_EYECATCHER) */
132
133 pthread_rwlock_t dict_lock; /* The global rwlock for the dictionary */
134
135 struct dict_object dict_vendors; /* Sentinel for the list of vendors, corresponding to vendor 0 */
136 struct dict_object dict_applications; /* Sentinel for the list of applications, corresponding to app 0 */
137 struct fd_list dict_types; /* Sentinel for the list of types */
138 struct fd_list dict_cmd_name; /* Sentinel for the list of commands, ordered by names */
139 struct fd_list dict_cmd_code; /* Sentinel for the list of commands, ordered by codes */
140
141 struct dict_object dict_cmd_error; /* Special command object for answers with the 'E' bit set */
142
143 int dict_count[DICT_TYPE_MAX]; /* Number of objects of each type */
144 };
145
146 /* Forward declarations of dump functions */
147 static void dump_vendor_data ( void * data );
148 static void dump_application_data ( void * data );
149 static void dump_type_data ( void * data );
150 /* the dump function for enum has a different prototype since it need the datatype */
151 static void dump_avp_data ( void * data );
152 static void dump_command_data ( void * data );
153 static void dump_rule_data ( void * data );
154
155 /* Forward declarations of search functions */
156 static int search_vendor ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
157 static int search_application ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
158 static int search_type ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
159 static int search_enumval ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
160 static int search_avp ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
161 static int search_cmd ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
162 static int search_rule ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
163
164 /* The following array contains lot of data about the different types of objects, for automated handling */
165 static struct {
166 enum dict_object_type type; /* information for this type */
167 char * name; /* string describing this object, for debug */
168 size_t datasize; /* The size of the data structure */
169 int parent; /* 0: never; 1: may; 2: must */
170 enum dict_object_type parenttype; /* The type of the parent, when relevant */
171 int eyecatcher; /* A kind of signature for this object */
172 void (*dump_data)(void * data ); /* The function to dump the data section */
173 int (*search_fct)(struct dictionary * dict, int criteria, void * what, struct dict_object **result );; /* The function to search an object of this type */
174 int haslist[NB_LISTS_PER_OBJ]; /* Tell if this list is used */
175 } dict_obj_info[] = { { 0, "(error)", 0, 0, 0, 0, NULL, NULL, {0, 0, 0} }
176
177 /* type name datasize parent parenttype
178 eyecatcher dump_data search_fct, haslist[] */
179
180 ,{ DICT_VENDOR, "VENDOR", sizeof(struct dict_vendor_data), 0, 0,
181 OBJECT_EYECATCHER + 1, dump_vendor_data, search_vendor, { 1, 0, 0 } }
182
183 ,{ DICT_APPLICATION, "APPLICATION", sizeof(struct dict_application_data), 1, DICT_VENDOR,
184 OBJECT_EYECATCHER + 2, dump_application_data, search_application, { 1, 0, 0 } }
185
186 ,{ DICT_TYPE, "TYPE", sizeof(struct dict_type_data), 1, DICT_APPLICATION,
187 OBJECT_EYECATCHER + 3, dump_type_data, search_type, { 1, 0, 0 } }
188
189 ,{ DICT_ENUMVAL, "ENUMVAL", sizeof(struct dict_enumval_data), 2, DICT_TYPE,
190 OBJECT_EYECATCHER + 4, NULL, search_enumval, { 1, 1, 0 } }
191
192 ,{ DICT_AVP, "AVP", sizeof(struct dict_avp_data), 1, DICT_TYPE,
193 OBJECT_EYECATCHER + 5, dump_avp_data, search_avp, { 1, 1, 0 } }
194
195 ,{ DICT_COMMAND, "COMMAND", sizeof(struct dict_cmd_data), 1, DICT_APPLICATION,
196 OBJECT_EYECATCHER + 6, dump_command_data, search_cmd, { 1, 1, 0 } }
197
198 ,{ DICT_RULE, "RULE", sizeof(struct dict_rule_data), 2, -1 /* special case: grouped avp or command */,
199 OBJECT_EYECATCHER + 7, dump_rule_data, search_rule, { 1, 0, 0 } }
200
201 };
202
203 /* Macro to verify a "type" value */
204 #define CHECK_TYPE( type ) ( ((type) > 0) && ((type) <= DICT_TYPE_MAX) )
205
206 /* Cast macro */
207 #define _O( object ) ((struct dict_object *) (object))
208
209 /* Get information line for a given object */
210 #define _OBINFO(object) (dict_obj_info[CHECK_TYPE(_O(object)->type) ? _O(object)->type : 0])
211
212
213
214
215 /*******************************************************************************************************/
216 /*******************************************************************************************************/
217 /* */
218 /* Objects management */
219 /* */
220 /*******************************************************************************************************/
221 /*******************************************************************************************************/
222
223 /* Functions to manage the objects creation and destruction. */
224
225 /* Duplicate a string inplace */
226 #define DUP_string( str ) { \
227 char * __str = (str); \
228 CHECK_MALLOC( (str) = strdup(__str) ); \
229 }
230
231 /* Initialize an object */
232 static void init_object( struct dict_object * obj, enum dict_object_type type )
233 {
234 int i;
235
236 TRACE_ENTRY("%p %d", obj, type);
237
238 /* Clean the object first */
239 memset ( obj, 0, sizeof(struct dict_object));
240
241 CHECK_PARAMS_DO( CHECK_TYPE(type), return );
242
243 obj->type = type;
244 obj->objeyec = OBJECT_EYECATCHER;
245 obj->typeyec = _OBINFO(obj).eyecatcher;
246
247 /* We don't initialize the data nor the parent here */
248
249 /* Now init the lists */
250 for (i=0; i<NB_LISTS_PER_OBJ; i++) {
251 if (_OBINFO(obj).haslist[i] != 0)
252 fd_list_init(&obj->list[i], obj);
253 else
254 fd_list_init(&obj->list[i], NULL);
255 }
256
257 fd_list_init(&obj->disp_cbs, NULL);
258 }
259
260 /* Initialize the "data" part of an object */
261 static int init_object_data(void * dest, void * source, enum dict_object_type type)
262 {
263 TRACE_ENTRY("%p %p %d", dest, source, type);
264 CHECK_PARAMS( dest && source && CHECK_TYPE(type) );
265
266 /* Generic: copy the full data structure */
267 memcpy( dest, source, dict_obj_info[type].datasize );
268
269 /* Then strings must be duplicated, not copied */
270 /* This function might be simplified by always defining the "name" field as the first field of the structures, but... it's error-prone */
271 switch (type) {
272 case DICT_VENDOR:
273 DUP_string( ((struct dict_vendor_data *)dest)->vendor_name );
274 break;
275
276 case DICT_APPLICATION:
277 DUP_string( ((struct dict_application_data *)dest)->application_name );
278 break;
279
280 case DICT_TYPE:
281 DUP_string( ((struct dict_type_data *)dest)->type_name );
282 break;
283
284 case DICT_ENUMVAL:
285 DUP_string( ((struct dict_enumval_data *)dest)->enum_name );
286 break;
287
288 case DICT_AVP:
289 DUP_string( ((struct dict_avp_data *)dest)->avp_name );
290 break;
291
292 case DICT_COMMAND:
293 DUP_string( ((struct dict_cmd_data *)dest)->cmd_name );
294 break;
295
296 default:
297 /* Nothing to do for RULES */
298 ;
299 }
300
301 return 0;
302 }
303
304 /* Check that an object is valid (1: OK, 0: error) */
305 static int verify_object( struct dict_object * obj )
306 {
307 TRACE_ENTRY("%p", obj);
308
309 CHECK_PARAMS_DO( obj
310 && (obj->objeyec == OBJECT_EYECATCHER)
311 && CHECK_TYPE(obj->type)
312 && (obj->typeyec == dict_obj_info[obj->type].eyecatcher),
313 {
314 if (obj) {
315 TRACE_DEBUG(FULL, "Invalid object : %p\n"
316 " obj->objeyec : %x / %x\n"
317 " obj->type : %d\n"
318 " obj->objeyec : %x / %x\n"
319 " obj->typeyec : %x / %x",
320 obj,
321 obj->objeyec, OBJECT_EYECATCHER,
322 obj->type,
323 obj->objeyec, OBJECT_EYECATCHER,
324 obj->typeyec, _OBINFO(obj).eyecatcher);
325 }
326 return 0;
327 } );
328
329 /* The object is probably valid. */
330 return 1;
331 }
332
333 /* Free the data associated to an object */
334 static void destroy_object_data(struct dict_object * obj)
335 {
336 /* TRACE_ENTRY("%p", obj); */
337
338 switch (obj->type) {
339 case DICT_VENDOR:
340 free( obj->data.vendor.vendor_name );
341 break;
342
343 case DICT_APPLICATION:
344 free( obj->data.application.application_name );
345 break;
346
347 case DICT_TYPE:
348 free( obj->data.type.type_name );
349 break;
350
351 case DICT_ENUMVAL:
352 free( obj->data.enumval.enum_name );
353 break;
354
355 case DICT_AVP:
356 free( obj->data.avp.avp_name );
357 break;
358
359 case DICT_COMMAND:
360 free( obj->data.cmd.cmd_name );
361 break;
362
363 default:
364 /* nothing to do */
365 ;
366 }
367 }
368
369 /* Forward declaration */
370 static void destroy_object(struct dict_object * obj);
371
372 /* Destroy all objects in a list - the lock must be held */
373 static void destroy_list(struct fd_list * head)
374 {
375 /* TRACE_ENTRY("%p", head); */
376
377 /* loop in the list */
378 while (!FD_IS_LIST_EMPTY(head))
379 {
380 /* When destroying the object, it is unlinked from the list */
381 destroy_object(_O(head->next->o));
382 }
383 }
384
385 /* Free an object and its sublists */
386 static void destroy_object(struct dict_object * obj)
387 {
388 int i;
389
390 /* TRACE_ENTRY("%p", obj); */
391
392 /* Update global count */
393 if (obj->dico)
394 obj->dico->dict_count[obj->type]--;
395
396 /* Mark the object as invalid */
397 obj->objeyec = 0xdead;
398
399 /* First, destroy the data associated to the object */
400 destroy_object_data(obj);
401
402 for (i=0; i<NB_LISTS_PER_OBJ; i++) {
403 if (_OBINFO(obj).haslist[i])
404 /* unlink the element from the list */
405 fd_list_unlink( &obj->list[i] );
406 else
407 /* This is either a sentinel or unused (=emtpy) list, let's destroy it */
408 destroy_list( &obj->list[i] );
409 }
410
411 /* Unlink all elements from the dispatch list; they will be freed when callback is unregistered */
412 while (!FD_IS_LIST_EMPTY(&obj->disp_cbs)) {
413 fd_list_unlink( obj->disp_cbs.next );
414 }
415
416 /* Last, destroy the object */
417 free(obj);
418 }
419
420 /*******************************************************************************************************/
421 /*******************************************************************************************************/
422 /* */
423 /* Compare functions */
424 /* */
425 /*******************************************************************************************************/
426 /*******************************************************************************************************/
427
428 /* Compare two values */
429 #define ORDER_scalar( i1, i2 ) \
430 ((i1 < i2 ) ? -1 : ( i1 > i2 ? 1 : 0 ))
431
432
433 /* Compare two vendor objects by their id (checks already performed) */
434 static int order_vendor_by_id ( struct dict_object *o1, struct dict_object *o2 )
435 {
436 TRACE_ENTRY("%p %p", o1, o2);
437
438 return ORDER_scalar( o1->data.vendor.vendor_id, o2->data.vendor.vendor_id );
439 }
440
441 /* Compare two application objects by their id (checks already performed) */
442 static int order_appli_by_id ( struct dict_object *o1, struct dict_object *o2 )
443 {
444 TRACE_ENTRY("%p %p", o1, o2);
445
446 return ORDER_scalar( o1->data.application.application_id, o2->data.application.application_id );
447 }
448
449 /* Compare two type objects by their name (checks already performed) */
450 static int order_type_by_name ( struct dict_object *o1, struct dict_object *o2 )
451 {
452 TRACE_ENTRY("%p %p", o1, o2);
453
454 return strcmp( o1->data.type.type_name, o2->data.type.type_name );
455 }
456
457 /* Compare two type_enum objects by their names (checks already performed) */
458 static int order_enum_by_name ( struct dict_object *o1, struct dict_object *o2 )
459 {
460 TRACE_ENTRY("%p %p", o1, o2);
461
462 return strcmp( o1->data.enumval.enum_name, o2->data.enumval.enum_name );
463 }
464
465 /* Compare two type_enum objects by their values (checks already performed) */
466 static int order_enum_by_val ( struct dict_object *o1, struct dict_object *o2 )
467 {
468 size_t oslen;
469 int cmp = 0;
470
471 TRACE_ENTRY("%p %p", o1, o2);
472
473 /* The comparison function depends on the type of data */
474 switch ( o1->parent->data.type.type_base ) {
475 case AVP_TYPE_OCTETSTRING:
476 oslen = o1->data.enumval.enum_value.os.len;
477 if (o2->data.enumval.enum_value.os.len < oslen)
478 oslen = o2->data.enumval.enum_value.os.len;
479 cmp = memcmp(o1->data.enumval.enum_value.os.data, o2->data.enumval.enum_value.os.data, oslen );
480 return (cmp ? cmp : ORDER_scalar(o1->data.enumval.enum_value.os.len,o2->data.enumval.enum_value.os.len));
481
482 case AVP_TYPE_INTEGER32:
483 return ORDER_scalar( o1->data.enumval.enum_value.i32, o2->data.enumval.enum_value.i32 );
484
485 case AVP_TYPE_INTEGER64:
486 return ORDER_scalar( o1->data.enumval.enum_value.i64, o2->data.enumval.enum_value.i64 );
487
488 case AVP_TYPE_UNSIGNED32:
489 return ORDER_scalar( o1->data.enumval.enum_value.u32, o2->data.enumval.enum_value.u32 );
490
491 case AVP_TYPE_UNSIGNED64:
492 return ORDER_scalar( o1->data.enumval.enum_value.u64, o2->data.enumval.enum_value.u64 );
493
494 case AVP_TYPE_FLOAT32:
495 return ORDER_scalar( o1->data.enumval.enum_value.f32, o2->data.enumval.enum_value.f32 );
496
497 case AVP_TYPE_FLOAT64:
498 return ORDER_scalar( o1->data.enumval.enum_value.f64, o2->data.enumval.enum_value.f64 );
499
500 case AVP_TYPE_GROUPED:
501 default:
502 ASSERT(0);
503 }
504 return 0;
505 }
506
507 /* Compare two avp objects by their codes (checks already performed) */
508 static int order_avp_by_code ( struct dict_object *o1, struct dict_object *o2 )
509 {
510 TRACE_ENTRY("%p %p", o1, o2);
511
512 return ORDER_scalar( o1->data.avp.avp_code, o2->data.avp.avp_code );
513 }
514
515 /* Compare two avp objects by their names (checks already performed) */
516 static int order_avp_by_name ( struct dict_object *o1, struct dict_object *o2 )
517 {
518 TRACE_ENTRY("%p %p", o1, o2);
519
520 return strcmp( o1->data.avp.avp_name, o2->data.avp.avp_name );
521 }
522
523 /* Compare two command objects by their names (checks already performed) */
524 static int order_cmd_by_name ( struct dict_object *o1, struct dict_object *o2 )
525 {
526 TRACE_ENTRY("%p %p", o1, o2);
527
528 return strcmp( o1->data.cmd.cmd_name, o2->data.cmd.cmd_name );
529 }
530
531 /* Compare two command objects by their codes and flags (request or answer) (checks already performed) */
532 static int order_cmd_by_codefl( struct dict_object *o1, struct dict_object *o2 )
533 {
534 uint8_t fl1, fl2;
535 int cmp = 0;
536
537 TRACE_ENTRY("%p %p", o1, o2);
538
539 cmp = ORDER_scalar( o1->data.cmd.cmd_code, o2->data.cmd.cmd_code );
540 if (cmp)
541 return cmp;
542
543 /* Same command code, we must compare the value of the 'R' flag */
544 fl1 = o1->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST;
545 fl2 = o2->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST;
546
547 /* We want requests first, so we reverse the operators here */
548 return ORDER_scalar(fl2, fl1);
549
550 }
551
552 /* Compare two rule object by the AVP name that they refer (checks already performed) */
553 static int order_rule_by_avpn ( struct dict_object *o1, struct dict_object *o2 )
554 {
555 TRACE_ENTRY("%p %p", o1, o2);
556
557 return strcmp( o1->data.rule.rule_avp->data.avp.avp_name, o2->data.rule.rule_avp->data.avp.avp_name );
558 }
559
560 /*******************************************************************************************************/
561 /*******************************************************************************************************/
562 /* */
563 /* Search functions */
564 /* */
565 /*******************************************************************************************************/
566 /*******************************************************************************************************/
567
568 /* Functions used to search for objects in the lists, according to some criteria */
569
570 /* On a general note, if result is not NULL, ENOENT is not returned but *result is NULL. */
571
572 /* The following macros assume that "what", "ret", "result" (variables), and "end" (label) exist
573 in the local context where they are called. They are meant to be called only from the functions that follow. */
574
575 /* For searchs of type "xxx_OF_xxx": children's parent or default parent */
576 #define SEARCH_childs_parent( type_of_child, default_parent ) { \
577 struct dict_object *__child = (struct dict_object *) what; \
578 CHECK_PARAMS_DO( verify_object(__child) && \
579 (__child->type == (type_of_child)), \
580 { ret = EINVAL; goto end; } ); \
581 ret = 0; \
582 if (result) \
583 *result = (__child->parent ? __child->parent :(default_parent));\
584 }
585
586 /* For search of strings in lists. isindex= 1 if the string is the ordering key of the list */
587 #define SEARCH_string( str, sentinel, datafield, isindex ) { \
588 char * __str = (char *) str; \
589 int __cmp; \
590 struct fd_list * __li; \
591 ret = 0; \
592 for (__li = (sentinel); __li->next != (sentinel); __li = __li->next) { \
593 __cmp = strcmp(__str, _O(__li->next->o)->data. datafield ); \
594 if (__cmp == 0) { \
595 if (result) \
596 *result = _O(__li->next->o); \
597 goto end; \
598 } \
599 if ((isindex) && (__cmp < 0)) \
600 break; \
601 } \
602 if (result) \
603 *result = NULL; \
604 else \
605 ret = ENOENT; \
606 }
607
608 /* For search of octetstrings in lists (not \0 terminated). */
609 #define SEARCH_ocstring( ostr, length, sentinel, osdatafield, isindex ) { \
610 unsigned char * __ostr = (unsigned char *) ostr; \
611 int __cmp; \
612 size_t __len; \
613 struct fd_list * __li; \
614 ret = 0; \
615 for (__li = (sentinel); __li->next != (sentinel); __li = __li->next) { \
616 __len = _O(__li->next->o)->data. osdatafield .len; \
617 if ( __len > (length) ) \
618 __len = (length); \
619 __cmp = memcmp(__ostr, \
620 _O(__li->next->o)->data. osdatafield .data, \
621 __len); \
622 if (! __cmp) { \
623 __cmp = ORDER_scalar( length, \
624 _O(__li->next->o)->data. osdatafield .len); \
625 } \
626 if (__cmp == 0) { \
627 if (result) \
628 *result = _O(__li->next->o); \
629 goto end; \
630 } \
631 if ((isindex) && (__cmp < 0)) \
632 break; \
633 } \
634 if (result) \
635 *result = NULL; \
636 else \
637 ret = ENOENT; \
638 }
639
640 /* For search of AVP name in rule lists. */
641 #define SEARCH_ruleavpname( str, sentinel ) { \
642 char * __str = (char *) str; \
643 int __cmp; \
644 struct fd_list * __li; \
645 ret = 0; \
646 for (__li = (sentinel); __li->next != (sentinel); __li = __li->next) { \
647 __cmp = strcmp(__str, \
648 _O(__li->next->o)->data.rule.rule_avp->data.avp.avp_name);\
649 if (__cmp == 0) { \
650 if (result) \
651 *result = _O(__li->next->o); \
652 goto end; \
653 } \
654 if (__cmp < 0) \
655 break; \
656 } \
657 if (result) \
658 *result = NULL; \
659 else \
660 ret = ENOENT; \
661 }
662
663 /* For search of scalars in lists. isindex= 1 if the value is the ordering key of the list */
664 #define SEARCH_scalar( value, sentinel, datafield, isindex, defaultobj ) { \
665 int __cmp; \
666 struct fd_list * __li; \
667 ret = 0; \
668 if ( ((defaultobj) != NULL) \
669 && (_O(defaultobj)->data. datafield == value)) { \
670 if (result) \
671 *result = _O(defaultobj); \
672 goto end; \
673 } \
674 for (__li = (sentinel); __li->next != (sentinel); __li = __li->next) { \
675 __cmp= ORDER_scalar(value, _O(__li->next->o)->data. datafield );\
676 if (__cmp == 0) { \
677 if (result) \
678 *result = _O(__li->next->o); \
679 goto end; \
680 } \
681 if ((isindex) && (__cmp < 0)) \
682 break; \
683 } \
684 if (result) \
685 *result = NULL; \
686 else \
687 ret = ENOENT; \
688 }
689
690 /* For search of commands in lists by code and flag. R_flag_val = 0 or CMD_FLAG_REQUEST */
691 #define SEARCH_codefl( value, R_flag_val, sentinel) { \
692 int __cmp; \
693 struct fd_list * __li; \
694 ret = 0; \
695 for ( __li = (sentinel); \
696 __li->next != (sentinel); \
697 __li = __li->next) { \
698 __cmp = ORDER_scalar(value, \
699 _O(__li->next->o)->data.cmd.cmd_code ); \
700 if (__cmp == 0) { \
701 uint8_t __mask, __val; \
702 __mask = _O(__li->next->o)->data.cmd.cmd_flag_mask; \
703 __val = _O(__li->next->o)->data.cmd.cmd_flag_val; \
704 if ( ! (__mask & CMD_FLAG_REQUEST) ) \
705 continue; \
706 if ( ( __val & CMD_FLAG_REQUEST ) != R_flag_val ) \
707 continue; \
708 if (result) \
709 *result = _O(__li->next->o); \
710 goto end; \
711 } \
712 if (__cmp < 0) \
713 break; \
714 } \
715 if (result) \
716 *result = NULL; \
717 else \
718 ret = ENOENT; \
719 }
720
721 static int search_vendor ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
722 {
723 int ret = 0;
724 vendor_id_t id;
725
726 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
727
728 switch (criteria) {
729 case VENDOR_BY_ID:
730 id = *(vendor_id_t *) what;
731 SEARCH_scalar( id, &dict->dict_vendors.list[0], vendor.vendor_id, 1, &dict->dict_vendors );
732 break;
733
734 case VENDOR_BY_NAME:
735 /* "what" is a vendor name */
736 SEARCH_string( what, &dict->dict_vendors.list[0], vendor.vendor_name, 0);
737 break;
738
739 case VENDOR_OF_APPLICATION:
740 /* "what" should be an application object */
741 SEARCH_childs_parent( DICT_APPLICATION, &dict->dict_vendors );
742 break;
743
744 default:
745 /* Invalid criteria */
746 CHECK_PARAMS( criteria = 0 );
747 }
748 end:
749 return ret;
750 }
751
752 static int search_application ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
753 {
754 int ret = 0;
755 application_id_t id;
756
757 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
758
759 switch (criteria) {
760 case APPLICATION_BY_ID:
761 id = *(application_id_t *) what;
762
763 SEARCH_scalar( id, &dict->dict_applications.list[0], application.application_id, 1, &dict->dict_applications );
764 break;
765
766 case APPLICATION_BY_NAME:
767 /* "what" is an application name */
768 SEARCH_string( what, &dict->dict_applications.list[0], application.application_name, 0);
769 break;
770
771 case APPLICATION_OF_TYPE:
772 /* "what" should be a type object */
773 SEARCH_childs_parent( DICT_TYPE, &dict->dict_applications );
774 break;
775
776 case APPLICATION_OF_COMMAND:
777 /* "what" should be a command object */
778 SEARCH_childs_parent( DICT_COMMAND, &dict->dict_applications );
779 break;
780
781 default:
782 /* Invalid criteria */
783 CHECK_PARAMS( criteria = 0 );
784 }
785 end:
786 return ret;
787 }
788
789 static int search_type ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
790 {
791 int ret = 0;
792
793 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
794
795 switch (criteria) {
796 case TYPE_BY_NAME:
797 /* "what" is a type name */
798 SEARCH_string( what, &dict->dict_types, type.type_name, 1);
799 break;
800
801 case TYPE_OF_ENUMVAL:
802 /* "what" should be a type_enum object */
803 SEARCH_childs_parent( DICT_ENUMVAL, NULL );
804 break;
805
806 case TYPE_OF_AVP:
807 /* "what" should be an avp object */
808 SEARCH_childs_parent( DICT_AVP, NULL );
809 break;
810
811
812 default:
813 /* Invalid criteria */
814 CHECK_PARAMS( criteria = 0 );
815 }
816 end:
817 return ret;
818 }
819
820 static int search_enumval ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
821 {
822 int ret = 0;
823
824 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
825
826 switch (criteria) {
827 case ENUMVAL_BY_STRUCT:
828 {
829 struct dict_object * parent = NULL;
830 struct dict_enumval_request * _what = (struct dict_enumval_request *) what;
831
832 CHECK_PARAMS( _what && ( _what->type_obj || _what->type_name ) );
833
834 if (_what->type_obj != NULL) {
835 parent = _what->type_obj;
836 CHECK_PARAMS( verify_object(parent) && (parent->type == DICT_TYPE) );
837 } else {
838 /* We received only the type name, we must find it first */
839 CHECK_FCT_DO( search_type( dict, TYPE_BY_NAME, _what->type_name, &parent ),
840 CHECK_PARAMS( 0 ) );
841 }
842
843 /* From here the "parent" object is valid */
844
845 if ( _what->search.enum_name != NULL ) {
846 /* We are looking for this string */
847 SEARCH_string( _what->search.enum_name, &parent->list[1], enumval.enum_name, 1 );
848 } else {
849 /* We are looking for the value in enum_value */
850 switch (parent->data.type.type_base) {
851 case AVP_TYPE_OCTETSTRING:
852 SEARCH_ocstring( _what->search.enum_value.os.data,
853 _what->search.enum_value.os.len,
854 &parent->list[2],
855 enumval.enum_value.os ,
856 1 );
857 break;
858
859 case AVP_TYPE_INTEGER32:
860 SEARCH_scalar( _what->search.enum_value.i32,
861 &parent->list[2],
862 enumval.enum_value.i32,
863 1,
864 (struct dict_object *)NULL);
865 break;
866
867 case AVP_TYPE_INTEGER64:
868 SEARCH_scalar( _what->search.enum_value.i64,
869 &parent->list[2],
870 enumval.enum_value.i64,
871 1,
872 (struct dict_object *)NULL);
873 break;
874
875 case AVP_TYPE_UNSIGNED32:
876 SEARCH_scalar( _what->search.enum_value.u32,
877 &parent->list[2],
878 enumval.enum_value.u32,
879 1,
880 (struct dict_object *)NULL);
881 break;
882
883 case AVP_TYPE_UNSIGNED64:
884 SEARCH_scalar( _what->search.enum_value.u64,
885 &parent->list[2],
886 enumval.enum_value.u64,
887 1,
888 (struct dict_object *)NULL);
889 break;
890
891 case AVP_TYPE_FLOAT32:
892 SEARCH_scalar( _what->search.enum_value.f32,
893 &parent->list[2],
894 enumval.enum_value.f32,
895 1,
896 (struct dict_object *)NULL);
897 break;
898
899 case AVP_TYPE_FLOAT64:
900 SEARCH_scalar( _what->search.enum_value.f64,
901 &parent->list[2],
902 enumval.enum_value.f64,
903 1,
904 (struct dict_object *)NULL);
905 break;
906
907 default:
908 /* Invalid parent type basetype */
909 CHECK_PARAMS( parent = NULL );
910 }
911 }
912
913 }
914 break;
915
916
917 default:
918 /* Invalid criteria */
919 CHECK_PARAMS( criteria = 0 );
920 }
921 end:
922 return ret;
923 }
924
925 static int search_avp ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
926 {
927 int ret = 0;
928
929 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
930
931 switch (criteria) {
932 case AVP_BY_CODE:
933 {
934 avp_code_t code;
935 code = *(avp_code_t *) what;
936
937 SEARCH_scalar( code, &dict->dict_vendors.list[1], avp.avp_code, 1, (struct dict_object *)NULL );
938 }
939 break;
940
941 case AVP_BY_NAME:
942 /* "what" is the AVP name, vendor 0 */
943 SEARCH_string( what, &dict->dict_vendors.list[2], avp.avp_name, 1);
944 break;
945
946 case AVP_BY_CODE_AND_VENDOR:
947 case AVP_BY_NAME_AND_VENDOR:
948 {
949 struct dict_avp_request * _what = (struct dict_avp_request *) what;
950 struct dict_object * vendor = NULL;
951
952 CHECK_PARAMS( (criteria != AVP_BY_NAME_AND_VENDOR) || _what->avp_name );
953
954 /* Now look for the vendor first */
955 CHECK_FCT( search_vendor( dict, VENDOR_BY_ID, &_what->avp_vendor, &vendor ) );
956 if (vendor == NULL) {
957 if (result)
958 *result = NULL;
959 else
960 ret = ENOENT;
961 goto end;
962 }
963
964 /* We now have our vendor = head of the appropriate avp list */
965 if (criteria == AVP_BY_NAME_AND_VENDOR) {
966 SEARCH_string( _what->avp_name, &vendor->list[2], avp.avp_name, 1);
967 } else {
968 /* AVP_BY_CODE_AND_VENDOR */
969 SEARCH_scalar( _what->avp_code, &vendor->list[1], avp.avp_code, 1, (struct dict_object *)NULL );
970 }
971 }
972 break;
973
974 default:
975 /* Invalid criteria */
976 CHECK_PARAMS( criteria = 0 );
977 }
978 end:
979 return ret;
980 }
981
982 static int search_cmd ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
983 {
984 int ret = 0;
985
986 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
987
988 switch (criteria) {
989 case CMD_BY_NAME:
990 /* "what" is a command name */
991 SEARCH_string( what, &dict->dict_cmd_name, cmd.cmd_name, 1);
992 break;
993
994 case CMD_BY_CODE_R:
995 case CMD_BY_CODE_A:
996 {
997 command_code_t code;
998 uint8_t searchfl = 0;
999
1000 /* The command code that we are searching */
1001 code = *(command_code_t *) what;
1002
1003 /* The flag (request or answer) of the command we are searching */
1004 if (criteria == CMD_BY_CODE_R) {
1005 searchfl = CMD_FLAG_REQUEST;
1006 }
1007
1008 /* perform the search */
1009 SEARCH_codefl( code, searchfl, &dict->dict_cmd_code );
1010 }
1011 break;
1012
1013 case CMD_ANSWER:
1014 {
1015 /* "what" is a command object of type "request" */
1016 struct dict_object * req = (struct dict_object *) what;
1017 struct dict_object * ans = NULL;
1018
1019 CHECK_PARAMS( verify_object(req)
1020 && (req->type == DICT_COMMAND)
1021 && (req->data.cmd.cmd_flag_mask & CMD_FLAG_REQUEST)
1022 && (req->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST) );
1023
1024 /* The answer is supposed to be the next element in the list, if it exists */
1025 ans = req->list[1].next->o;
1026 if ( ans == NULL ) {
1027 TRACE_DEBUG( FULL, "the request was the last element in the list" );
1028 ret = ENOENT;
1029 goto end;
1030 }
1031
1032 /* Now check that the ans element is really the correct one */
1033 if ( (ans->data.cmd.cmd_code != req->data.cmd.cmd_code)
1034 || (!(ans->data.cmd.cmd_flag_mask & CMD_FLAG_REQUEST))
1035 || ( ans->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST ) ) {
1036 TRACE_DEBUG( FULL, "the answer does not follow the request in the list" );
1037 ret = ENOENT;
1038 goto end;
1039 }
1040
1041 if (result)
1042 *result = ans;
1043 ret = 0;
1044 }
1045 break;
1046
1047 default:
1048 /* Invalid criteria */
1049 CHECK_PARAMS( criteria = 0 );
1050 }
1051 end:
1052 return ret;
1053 }
1054
1055 static int search_rule ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
1056 {
1057 int ret = 0;
1058
1059 TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
1060
1061 switch (criteria) {
1062 case RULE_BY_AVP_AND_PARENT:
1063 {
1064 struct dict_object * parent = NULL;
1065 struct dict_object * avp = NULL;
1066 struct dict_rule_request * _what = (struct dict_rule_request *) what;
1067
1068 CHECK_PARAMS( _what
1069 && (parent = _what->rule_parent)
1070 && (avp = _what->rule_avp ) );
1071
1072 CHECK_PARAMS( verify_object(parent)
1073 && ((parent->type == DICT_COMMAND)
1074 || ((parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED))) );
1075
1076 CHECK_PARAMS( verify_object(avp) && (avp->type == DICT_AVP) );
1077
1078 /* Perform the search */
1079 SEARCH_ruleavpname( avp->data.avp.avp_name, &parent->list[2]);
1080
1081 }
1082 break;
1083
1084 default:
1085 /* Invalid criteria */
1086 CHECK_PARAMS( criteria = 0 );
1087 }
1088 end:
1089 return ret;
1090 }
1091
1092 /*******************************************************************************************************/
1093 /*******************************************************************************************************/
1094 /* */
1095 /* Dump / debug functions */
1096 /* */
1097 /*******************************************************************************************************/
1098 /*******************************************************************************************************/
1099 /* The following functions are used to debug the module, and allow to print out the content of the dictionary */
1100 static void dump_vendor_data ( void * data )
1101 {
1102 struct dict_vendor_data * vendor = (struct dict_vendor_data *)data;
1103
1104 fd_log_debug("data: %-6u \"%s\"", vendor->vendor_id, vendor->vendor_name);
1105 }
1106 static void dump_application_data ( void * data )
1107 {
1108 struct dict_application_data * appli = (struct dict_application_data *) data;
1109 fd_log_debug("data: %-6u \"%s\"", appli->application_id, appli->application_name);
1110 }
1111 static void dump_type_data ( void * data )
1112 {
1113 struct dict_type_data * type = ( struct dict_type_data * ) data;
1114
1115 fd_log_debug("data: %-12s \"%s\"",
1116 type_base_name[type->type_base],
1117 type->type_name);
1118 }
1119 static void dump_enumval_data ( struct dict_enumval_data * enumval, enum dict_avp_basetype type )
1120 {
1121 const int LEN_MAX = 20;
1122 fd_log_debug("data: (%-12s) \"%s\" -> ", type_base_name[type], enumval->enum_name);
1123 switch (type) {
1124 case AVP_TYPE_OCTETSTRING:
1125 {
1126 int i, n=LEN_MAX;
1127 if (enumval->enum_value.os.len < LEN_MAX)
1128 n = enumval->enum_value.os.len;
1129 for (i=0; i < n; i++)
1130 fd_log_debug("0x%02.2X/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i]));
1131 if (n == LEN_MAX)
1132 fd_log_debug("...");
1133 }
1134 break;
1135
1136 case AVP_TYPE_INTEGER32:
1137 fd_log_debug("%i", enumval->enum_value.i32);
1138 break;
1139
1140 case AVP_TYPE_INTEGER64:
1141 fd_log_debug("%lli", enumval->enum_value.i64);
1142 break;
1143
1144 case AVP_TYPE_UNSIGNED32:
1145 fd_log_debug("%u", enumval->enum_value.u32);
1146 break;
1147
1148 case AVP_TYPE_UNSIGNED64:
1149 fd_log_debug("%llu", enumval->enum_value.u64);
1150 break;
1151
1152 case AVP_TYPE_FLOAT32:
1153 fd_log_debug("%f", enumval->enum_value.f32);
1154 break;
1155
1156 case AVP_TYPE_FLOAT64:
1157 fd_log_debug("%g", enumval->enum_value.f64);
1158 break;
1159
1160 default:
1161 fd_log_debug("??? (ERROR unknown type %d)", type);
1162 }
1163 }
1164 static void dump_avp_data ( void * data )
1165 {
1166 struct dict_avp_data * avp = (struct dict_avp_data * ) data;
1167 fd_log_debug("data: v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %-6u \"%s\"",
1168 DUMP_AVPFL_val(avp->avp_flag_val),
1169 DUMP_AVPFL_val(avp->avp_flag_mask),
1170 type_base_name[avp->avp_basetype],
1171 avp->avp_code,
1172 avp->avp_name );
1173 }
1174 static void dump_command_data ( void * data )
1175 {
1176 struct dict_cmd_data * cmd = (struct dict_cmd_data *) data;
1177 fd_log_debug("data: v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %-6u \"%s\"",
1178 DUMP_CMDFL_val(cmd->cmd_flag_val), DUMP_CMDFL_val(cmd->cmd_flag_mask), cmd->cmd_code, cmd->cmd_name);
1179 }
1180 static void dump_rule_data ( void * data )
1181 {
1182 struct dict_rule_data * rule = (struct dict_rule_data * )data;
1183 fd_log_debug("data: pos:%d ord:%d m/M:%2d/%2d avp:\"%s\"",
1184 rule->rule_position,
1185 rule->rule_order,
1186 rule->rule_min,
1187 rule->rule_max,
1188 rule->rule_avp->data.avp.avp_name);
1189 }
1190
1191 static void dump_object ( struct dict_object * obj, int parents, int depth, int indent );
1192
1193 static void dump_list ( struct fd_list * sentinel, int parents, int depth, int indent )
1194 {
1195 struct fd_list * li = sentinel;
1196 /* We don't lock here, the caller must have taken the dictionary lock for reading already */
1197 while (li->next != sentinel)
1198 {
1199 li = li->next;
1200 dump_object( _O(li->o), parents, depth, indent );
1201 }
1202 }
1203
1204 static void dump_object ( struct dict_object * obj, int parents, int depth, int indent )
1205 {
1206 if (obj == NULL)
1207 return;
1208
1209 if (parents)
1210 dump_object (obj->parent, parents-1, 0, indent + 1 );
1211
1212 fd_log_debug("%*s@%p: %s%s (p:%-9p) ",
1213 indent,
1214 "",
1215 obj,
1216 verify_object(obj) ? "" : "INVALID ",
1217 _OBINFO(obj).name,
1218 obj->parent);
1219
1220 if (obj->type == DICT_ENUMVAL)
1221 dump_enumval_data ( &obj->data.enumval, obj->parent->data.type.type_base );
1222 else
1223 _OBINFO(obj).dump_data(&obj->data);
1224
1225 fd_log_debug("\n");
1226
1227 if (depth) {
1228 int i;
1229 for (i=0; i<NB_LISTS_PER_OBJ; i++) {
1230 if ((obj->list[i].o == NULL) && (obj->list[i].next != &obj->list[i])) {
1231 fd_log_debug("%*s>%p: list[%d]:\n", indent, "", obj, i);
1232 dump_list(&obj->list[i], parents, depth - 1, indent + 2);
1233 }
1234 }
1235 }
1236 }
1237
1238 void fd_dict_dump_object(struct dict_object * obj)
1239 {
1240 fd_log_debug("Dictionary object %p dump:\n", obj);
1241 dump_object( obj, 1, 2, 2 );
1242 }
1243
1244 void fd_dict_dump(struct dictionary * dict)
1245 {
1246 int i;
1247
1248 CHECK_PARAMS_DO(dict && (dict->dict_eyec == DICT_EYECATCHER), return);
1249
1250 CHECK_POSIX_DO( pthread_rwlock_rdlock( &dict->dict_lock ), /* ignore */ );
1251
1252 fd_log_debug("######################################################\n");
1253 fd_log_debug("###### Dumping vendors, AVPs and related rules #######\n");
1254
1255 dump_object( &dict->dict_vendors, 0, 3, 0 );
1256
1257 fd_log_debug("###### Dumping applications #######\n");
1258
1259 dump_object( &dict->dict_applications, 0, 1, 0 );
1260
1261 fd_log_debug("###### Dumping types #######\n");
1262
1263 dump_list( &dict->dict_types, 0, 2, 0 );
1264
1265 fd_log_debug("###### Dumping commands per name #######\n");
1266
1267 dump_list( &dict->dict_cmd_name, 0, 2, 0 );
1268
1269 fd_log_debug("###### Dumping commands per code and flags #######\n");
1270
1271 dump_list( &dict->dict_cmd_code, 0, 0, 0 );
1272
1273 fd_log_debug("###### Statistics #######\n");
1274
1275 for (i=1; i<=DICT_TYPE_MAX; i++)
1276 fd_log_debug(" %5d objects of type %s\n", dict->dict_count[i], dict_obj_info[i].name);
1277
1278 fd_log_debug("######################################################\n");
1279
1280 /* Free the rwlock */
1281 CHECK_POSIX_DO( pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */ );
1282 }
1283
1284 /*******************************************************************************************************/
1285 /*******************************************************************************************************/
1286 /* */
1287 /* Exported functions */
1288 /* */
1289 /*******************************************************************************************************/
1290 /*******************************************************************************************************/
1291
1292 /* These are the functions exported outside libfreeDiameter. */
1293
1294 /* Get the data associated to an object */
1295 int fd_dict_gettype ( struct dict_object * object, enum dict_object_type * type)
1296 {
1297 TRACE_ENTRY("%p %p", object, type);
1298
1299 CHECK_PARAMS( type && verify_object(object) );
1300
1301 /* Copy the value and return */
1302 *type = object->type;
1303 return 0;
1304 }
1305
1306 int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict)
1307 {
1308 TRACE_ENTRY("%p %p", object, dict);
1309
1310 CHECK_PARAMS( dict && verify_object(object) );
1311
1312 /* Copy the value and return */
1313 *dict = object->dico;
1314 return 0;
1315 }
1316
1317
1318 /* Get the data associated to an object */
1319 int fd_dict_getval ( struct dict_object * object, void * val)
1320 {
1321 TRACE_ENTRY("%p %p", object, val);
1322
1323 CHECK_PARAMS( val && verify_object(object) );
1324
1325 /* Copy the value and return */
1326 memcpy(val, &object->data, _OBINFO(object).datasize);;
1327 return 0;
1328 }
1329
1330 /* Add a new object in the dictionary */
1331 int fd_dict_new ( struct dictionary * dict, enum dict_object_type type, void * data, struct dict_object * parent, struct dict_object **ref )
1332 {
1333 int ret = 0;
1334 struct dict_object * new = NULL;
1335 struct dict_object * vendor = NULL;
1336
1337 TRACE_ENTRY("%p %d(%s) %p %p %p", dict, type, dict_obj_info[CHECK_TYPE(type) ? type : 0].name, data, parent, ref);
1338
1339 /* Check parameters */
1340 CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && CHECK_TYPE(type) && data );
1341
1342 /* Check the "parent" parameter */
1343 switch (dict_obj_info[type].parent) {
1344 case 0: /* parent is forbidden */
1345 CHECK_PARAMS( parent == NULL );
1346
1347 case 1: /* parent is optional */
1348 if (parent == NULL)
1349 break;
1350
1351 case 2: /* parent is mandatory */
1352 CHECK_PARAMS( verify_object(parent) );
1353
1354 if (type == DICT_RULE ) { /* Special case : grouped AVP or Command parents are allowed */
1355 CHECK_PARAMS( (parent->type == DICT_COMMAND )
1356 || ( (parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED ) ) );
1357 } else {
1358 CHECK_PARAMS( parent->type == dict_obj_info[type].parenttype );
1359 }
1360 }
1361
1362 /* For AVP object, we must also check that the "vendor" referenced exists */
1363 if (type == DICT_AVP) {
1364 CHECK_FCT_DO( fd_dict_search( dict, DICT_VENDOR, VENDOR_BY_ID, &(((struct dict_avp_data *)data)->avp_vendor), (void*)&vendor, ENOENT ),
1365 CHECK_PARAMS( vendor = NULL ) );
1366
1367 /* Also check if a parent is provided, that the type are the same */
1368 if (parent) {
1369 CHECK_PARAMS( parent->data.type.type_base == ((struct dict_avp_data *)data)->avp_basetype );
1370 }
1371 }
1372
1373 /* For RULE object, we must also check that the "avp" referenced exists */
1374 if (type == DICT_RULE) {
1375 CHECK_PARAMS( verify_object(((struct dict_rule_data *)data)->rule_avp) );
1376 CHECK_PARAMS( ((struct dict_rule_data *)data)->rule_avp->type == DICT_AVP );
1377 }
1378
1379 /* For COMMAND object, check that the 'R' flag is fixed */
1380 if (type == DICT_COMMAND) {
1381 CHECK_PARAMS( ((struct dict_cmd_data *)data)->cmd_flag_mask & CMD_FLAG_REQUEST );
1382 }
1383
1384 /* Parameters are valid, create the new object */
1385 CHECK_MALLOC( new = malloc(sizeof(struct dict_object)) );
1386
1387 /* Initialize the data of the new object */
1388 init_object(new, type);
1389 init_object_data(&new->data, data, type);
1390 new->dico = dict;
1391 new->parent = parent;
1392
1393 /* We will change the dictionary => acquire the write lock */
1394 CHECK_POSIX_DO( ret = pthread_rwlock_wrlock(&dict->dict_lock), goto error_free );
1395
1396 /* Now link the object -- this also checks that no object with same keys already exists */
1397 switch (type) {
1398 case DICT_VENDOR:
1399 /* A vendor object is linked in the g_dict_vendors.list[0], by their id */
1400 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &dict->dict_vendors.list[0], &new->list[0], (int (*)(void*, void *))order_vendor_by_id, (void **)ref ),
1401 goto error_unlock );
1402 break;
1403
1404 case DICT_APPLICATION:
1405 /* An application object is linked in the g_dict_applciations.list[0], by their id */
1406 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &dict->dict_applications.list[0], &new->list[0], (int (*)(void*, void *))order_appli_by_id, (void **)ref ),
1407 goto error_unlock );
1408 break;
1409
1410 case DICT_TYPE:
1411 /* A type object is linked in g_list_types by its name */
1412 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &dict->dict_types, &new->list[0], (int (*)(void*, void *))order_type_by_name, (void **)ref ),
1413 goto error_unlock );
1414 break;
1415
1416 case DICT_ENUMVAL:
1417 /* A type_enum object is linked in it's parent 'type' object lists 1 and 2 by its name and values */
1418 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &parent->list[1], &new->list[0], (int (*)(void*, void *))order_enum_by_name, (void **)ref ),
1419 goto error_unlock );
1420 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &parent->list[2], &new->list[1], (int (*)(void*, void *))order_enum_by_val, (void **)ref ),
1421 { fd_list_unlink(&new->list[0]); goto error_unlock; } );
1422 break;
1423
1424 case DICT_AVP:
1425 /* An avp object is linked in lists 1 and 2 of its vendor, by code and name */
1426 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &vendor->list[1], &new->list[0], (int (*)(void*, void *))order_avp_by_code, (void **)ref ),
1427 goto error_unlock );
1428 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &vendor->list[2], &new->list[1], (int (*)(void*, void *))order_avp_by_name, (void **)ref ),
1429 { fd_list_unlink(&new->list[0]); goto error_unlock; } );
1430 break;
1431
1432 case DICT_COMMAND:
1433 /* A command object is linked in g_list_cmd_name and g_list_cmd_code by its name and code */
1434 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &dict->dict_cmd_code, &new->list[1], (int (*)(void*, void *))order_cmd_by_codefl, (void **)ref ),
1435 goto error_unlock );
1436 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &dict->dict_cmd_name, &new->list[0], (int (*)(void*, void *))order_cmd_by_name, (void **)ref ),
1437 { fd_list_unlink(&new->list[1]); goto error_unlock; } );
1438 break;
1439
1440 case DICT_RULE:
1441 /* A rule object is linked in list[2] of its parent command or AVP by the name of the AVP it refers */
1442 CHECK_FCT_DO( ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avpn, (void **)ref ),
1443 goto error_unlock );
1444 break;
1445
1446 default:
1447 ASSERT(0);
1448 }
1449
1450 /* A new object has been created, increment the global counter */
1451 dict->dict_count[type]++;
1452
1453 /* Unlock the dictionary */
1454 CHECK_POSIX_DO( ret = pthread_rwlock_unlock(&dict->dict_lock), goto error_free );
1455
1456 /* Save the pointer to the new object */
1457 if (ref)
1458 *ref = new;
1459
1460 return 0;
1461
1462 error_unlock:
1463 CHECK_POSIX_DO( pthread_rwlock_unlock(&dict->dict_lock), /* continue */ );
1464 error_free:
1465 free(new);
1466 return ret;
1467 }
1468
1469 int fd_dict_search ( struct dictionary * dict, enum dict_object_type type, int criteria, void * what, struct dict_object **result, int retval )
1470 {
1471 int ret = 0;
1472
1473 TRACE_ENTRY("%p %d(%s) %d %p %p %d", dict, type, dict_obj_info[CHECK_TYPE(type) ? type : 0].name, criteria, what, result, retval);
1474
1475 /* Check param */
1476 CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && CHECK_TYPE(type) );
1477
1478 /* Lock the dictionary for reading */
1479 CHECK_POSIX( pthread_rwlock_rdlock(&dict->dict_lock) );
1480
1481 /* Now call the type-specific search function */
1482 ret = dict_obj_info[type].search_fct (dict, criteria, what, result);
1483
1484 /* Unlock */
1485 CHECK_POSIX( pthread_rwlock_unlock(&dict->dict_lock) );
1486
1487 /* Update the return value as needed */
1488 if ((result != NULL) && (*result == NULL))
1489 ret = retval;
1490
1491 return ret;
1492 }
1493
1494 /*******************************************************************************************************/
1495 /*******************************************************************************************************/
1496 /* */
1497 /* The init/fini functions */
1498 /* */
1499 /*******************************************************************************************************/
1500 /*******************************************************************************************************/
1501
1502 /* Initialize the dictionary */
1503 int fd_dict_init ( struct dictionary ** dict)
1504 {
1505 struct dictionary * new = NULL;
1506
1507 TRACE_ENTRY("");
1508
1509 /* Sanity checks */
1510 ASSERT( (sizeof(type_base_name) / sizeof(type_base_name[0])) == (AVP_TYPE_MAX + 1) );
1511 ASSERT( (sizeof(dict_obj_info) / sizeof(dict_obj_info[0])) == (DICT_TYPE_MAX + 1) );
1512 CHECK_PARAMS(dict);
1513
1514 /* Allocate the memory for the dictionary */
1515 CHECK_MALLOC( new = malloc(sizeof(struct dictionary)) );
1516 memset(new, 0, sizeof(struct dictionary));
1517
1518 new->dict_eyec = DICT_EYECATCHER;
1519
1520 /* Initialize the lock for the dictionary */
1521 CHECK_POSIX( pthread_rwlock_init(&new->dict_lock, NULL) );
1522
1523 /* Initialize the sentinel for vendors and AVP lists */
1524 init_object( &new->dict_vendors, DICT_VENDOR );
1525 new->dict_vendors.data.vendor.vendor_name = "(no vendor)";
1526 new->dict_vendors.list[0].o = NULL; /* overwrite since element is also sentinel for this list. */
1527
1528
1529 /* Initialize the sentinel for applciations */
1530 init_object( &new->dict_applications, DICT_APPLICATION );
1531 new->dict_applications.data.application.application_name = "Diameter Common Messages";
1532 new->dict_applications.list[0].o = NULL; /* overwrite since since element is also sentinel for this list. */
1533
1534 /* Initialize the sentinel for types */
1535 fd_list_init ( &new->dict_types, NULL );
1536
1537 /* Initialize the sentinels for commands */
1538 fd_list_init ( &new->dict_cmd_name, NULL );
1539 fd_list_init ( &new->dict_cmd_code, NULL );
1540
1541 /* Initialize the error command object */
1542 init_object( &new->dict_cmd_error, DICT_COMMAND );
1543 new->dict_cmd_error.data.cmd.cmd_name="(generic error format)";
1544 new->dict_cmd_error.data.cmd.cmd_flag_mask=CMD_FLAG_ERROR | CMD_FLAG_REQUEST | CMD_FLAG_RETRANSMIT;
1545 new->dict_cmd_error.data.cmd.cmd_flag_val =CMD_FLAG_ERROR;
1546
1547 *dict = new;
1548
1549 /* Done */
1550 return 0;
1551 }
1552
1553 /* Destroy a dictionary */
1554 int fd_dict_fini ( struct dictionary ** dict)
1555 {
1556 int i;
1557
1558 TRACE_ENTRY("");
1559 CHECK_PARAMS( dict && *dict && ((*dict)->dict_eyec == DICT_EYECATCHER) );
1560
1561 /* Acquire the write lock to make sure no other operation is ongoing */
1562 CHECK_POSIX( pthread_rwlock_wrlock(&(*dict)->dict_lock) );
1563
1564 /* Empty all the lists, free the elements */
1565 destroy_list ( &(*dict)->dict_cmd_error.list[2] );
1566 destroy_list ( &(*dict)->dict_cmd_code );
1567 destroy_list ( &(*dict)->dict_cmd_name );
1568 destroy_list ( &(*dict)->dict_types );
1569 for (i=0; i< NB_LISTS_PER_OBJ; i++) {
1570 destroy_list ( &(*dict)->dict_applications.list[i] );
1571 destroy_list ( &(*dict)->dict_vendors.list[i] );
1572 }
1573
1574 /* Dictionary is empty, now destroy the lock */
1575 CHECK_POSIX( pthread_rwlock_unlock(&(*dict)->dict_lock) );
1576 CHECK_POSIX( pthread_rwlock_destroy(&(*dict)->dict_lock) );
1577
1578 free(*dict);
1579 *dict = NULL;
1580
1581 return 0;
1582 }
1583
1584 /*******************************************************************************************************/
1585 /*******************************************************************************************************/
1586 /* */
1587 /* Other functions */
1588 /* */
1589 /*******************************************************************************************************/
1590 /*******************************************************************************************************/
1591
1592 /* Iterate a callback on the rules for an object */
1593 int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) )
1594 {
1595 int ret = 0;
1596 struct fd_list * li;
1597
1598 TRACE_ENTRY("%p %p %p", parent, data, cb);
1599
1600 /* Check parameters */
1601 CHECK_PARAMS( verify_object(parent) );
1602 CHECK_PARAMS( (parent->type == DICT_COMMAND)
1603 || ((parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED)) );
1604 TRACE_DEBUG (FULL, "Iterating on rules of %s: '%s'.",
1605 _OBINFO(parent).name,
1606 parent->type == DICT_COMMAND ?
1607 parent->data.cmd.cmd_name
1608 : parent->data.avp.avp_name);
1609
1610 /* Acquire the read lock */
1611 CHECK_POSIX( pthread_rwlock_rdlock(&parent->dico->dict_lock) );
1612
1613 /* go through the list and call the cb on each rule data */
1614 for (li = &(parent->list[2]); li->next != &(parent->list[2]); li = li->next) {
1615 ret = (*cb)(data, &(_O(li->next->o)->data.rule));
1616 if (ret != 0)
1617 break;
1618 }
1619
1620 /* Release the lock */
1621 CHECK_POSIX( pthread_rwlock_unlock(&parent->dico->dict_lock) );
1622
1623 return ret;
1624 }
1625
1626 /* Create the list of vendors. Returns a 0-terminated array, that must be freed after use. Returns NULL on error. */
1627 uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict)
1628 {
1629 uint32_t * ret = NULL;
1630 int i = 0;
1631 struct fd_list * li;
1632
1633 TRACE_ENTRY();
1634
1635 /* Acquire the read lock */
1636 CHECK_POSIX_DO( pthread_rwlock_rdlock(&dict->dict_lock), return NULL );
1637
1638 /* Allocate an array to contain all the elements */
1639 CHECK_MALLOC_DO( ret = calloc( dict->dict_count[DICT_VENDOR] + 1, sizeof(uint32_t) ), goto out );
1640
1641 /* Copy the vendors IDs */
1642 for (li = dict->dict_vendors.list[0].next; li != &(dict->dict_vendors.list[0]); li = li->next) {
1643 ret[i] = _O(li->o)->data.vendor.vendor_id;
1644 i++;
1645 ASSERT( i <= dict->dict_count[DICT_VENDOR] );
1646 }
1647 out:
1648 /* Release the lock */
1649 CHECK_POSIX_DO( pthread_rwlock_unlock(&dict->dict_lock), return NULL );
1650
1651 return ret;
1652 }
1653
1654 /* Return the location of the cb list for an object, after checking its type */
1655 int fd_dict_disp_cb(enum dict_object_type type, struct dict_object *obj, struct fd_list ** cb_list)
1656 {
1657 TRACE_ENTRY("%d %p %p", type, obj, cb_list);
1658 CHECK_PARAMS( verify_object(obj) );
1659 CHECK_PARAMS( _OBINFO(obj).type == type );
1660 CHECK_PARAMS( cb_list );
1661 *cb_list = &obj->disp_cbs;
1662 return 0;
1663 }
1664
1665 int fd_dict_get_error_cmd(struct dictionary * dict, struct dict_object **obj)
1666 {
1667 TRACE_ENTRY("%p %p", dict, obj);
1668 CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && obj );
1669 *obj = &dict->dict_cmd_error;
1670 return 0;
1671 }
"Welcome to our mercurial repository"