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