Navigation


source: freeDiameter/libfdproto/dictionary.c

Last change on this file was 1554:566bb46cc73f, checked in by Sebastien Decugis <sdecugis@freediameter.net>, 5 months ago

Updated copyright information

File size: 76.0 KB
Line 
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 */
41const 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 */
57static DECLARE_FD_DUMP_PROTOTYPE(dump_vendor_data, void * data );
58static DECLARE_FD_DUMP_PROTOTYPE(dump_application_data, void * data );
59static DECLARE_FD_DUMP_PROTOTYPE(dump_type_data, void * data );
60  /* the dump function for enum has a different prototype since it need the datatype */
61static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_data, void * data );
62static DECLARE_FD_DUMP_PROTOTYPE(dump_command_data, void * data );
63static DECLARE_FD_DUMP_PROTOTYPE(dump_rule_data, void * data );
64
65/* Forward declarations of search functions */
66static int search_vendor        ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
67static int search_application   ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
68static int search_type          ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
69static int search_enumval       ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
70static int search_avp           ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
71static int search_cmd           ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
72static 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 */
75static 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 */
142static 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 */
171static 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) */
222static 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 */
249static 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 */
285static void destroy_object(struct dict_object * obj);
286
287/* Destroy all objects in a list - the lock must be held */
288static 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 */
301static 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) */
351static 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) */
359static 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) */
367static 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) */
375static 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) */
383static 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) */
419static 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) */
427static 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) */
435static 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) */
443static 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) */
464static 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
485in 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
650static 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        }
682end:
683        return ret;
684}
685
686static 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        }
719end:
720        return ret;
721}
722
723static 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        }
750end:
751        return ret;
752}
753
754static 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        }
855end:
856        return ret;
857}
858
859static 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        }
964end:
965        return ret;
966}
967
968static 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        }
1037end:
1038        return ret;
1039}
1040
1041static 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        }
1074end:
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 */
1086static 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}
1092static 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}
1097static 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}
1105static 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}
1151static 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}
1161static 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}
1167static 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
1178static DECLARE_FD_DUMP_PROTOTYPE(dump_object, struct dict_object * obj, int parents, int depth, int indent );
1179
1180static 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
1197static 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
1234DECLARE_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
1243DECLARE_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;
1284error:
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 */
1293static 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
1309static 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
1314static 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
1319static 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
1324static 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
1329static 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
1334static 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 */
1340static 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
1374typedef DECLARE_FD_DUMP_PROTOTYPE((*dump_val_cb_t), union avp_value *);
1375
1376/* Formatter for the AVP value dump line */
1377static 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 */
1418DECLARE_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 */
1482int 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
1493int 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 */
1506int 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 */
1518int 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
1684error_param:
1685        ret = EINVAL;
1686        goto all_errors;
1687
1688error_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        }
1842all_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        }
1862error_free:
1863        free(new);
1864        return ret;
1865}
1866
1867
1868int 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
1905int 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
1932All 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
1939The following criteria are allowed, with corresponding parent.
1940The parent is either struct dictionary * or struct dict_object *
1941
1942VENDOR_BY_ID : (parent = dictionary) returns list of vendors ordered by ID
1943APPLICATION_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
1947TYPE_BY_NAME : (parent = dictionary) returns list of types ordered by name (osstring order)
1948ENUMVAL_BY_NAME : (parent = type object) return list of constants for this type ordered by name (osstring order)
1949ENUMVAL_BY_VALUE : (parent = type object) return list of constants for this type ordered by values
1950AVP_BY_NAME : (parent = vendor object) return list of AVP for this vendor ordered by name (osstring order)
1951AVP_BY_CODE : (parent = vendor object) return list of AVP for this vendor ordered by code
1952CMD_BY_NAME : (parent = dictionary) returns list of commands ordered by name (osstring order)
1953CMD_BY_CODE_R : (parent = dictionary) returns list of commands ordered by code
1954RULE_BY_AVP_AND_PARENT: (parent = command or grouped AVP object) return list of rules for this object ordered by AVP vendor/code
1955
1956All other criteria are rejected.
1957 */
1958int 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 */
2037int 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 */
2096int 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 */
2135int 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. */
2169uint32_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        }
2189out:
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 */
2197int 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
2207int 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}
Note: See TracBrowser for help on using the repository browser.