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