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