1 /*********************************************************************************************************
2 * Software License Agreement (BSD License)                                                               *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
4 *													 *
5 * Copyright (c) 2013, 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 "tests.h"
37 
38 #define Define_cb( __int, __extra )												\
39 int cb_##__int( struct msg ** msg, struct avp * avp, struct session * session, void * opaque, enum disp_action * action )	\
40 {																\
41 	CHECK( 1, msg ? 1 : 0 );												\
42 	CHECK( 1, action ? 1 : 0 );												\
43 	CHECK( sess, session );													\
44 	if (opaque) {														\
45 		CHECK( 1, opaque == g_opaque ? 1 : 0 );										\
46 	}															\
47 	*action = DISP_ACT_CONT;												\
48 	cbcalled[__int] += 1;													\
49 	do {															\
50 		__extra ;													\
51 	} while (0);														\
52 	return 0;														\
53 }
54 
55 #define NB_CB	10
56 char cbcalled[NB_CB];
57 struct session * sess;
58 void * g_opaque = (void *)"test";
59 
60 /* cb_0 */  Define_cb( 0, );
61 /* cb_1 */  Define_cb( 1, );
62 /* cb_2 */  Define_cb( 2, );
63 /* cb_3 */  Define_cb( 3, );
64 /* cb_4 */  Define_cb( 4, );
65 /* cb_5 */  Define_cb( 5, );
66 /* cb_6 */  Define_cb( 6, return 12345 );
67 /* cb_7 */  Define_cb( 7, { CHECK( 1, avp ? 1 : 0 ); } );
68 /* cb_8 */  Define_cb( 8, { CHECK( 0, fd_msg_free( *msg ) ); *msg = NULL; } );
69 /* cb_9 */  Define_cb( 9, *action = DISP_ACT_SEND );
70 /* max: cb_<NB_CB - 1> */
71 
72 /* Create a new message containing what we want */
new_msg(int appid,struct dict_object * cmd,struct dict_object * avp1,struct dict_object * avp2,int val)73 struct msg * new_msg(int appid, struct dict_object * cmd, struct dict_object * avp1, struct dict_object * avp2, int val)
74 {
75 	struct msg *new;
76 	struct avp *avp;
77 	union avp_value value;
78 	struct msg_hdr * msg_hdr = NULL;
79 
80 	CHECK( 0, fd_msg_new ( cmd, 0, &new ) );
81 	CHECK( 0, fd_msg_hdr ( new, &msg_hdr ) );
82 	msg_hdr->msg_appl = appid;
83 
84 	if (avp1) {
85 		CHECK( 0, fd_msg_avp_new ( avp1, 0, &avp ) );
86 		value.u32 = 0;
87 		CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
88 		CHECK( 0, fd_msg_avp_add ( new, MSG_BRW_LAST_CHILD, avp ) );
89 	}
90 
91 	if (avp2) {
92 		CHECK( 0, fd_msg_avp_new ( avp2, 0, &avp ) );
93 		value.u32 = val;
94 		CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
95 		CHECK( 0, fd_msg_avp_add ( new, MSG_BRW_LAST_CHILD, avp ) );
96 	}
97 
98 	return new;
99 }
100 
101 /* Main test routine */
main(int argc,char * argv[])102 int main(int argc, char *argv[])
103 {
104 	struct dict_object * app1, * app2;
105 	struct dict_object * cmd1, * cmd2;
106 	struct dict_object * avp1, * avp2; /* avp2 is enumerated; they are both unsigned32 types */
107 	struct dict_object * enu1, * enu2;
108 	struct msg * msg = NULL, *error;
109 	enum disp_action action;
110 	struct disp_hdl * hdl[NB_CB];
111 	struct disp_when when;
112 	char * ec, *em;
113 
114 	/* First, initialize the daemon modules */
115 	INIT_FD();
116 
117 	/* Create a dummy session, we don't use it anyway */
118 	#define DUMMY_SID "test.disp"
119 	CHECK( 0, fd_sess_new( &sess, DUMMY_SID, CONSTSTRLEN(DUMMY_SID), NULL, 0 ) );
120 
121 	memset(&when, 0xff, sizeof(when)); /* check that we don't use un-initialized parts */
122 
123 	/* Initialize dictionary objects */
124 	{
125 		struct dict_object * enutype;
126 		struct dict_application_data app1_data = { 1, "Application test 1" };
127 		struct dict_application_data app2_data = { 2, "Application test 2" };
128 		struct dict_cmd_data cmd1_data = { 1, "Command test 1 (req)", CMD_FLAG_REQUEST,	CMD_FLAG_REQUEST };
129 		struct dict_cmd_data cmd2_data = { 1, "Command test 2 (ans)", CMD_FLAG_REQUEST,	0 };
130 		struct dict_type_data type_data = { AVP_TYPE_UNSIGNED32, "Type test", NULL, NULL };
131 		struct dict_avp_data avp1_data = { 10001, 0, "AVP test 1", 0, 0, AVP_TYPE_UNSIGNED32 };
132 		struct dict_avp_data avp2_data = { 10002, 0, "AVP test 2", 0, 0, AVP_TYPE_UNSIGNED32 };
133 		struct dict_enumval_data enu1_data = { "ENU test 1", { .u32 = 1 }};
134 		struct dict_enumval_data enu2_data = { "ENU test 2", { .u32 = 2 }};
135 
136 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app1_data, NULL, &app1 ) );
137 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app2_data, NULL, &app2 ) );
138 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd1_data, NULL, &cmd1 ) );
139 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd2_data, NULL, &cmd2 ) );
140 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data, NULL, &enutype ) );
141 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp1_data, NULL,    &avp1 ) );
142 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp2_data, enutype, &avp2 ) );
143 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &enu1_data, enutype, &enu1 ) );
144 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &enu2_data, enutype, &enu2 ) );
145 	}
146 
147 	/* Register first handler, very simple test */
148 	{
149 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, NULL, &hdl[0] ) );
150 		CHECK( 1, hdl[0] ? 1 : 0 );
151 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
152 		CHECK( NULL, hdl[0] );
153 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, NULL, &hdl[0] ) );
154 
155 		/* Check this handler is called for a message */
156 		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
157 		memset(cbcalled, 0, sizeof(cbcalled));
158 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
159 		CHECK( 1, cbcalled[0] );
160 		CHECK( DISP_ACT_CONT, action );
161 
162 		/* Delete the message */
163 		CHECK( 0, fd_msg_free( msg ) );
164 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
165 	}
166 
167 	/* Handlers for applications */
168 	{
169 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
170 		when.app = app1;
171 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_APPID, &when, NULL, &hdl[1] ) );
172 		when.app = app2;
173 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_APPID, &when, NULL, &hdl[2] ) );
174 		when.avp = avp2;
175 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_APPID, &when, NULL, &hdl[3] ) );
176 		when.avp = avp1;
177 		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_APPID, &when, NULL, &hdl[4] ) );
178 
179 		/* Check the callbacks are called as appropriate */
180 		memset(cbcalled, 0, sizeof(cbcalled));
181 		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
182 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
183 		CHECK( 1, cbcalled[0] );
184 		CHECK( 0, cbcalled[1] );
185 		CHECK( 0, cbcalled[2] );
186 		CHECK( 0, cbcalled[3] );
187 		CHECK( 0, cbcalled[4] );
188 		CHECK( DISP_ACT_CONT, action );
189 		CHECK( 0, fd_msg_free( msg ) );
190 
191 		memset(cbcalled, 0, sizeof(cbcalled));
192 		msg = new_msg( 1, cmd1, avp1, NULL, 0 );
193 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
194 		CHECK( 1, cbcalled[0] );
195 		CHECK( 1, cbcalled[1] );
196 		CHECK( 0, cbcalled[2] );
197 		CHECK( 0, cbcalled[3] );
198 		CHECK( 0, cbcalled[4] );
199 		CHECK( DISP_ACT_CONT, action );
200 		CHECK( 0, fd_msg_free( msg ) );
201 
202 		memset(cbcalled, 0, sizeof(cbcalled));
203 		msg = new_msg( 2, cmd1, avp1, NULL, 0 );
204 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
205 		CHECK( 1, cbcalled[0] );
206 		CHECK( 0, cbcalled[1] );
207 		CHECK( 1, cbcalled[2] );
208 		CHECK( 1, cbcalled[3] );
209 		CHECK( 1, cbcalled[4] );
210 		CHECK( DISP_ACT_CONT, action );
211 		CHECK( 0, fd_msg_free( msg ) );
212 
213 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
214 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
215 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
216 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
217 		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
218 	}
219 
220 	/* Handlers for commands */
221 	{
222 		when.app = NULL;
223 		when.command = NULL;
224 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
225 		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_CC, &when, NULL, &hdl[1] ) );
226 		when.command = cmd1;
227 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_CC, &when, NULL, &hdl[1] ) ); /* cmd1 */
228 		when.app = app2;
229 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_CC, &when, NULL, &hdl[2] ) ); /* app2 + cmd1 */
230 		when.command = cmd2;
231 		when.app = NULL;
232 		when.avp = avp1;
233 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_CC, &when, NULL, &hdl[3] ) ); /* cmd2 (avp1 ignored) */
234 
235 		/* Check the callbacks are called as appropriate */
236 		memset(cbcalled, 0, sizeof(cbcalled));
237 		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
238 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
239 		CHECK( 1, cbcalled[0] );
240 		CHECK( 1, cbcalled[1] );
241 		CHECK( 0, cbcalled[2] );
242 		CHECK( 0, cbcalled[3] );
243 		CHECK( DISP_ACT_CONT, action );
244 		CHECK( 0, fd_msg_free( msg ) );
245 
246 		memset(cbcalled, 0, sizeof(cbcalled));
247 		msg = new_msg( 2, cmd1, avp1, NULL, 0 );
248 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
249 		CHECK( 1, cbcalled[0] );
250 		CHECK( 1, cbcalled[1] );
251 		CHECK( 1, cbcalled[2] );
252 		CHECK( 0, cbcalled[3] );
253 		CHECK( DISP_ACT_CONT, action );
254 		CHECK( 0, fd_msg_free( msg ) );
255 
256 		memset(cbcalled, 0, sizeof(cbcalled));
257 		msg = new_msg( 2, cmd2, avp1, NULL, 0 );
258 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
259 		CHECK( 1, cbcalled[0] );
260 		CHECK( 0, cbcalled[1] );
261 		CHECK( 0, cbcalled[2] );
262 		CHECK( 1, cbcalled[3] );
263 		CHECK( DISP_ACT_CONT, action );
264 		CHECK( 0, fd_msg_free( msg ) );
265 
266 		memset(cbcalled, 0, sizeof(cbcalled));
267 		msg = new_msg( 1, cmd2, NULL, avp2, 0 );
268 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
269 		CHECK( 1, cbcalled[0] );
270 		CHECK( 0, cbcalled[1] );
271 		CHECK( 0, cbcalled[2] );
272 		CHECK( 1, cbcalled[3] );
273 		CHECK( DISP_ACT_CONT, action );
274 		CHECK( 0, fd_msg_free( msg ) );
275 
276 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
277 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
278 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
279 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
280 	}
281 
282 	/* Handlers for AVPs */
283 	{
284 		when.app = NULL;
285 		when.command = NULL;
286 		when.avp = NULL;
287 
288 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) ); /* all */
289 		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP, &when, NULL, &hdl[1] ) );
290 
291 		when.avp = avp1;
292 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP, &when, NULL, &hdl[1] ) ); /* avp1 */
293 
294 		when.command = cmd1;
295 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP, &when, NULL, &hdl[2] ) ); /* avp1 + cmd1 */
296 
297 		when.command = NULL;
298 		when.app = app1;
299 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_AVP, &when, NULL, &hdl[3] ) ); /* avp1 + app1 */
300 
301 		when.command = cmd1;
302 		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_AVP, &when, NULL, &hdl[4] ) ); /* avp1 + cmd1 + app1 */
303 
304 		when.app = NULL;
305 		when.command = NULL;
306 		when.avp = avp2;
307 		when.value = enu1;
308 		CHECK( 0, fd_disp_register( cb_5, DISP_HOW_AVP, &when, NULL, &hdl[5] ) ); /* avp2 */
309 
310 		when.value = enu2;
311 		CHECK( 0, fd_disp_register( cb_7, DISP_HOW_AVP, &when, NULL, &hdl[6] ) ); /* avp2 */
312 
313 
314 
315 		/* Check the callbacks are called as appropriate */
316 		memset(cbcalled, 0, sizeof(cbcalled));
317 		msg = new_msg( 0, cmd1, NULL, NULL, 0 );
318 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
319 		CHECK( 1, cbcalled[0] );
320 		CHECK( 0, cbcalled[1] );
321 		CHECK( 0, cbcalled[2] );
322 		CHECK( 0, cbcalled[3] );
323 		CHECK( 0, cbcalled[4] );
324 		CHECK( 0, cbcalled[5] );
325 		CHECK( DISP_ACT_CONT, action );
326 		CHECK( 0, fd_msg_free( msg ) );
327 
328 		memset(cbcalled, 0, sizeof(cbcalled));
329 		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
330 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
331 		CHECK( 1, cbcalled[0] );
332 		CHECK( 1, cbcalled[1] );
333 		CHECK( 1, cbcalled[2] );
334 		CHECK( 0, cbcalled[3] );
335 		CHECK( 0, cbcalled[4] );
336 		CHECK( 0, cbcalled[5] );
337 		CHECK( DISP_ACT_CONT, action );
338 		CHECK( 0, fd_msg_free( msg ) );
339 
340 		memset(cbcalled, 0, sizeof(cbcalled));
341 		msg = new_msg( 1, cmd2, avp1, NULL, 0 );
342 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
343 		CHECK( 1, cbcalled[0] );
344 		CHECK( 1, cbcalled[1] );
345 		CHECK( 0, cbcalled[2] );
346 		CHECK( 1, cbcalled[3] );
347 		CHECK( 0, cbcalled[4] );
348 		CHECK( 0, cbcalled[5] );
349 		CHECK( DISP_ACT_CONT, action );
350 		CHECK( 0, fd_msg_free( msg ) );
351 
352 		memset(cbcalled, 0, sizeof(cbcalled));
353 		msg = new_msg( 1, cmd1, avp1, NULL, 0 );
354 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
355 		CHECK( 1, cbcalled[0] );
356 		CHECK( 1, cbcalled[1] );
357 		CHECK( 1, cbcalled[2] );
358 		CHECK( 1, cbcalled[3] );
359 		CHECK( 1, cbcalled[4] );
360 		CHECK( 0, cbcalled[5] );
361 		CHECK( DISP_ACT_CONT, action );
362 		CHECK( 0, fd_msg_free( msg ) );
363 
364 		memset(cbcalled, 0, sizeof(cbcalled));
365 		msg = new_msg( 1, cmd1, avp1, avp2, 0 );
366 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
367 		CHECK( 1, cbcalled[0] );
368 		CHECK( 1, cbcalled[1] );
369 		CHECK( 1, cbcalled[2] );
370 		CHECK( 1, cbcalled[3] );
371 		CHECK( 1, cbcalled[4] );
372 		CHECK( 1, cbcalled[5] );
373 		CHECK( 1, cbcalled[7] );
374 		CHECK( DISP_ACT_CONT, action );
375 		CHECK( 0, fd_msg_free( msg ) );
376 
377 		memset(cbcalled, 0, sizeof(cbcalled));
378 		msg = new_msg( 1, cmd1, NULL, avp2, 1 );
379 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
380 		CHECK( 1, cbcalled[0] );
381 		CHECK( 0, cbcalled[1] );
382 		CHECK( 0, cbcalled[2] );
383 		CHECK( 0, cbcalled[3] );
384 		CHECK( 0, cbcalled[4] );
385 		CHECK( 1, cbcalled[5] );
386 		CHECK( 1, cbcalled[7] );
387 		CHECK( DISP_ACT_CONT, action );
388 		CHECK( 0, fd_msg_free( msg ) );
389 
390 		memset(cbcalled, 0, sizeof(cbcalled));
391 		msg = new_msg( 1, cmd1, NULL, avp2, 2 );
392 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
393 		CHECK( 1, cbcalled[0] );
394 		CHECK( 0, cbcalled[1] );
395 		CHECK( 0, cbcalled[2] );
396 		CHECK( 0, cbcalled[3] );
397 		CHECK( 0, cbcalled[4] );
398 		CHECK( 1, cbcalled[5] );
399 		CHECK( 1, cbcalled[7] );
400 		CHECK( DISP_ACT_CONT, action );
401 		CHECK( 0, fd_msg_free( msg ) );
402 
403 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
404 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
405 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
406 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
407 		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
408 		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
409 		CHECK( 0, fd_disp_unregister( &hdl[6], NULL ) );
410 	}
411 
412 	/* Handlers for enum values */
413 	{
414 		when.app = NULL;
415 		when.command = NULL;
416 		when.avp = NULL;
417 		when.value = NULL;
418 
419 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) ); /* all */
420 		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
421 		when.value = enu1;
422 		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
423 		when.avp = avp1;
424 		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
425 		when.avp = avp2;
426 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) ); /* avp2, enu1 */
427 
428 		when.command = cmd1;
429 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[2] ) ); /* avp2, enu1 + cmd1 */
430 
431 		when.command = NULL;
432 		when.app = app1;
433 		when.value = enu2;
434 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[3] ) ); /* avp2, enu2 + app1 */
435 
436 		/* Check the callbacks are called as appropriate */
437 		memset(cbcalled, 0, sizeof(cbcalled));
438 		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
439 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
440 		CHECK( 1, cbcalled[0] );
441 		CHECK( 0, cbcalled[1] );
442 		CHECK( 0, cbcalled[2] );
443 		CHECK( 0, cbcalled[3] );
444 		CHECK( DISP_ACT_CONT, action );
445 		CHECK( 0, fd_msg_free( msg ) );
446 
447 		memset(cbcalled, 0, sizeof(cbcalled));
448 		msg = new_msg( 1, cmd2, avp1, avp2, 0 );
449 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
450 		CHECK( 1, cbcalled[0] );
451 		CHECK( 0, cbcalled[1] );
452 		CHECK( 0, cbcalled[2] );
453 		CHECK( 0, cbcalled[3] );
454 		CHECK( DISP_ACT_CONT, action );
455 		CHECK( 0, fd_msg_free( msg ) );
456 
457 		memset(cbcalled, 0, sizeof(cbcalled));
458 		msg = new_msg( 1, cmd2, avp1, avp2, 1 );
459 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
460 		CHECK( 1, cbcalled[0] );
461 		CHECK( 1, cbcalled[1] );
462 		CHECK( 0, cbcalled[2] );
463 		CHECK( 0, cbcalled[3] );
464 		CHECK( DISP_ACT_CONT, action );
465 		CHECK( 0, fd_msg_free( msg ) );
466 
467 		memset(cbcalled, 0, sizeof(cbcalled));
468 		msg = new_msg( 1, cmd2, avp1, avp2, 2 );
469 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
470 		CHECK( 1, cbcalled[0] );
471 		CHECK( 0, cbcalled[1] );
472 		CHECK( 0, cbcalled[2] );
473 		CHECK( 1, cbcalled[3] );
474 		CHECK( DISP_ACT_CONT, action );
475 		CHECK( 0, fd_msg_free( msg ) );
476 
477 		memset(cbcalled, 0, sizeof(cbcalled));
478 		msg = new_msg( 1, cmd1, avp1, avp2, 1 );
479 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
480 		CHECK( 1, cbcalled[0] );
481 		CHECK( 1, cbcalled[1] );
482 		CHECK( 1, cbcalled[2] );
483 		CHECK( 0, cbcalled[3] );
484 		CHECK( DISP_ACT_CONT, action );
485 		CHECK( 0, fd_msg_free( msg ) );
486 
487 		memset(cbcalled, 0, sizeof(cbcalled));
488 		msg = new_msg( 1, cmd2, avp1, avp2, 1 );
489 		{
490 			struct avp *avp;
491 			union avp_value value;
492 			CHECK( 0, fd_msg_avp_new ( avp2, 0, &avp ) );
493 			value.u32 = 2;
494 			CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
495 			CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_LAST_CHILD, avp ) );
496 		}
497 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
498 		CHECK( 1, cbcalled[0] );
499 		CHECK( 1, cbcalled[1] );
500 		CHECK( 0, cbcalled[2] );
501 		CHECK( 1, cbcalled[3] );
502 		CHECK( DISP_ACT_CONT, action );
503 		CHECK( 0, fd_msg_free( msg ) );
504 
505 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
506 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
507 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
508 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
509 	}
510 
511 	/* Test behavior of handlers */
512 	{
513 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
514 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, NULL, &hdl[1] ) );
515 		CHECK( 0, fd_disp_register( cb_6, DISP_HOW_ANY, &when, NULL, &hdl[2] ) );
516 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, NULL, &hdl[3] ) );
517 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, NULL, &hdl[4] ) );
518 
519 		memset(cbcalled, 0, sizeof(cbcalled));
520 		msg = new_msg( 1, cmd1, avp1, avp2, 1 );
521 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
522 		CHECK( 1, cbcalled[0] );
523 		CHECK( 1, cbcalled[1] );
524 		CHECK( 1, cbcalled[6] );
525 		CHECK( 0, cbcalled[2] );
526 		CHECK( 0, cbcalled[3] );
527 		CHECK( 0, msg ? 1 : 0);
528 		CHECK( 1, em ? 1 : 0);
529 		CHECK( 0, fd_msg_free( error ) );
530 
531 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
532 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
533 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
534 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
535 		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
536 
537 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
538 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, NULL, &hdl[1] ) );
539 		CHECK( 0, fd_disp_register( cb_8, DISP_HOW_ANY, &when, NULL, &hdl[2] ) );
540 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, NULL, &hdl[3] ) );
541 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, NULL, &hdl[4] ) );
542 
543 		memset(cbcalled, 0, sizeof(cbcalled));
544 		msg = new_msg( 1, cmd1, avp1, avp2, 1 );
545 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
546 		CHECK( 1, cbcalled[0] );
547 		CHECK( 1, cbcalled[1] );
548 		CHECK( 1, cbcalled[8] );
549 		CHECK( 0, cbcalled[2] );
550 		CHECK( 0, cbcalled[3] );
551 		CHECK( NULL, msg );
552 		CHECK( NULL, em );
553 
554 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
555 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
556 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
557 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
558 		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
559 
560 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
561 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, NULL, &hdl[1] ) );
562 		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_ANY, &when, NULL, &hdl[2] ) );
563 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, NULL, &hdl[3] ) );
564 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, NULL, &hdl[4] ) );
565 
566 		memset(cbcalled, 0, sizeof(cbcalled));
567 		msg = new_msg( 1, cmd1, avp1, avp2, 1 );
568 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
569 		CHECK( 1, cbcalled[0] );
570 		CHECK( 1, cbcalled[1] );
571 		CHECK( 1, cbcalled[9] );
572 		CHECK( 0, cbcalled[2] );
573 		CHECK( 0, cbcalled[3] );
574 		CHECK( DISP_ACT_SEND, action );
575 		CHECK( 0, fd_msg_free( msg ) );
576 
577 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
578 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
579 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
580 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
581 		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
582 	}
583 
584 	/* Test order of handlers */
585 	{
586 		when.app = app2;
587 		when.command = cmd2;
588 		when.avp = avp2;
589 		when.value = enu2;
590 
591 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
592 		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
593 		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP, &when, NULL, &hdl[2] ) );
594 		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_CC, &when, NULL, &hdl[3] ) );
595 		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_APPID, &when, NULL, &hdl[4] ) );
596 
597 		memset(cbcalled, 0, sizeof(cbcalled));
598 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
599 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
600 		CHECK( 1, cbcalled[0] );
601 		CHECK( 1, cbcalled[1] );
602 		CHECK( 1, cbcalled[2] );
603 		CHECK( 1, cbcalled[3] );
604 		CHECK( 1, cbcalled[4] );
605 		CHECK( 0, cbcalled[9] );
606 		CHECK( 0, fd_msg_free( msg ) );
607 
608 		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_ANY, &when, NULL, &hdl[5] ) );
609 		memset(cbcalled, 0, sizeof(cbcalled));
610 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
611 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
612 		CHECK( 1, cbcalled[0] );
613 		CHECK( 0, cbcalled[1] );
614 		CHECK( 0, cbcalled[2] );
615 		CHECK( 0, cbcalled[3] );
616 		CHECK( 0, cbcalled[4] );
617 		CHECK( 1, cbcalled[9] );
618 		CHECK( 0, fd_msg_free( msg ) );
619 		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
620 
621 		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[5] ) );
622 		memset(cbcalled, 0, sizeof(cbcalled));
623 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
624 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
625 		CHECK( 1, cbcalled[0] );
626 		CHECK( 1, cbcalled[1] );
627 		CHECK( 1, cbcalled[2] );
628 		CHECK( 0, cbcalled[3] );
629 		CHECK( 0, cbcalled[4] );
630 		CHECK( 1, cbcalled[9] );
631 		CHECK( 0, fd_msg_free( msg ) );
632 		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
633 
634 		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_AVP, &when, NULL, &hdl[5] ) );
635 		memset(cbcalled, 0, sizeof(cbcalled));
636 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
637 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
638 		CHECK( 1, cbcalled[0] );
639 		CHECK( 1, cbcalled[1] );
640 		CHECK( 1, cbcalled[2] );
641 		CHECK( 0, cbcalled[3] );
642 		CHECK( 0, cbcalled[4] );
643 		CHECK( 1, cbcalled[9] );
644 		CHECK( 0, fd_msg_free( msg ) );
645 		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
646 
647 		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_CC, &when, NULL, &hdl[5] ) );
648 		memset(cbcalled, 0, sizeof(cbcalled));
649 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
650 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
651 		CHECK( 1, cbcalled[0] );
652 		CHECK( 1, cbcalled[1] );
653 		CHECK( 1, cbcalled[2] );
654 		CHECK( 1, cbcalled[3] );
655 		CHECK( 0, cbcalled[4] );
656 		CHECK( 1, cbcalled[9] );
657 		CHECK( 0, fd_msg_free( msg ) );
658 		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
659 
660 		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_APPID, &when, NULL, &hdl[5] ) );
661 		memset(cbcalled, 0, sizeof(cbcalled));
662 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
663 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
664 		CHECK( 1, cbcalled[0] );
665 		CHECK( 1, cbcalled[1] );
666 		CHECK( 1, cbcalled[2] );
667 		CHECK( 1, cbcalled[3] );
668 		CHECK( 1, cbcalled[4] );
669 		CHECK( 1, cbcalled[9] );
670 		CHECK( 0, fd_msg_free( msg ) );
671 		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
672 
673 		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
674 		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
675 		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
676 		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
677 		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
678 	}
679 
680 	/* Test application support advertisement */
681 	{
682 		struct dict_object * vnd;
683 		struct dict_vendor_data vnd_data = { 1, "Vendor test" };
684 		struct fd_app * app;
685 
686 		CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vnd_data, NULL, &vnd ) );
687 
688 		CHECK( EINVAL, fd_disp_app_support ( vnd, NULL, 1, 0 ) );
689 		CHECK( EINVAL, fd_disp_app_support ( app1, NULL, 0, 0 ) );
690 		CHECK( 0, fd_disp_app_support ( app1, NULL, 1, 0 ) );
691 		CHECK( 0, fd_disp_app_support ( app1, NULL, 0, 1 ) );
692 		CHECK( 0, fd_disp_app_support ( app2, vnd, 1, 0 ) );
693 
694 		app = (struct fd_app *)(fd_g_config->cnf_apps.next);
695 		CHECK( 1, app->appid );
696 		CHECK( 1, app->flags.auth );
697 		CHECK( 1, app->flags.acct );
698 		app = (struct fd_app *)(fd_g_config->cnf_apps.prev);
699 		CHECK( 2, app->appid );
700 		CHECK( 1, app->flags.auth );
701 		CHECK( 0, app->flags.acct );
702 
703 		#if 0
704 		fd_log_debug("%s", fd_conf_dump(FD_DUMP_TEST_PARAMS));
705 		#endif
706 	}
707 
708 	/* Test opaque pointer management */
709 	{
710 		void * ptr;
711 		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, g_opaque, &hdl[0] ) );
712 
713 		/* Check this handler is called for a message */
714 		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
715 		memset(cbcalled, 0, sizeof(cbcalled));
716 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec, &em, &error ) );
717 		CHECK( 1, cbcalled[0] );
718 		CHECK( DISP_ACT_CONT, action );
719 
720 		/* Delete the message */
721 		CHECK( 0, fd_msg_free( msg ) );
722 		CHECK( 0, fd_disp_unregister( &hdl[0], &ptr ) );
723 		CHECK( 1, ptr == g_opaque ? 1 : 0 );
724 	}
725 
726 	/* That's all for the tests yet */
727 	PASSTEST();
728 }
729 
730