blob: 310a9d2b661f4b0d247cc6e0e3c28fee819520fc [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
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#include <dirent.h>
38#include <libgen.h>
39#include <dlfcn.h>
40
41#ifndef BUILD_DIR
42#error "Missing BUILD_DIR information"
43#endif /* BUILD_DIR */
44
45
46/* The number of times each operation is repeated to measure the average operation time */
47#define DEFAULT_NUMBER_OF_SAMPLES 100000
48
49static void display_result(int nr, struct timespec * start, struct timespec * end, char * fct, char * type, char *op)
50{
51 long double dur = (long double)end->tv_sec + (long double)end->tv_nsec/1000000000;
52 dur -= (long double)start->tv_sec + (long double)start->tv_nsec/1000000000;
53 long double thrp = (long double)nr / dur;
54 printf("%-19s: %d %-8s %-7s in %.6LFs (%.1LFmsg/s)\n", fct, nr, type, op, dur, thrp);
55}
56
57struct ext_info {
58 struct fd_list chain; /* link in the list */
59 void *handler; /* object returned by dlopen() */
60 int (*init_cb)(int, int, char *);
61 char *ext_name; /* points to the extension name, either inside depends, or basename(filename) */
62 int free_ext_name; /* must be freed if it was malloc'd */
63 const char **depends; /* names of the other extensions this one depends on (if provided) */
64};
65
66static void load_all_extensions(char * prefix)
67{
68 DIR *dir;
69 struct dirent *dp;
70 char fullname[512];
71 int pathlen;
72 struct fd_list all_extensions = FD_LIST_INITIALIZER(all_extensions);
73 struct fd_list ext_with_depends = FD_LIST_INITIALIZER(ext_with_depends);
74
75 /* Find all extensions which have been compiled along the test */
76 LOG_D("Loading %s*.fdx from: '%s'", BUILD_DIR "/extensions", prefix ?: "");
77 CHECK( 0, (dir = opendir (BUILD_DIR "/extensions")) == NULL ? 1 : 0 );
78 pathlen = snprintf(fullname, sizeof(fullname), BUILD_DIR "/extensions/");
79
80 while ((dp = readdir (dir)) != NULL) {
81 char * dot = strrchr(dp->d_name, '.');
82 if (dot && ((!prefix) || !(strncmp(dp->d_name, prefix, strlen(prefix)))) && (!(strcmp(dot, ".fdx")))) {
83 /* We found a file with name dict_*.fdx, attempt to load it */
84 struct ext_info * new = malloc(sizeof(struct ext_info));
85 CHECK( 1, new ? 1:0);
86 fd_list_init(&new->chain, new);
87
88 snprintf(fullname + pathlen, sizeof(fullname) - pathlen, "%s", dp->d_name);
89
90 LOG_D("Extension: '%s'", dp->d_name);
91
92 /* load */
93 new->handler = dlopen(fullname, RTLD_NOW | RTLD_GLOBAL);
94 if (!new->handler) {
95 TRACE_DEBUG(INFO, "Unable to load '%s': %s.", fullname, dlerror());
96 }
97 CHECK( 0, new->handler == NULL ? 1 : 0 );
98
99 /* resolve entry */
100 new->init_cb = dlsym( new->handler, "fd_ext_init" );
101 if (!new->init_cb) {
102 TRACE_DEBUG(INFO, "No 'fd_ext_init' entry point in '%s': %s.", fullname, dlerror());
103 }
104 CHECK( 0, new->init_cb == NULL ? 1 : 0 );
105
106 new->depends = dlsym( new->handler, "fd_ext_depends" );
107 if (new->depends) {
108 new->ext_name = (char *)new->depends[0];
109 new->free_ext_name = 0;
110 if ( new->depends[1] ) {
111 fd_list_insert_before(&ext_with_depends, &new->chain);
112 } else {
113 fd_list_insert_before(&all_extensions, &new->chain);
114 }
115 } else {
116 new->ext_name = strdup(basename(dp->d_name));
117 new->free_ext_name = 1;
118 fd_list_insert_before(&all_extensions, &new->chain);
119 }
120
121 }
122 }
123
124 /* Now, reorder the list by dependencies */
125 {
126 int count, prevcount = 0;
127 struct fd_list * li;
128 do {
129 count = 0;
130 for (li=ext_with_depends.next; li != &ext_with_depends; li=li->next) {
131 struct ext_info * e = li->o;
132 int d;
133 int satisfied=0;
134
135 /* Can we satisfy all dependencies? */
136 for (d=1; ;d++) {
137 struct fd_list * eli;
138 if (!e->depends[d]) {
139 satisfied = 1;
140 break;
141 }
142
143 /* can we find this dependency in the list? */
144 for (eli=all_extensions.next; eli != &all_extensions; eli = eli->next) {
145 struct ext_info * de = eli->o;
146 if (!strcasecmp(de->ext_name, e->depends[d]))
147 break; /* this dependency is satisfied */
148 }
149
150 if (eli == &all_extensions) {
151 satisfied = 0;
152 break;
153 }
154 }
155
156 if (satisfied) {
157 /* OK, we have all our dependencies in the list */
158 li=li->prev;
159 fd_list_unlink(&e->chain);
160 fd_list_insert_before(&all_extensions, &e->chain);
161 } else {
162 count++;
163 }
164 }
165
166 if (prevcount && (prevcount == count)) {
167 LOG_E("Some extensions cannot have their dependencies satisfied, e.g.: %s", ((struct ext_info *)ext_with_depends.next->o)->ext_name);
168 CHECK(0, 1);
169 }
170 prevcount = count;
171
172 if (FD_IS_LIST_EMPTY(&ext_with_depends))
173 break;
174 } while (1);
175 }
176
177 /* Now, load all the extensions */
178 {
179 struct fd_list * li;
180 for (li=all_extensions.next; li != &all_extensions; li=li->next) {
181 struct ext_info * e = li->o;
182 int ret = (*e->init_cb)( FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, NULL );
183 LOG_N("Initializing extension '%s': %s", e->ext_name, ret ? strerror(ret) : "Success");
184 }
185 }
186
187 /* We should probably clean the list here ? */
188}
189
190/* Main test routine */
191int main(int argc, char *argv[])
192{
193 struct msg * acr = NULL;
194 unsigned char * buf = NULL;
195
196 int dictionaries_loaded = 0;
197
198 test_parameter = DEFAULT_NUMBER_OF_SAMPLES;
199
200 /* First, initialize the daemon modules */
201 INIT_FD();
202 CHECK( 0, fd_queues_init() );
203 CHECK( 0, fd_msg_init() );
204 CHECK( 0, fd_rtdisp_init() );
205
206
207 {
208 struct dict_object * acr_model = NULL;
209
210 /* Now find the ACR dictionary object */
211 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) );
212
213 /* Create the instance, using the templates */
214 CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) );
215 }
216
217 /* Now let's create some additional Dictionary objects for the test */
218 {
219 /* The constant values used here are totally arbitrary chosen */
220 struct dict_object * vendor;
221 {
222 struct dict_vendor_data vendor_data = { 73565, "Vendor test" };
223 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) );
224 }
225
226 {
227 struct dict_application_data app_data = { 73566, "Application test" };
228 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app_data , vendor, NULL ) );
229 }
230
231 {
232 struct dict_avp_data avp_data = { 73567, 0, "AVP Test - no vendor - f32", 0, 0, AVP_TYPE_FLOAT32 };
233 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
234 }
235
236 {
237 struct dict_avp_data avp_data = { 139103, 0, "AVP Test - no vendor - f64", 0, 0, AVP_TYPE_FLOAT64 };
238 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
239 }
240
241 {
242 struct dict_object * type = NULL;
243 struct dict_type_data type_data = { AVP_TYPE_INTEGER64, "Int64 test" };
244 struct dict_avp_data avp_data = { 73568, 73565, "AVP Test - i64", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER64 };
245 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
246 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
247 }
248
249 {
250 struct dict_object * type = NULL;
251 struct dict_type_data type_data = { AVP_TYPE_INTEGER32, "Enum32 test" };
252 struct dict_enumval_data val1 = { "i32 const test (val 1)", { .i32 = 1 } };
253 struct dict_enumval_data val2 = { "i32 const test (val 2)", { .i32 = 2 } };
254 struct dict_enumval_data val3 = { "i32 const test (val -5)",{ .i32 = -5 } };
255 struct dict_avp_data avp_data = { 73569, 73565, "AVP Test - enumi32", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER32 };
256
257 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
258 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
259 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
260 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
261 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
262 }
263
264 {
265 struct dict_object * type = NULL;
266 struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test" };
267 struct dict_avp_data avp_data = { 73570, 73565, "AVP Test - os", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
268 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
269 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
270 }
271
272 {
273 struct dict_object * type = NULL;
274 struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS enum test" };
275 struct dict_enumval_data val1 = { "os const test (Test)", { .os = { (unsigned char *)"Test", 4 } } };
276 struct dict_enumval_data val2 = { "os const test (waaad)", { .os = { (unsigned char *)"waaad", 5 } } };
277 struct dict_enumval_data val3 = { "os const test (waa)", { .os = { (unsigned char *)"waaad", 3 } } };
278 struct dict_avp_data avp_data = { 73571, 73565, "AVP Test - enumos", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
279
280 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
281 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
282 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
283 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
284 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
285 }
286
287 {
288 struct dict_object * gavp = NULL;
289 struct dict_avp_data avp_data = { 73572, 73565, "AVP Test - grouped", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
290
291 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
292
293 /* Macro to search AVP and create a rule */
294 #define ADD_RULE( _parent, _vendor, _avpname, _pos, _min, _max, _ord ) { \
295 struct dict_object * _avp = NULL; \
296 struct dict_avp_request _req = { (_vendor), 0, (_avpname) }; \
297 struct dict_rule_data _data; \
298 CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
299 _data.rule_avp = _avp; \
300 _data.rule_position = (_pos); \
301 _data.rule_order = (_ord); \
302 _data.rule_min = (_min); \
303 _data.rule_max = (_max); \
304 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &_data , (_parent), NULL ) ); \
305 }
306
307 ADD_RULE(gavp, 73565, "AVP Test - os", RULE_OPTIONAL, -1, -1, 0);
308
309 }
310
311 {
312 struct dict_object * application = NULL;
313 struct dict_object * command = NULL;
314 struct dict_cmd_data cmd_data = { 73573, "Test-Command-Request", CMD_FLAG_REQUEST, CMD_FLAG_REQUEST };
315
316 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) );
317 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) );
318 ADD_RULE(command, 0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD, -1, 1, 1);
319 ADD_RULE(command, 73565, "AVP Test - i64", RULE_REQUIRED, -1, -1, 0);
320 ADD_RULE(command, 73565, "AVP Test - enumi32", RULE_OPTIONAL, -1, -1, 0);
321 ADD_RULE(command, 73565, "AVP Test - os", RULE_OPTIONAL, -1, -1, 0);
322 ADD_RULE(command, 73565, "AVP Test - enumos", RULE_OPTIONAL, -1, -1, 0);
323 ADD_RULE(command, 73565, "AVP Test - grouped", RULE_OPTIONAL, -1, -1, 0);
324 }
325
326 {
327 struct dict_object * application = NULL;
328 struct dict_object * command = NULL;
329 struct dict_cmd_data cmd_data = { 73573, "Test-Command-Answer", CMD_FLAG_REQUEST, 0 };
330
331 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) );
332 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) );
333 }
334
335 {
336 struct dict_object * gavp = NULL;
337 struct dict_avp_data avp_data = { 73574, 73565, "AVP Test - rules", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
338
339 CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
340
341 ADD_RULE(gavp, 0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD, 0, 1, 1);
342 ADD_RULE(gavp, 73565, "AVP Test - i64", RULE_FIXED_HEAD, -1, 1, 2);
343 ADD_RULE(gavp, 73565, "AVP Test - enumi32", RULE_FIXED_HEAD, -1, 1, 3);
344 ADD_RULE(gavp, 73565, "AVP Test - os", RULE_REQUIRED, 2, 3, 0);
345 ADD_RULE(gavp, 73565, "AVP Test - enumos", RULE_OPTIONAL, 0, 1, 0);
346 ADD_RULE(gavp, 73565, "AVP Test - grouped", RULE_FIXED_TAIL, -1, 1, 1);
347 /* ABNF :
348 < no vendor - f32 >
349 < i64 >
350 < enumi32 >
351 2*3 { os }
352 *1 [ enumos ]
353 < grouped >
354 */
355 }
356 }
357
358 /* Now create some values and check the length is correctly handled */
359 {
360 struct dict_object * cmd_model = NULL;
361 struct msg * msg = NULL;
362 struct dict_object * avp_model = NULL;
363 union avp_value value;
364
365 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) );
366
367 /* Check the sizes are handled properly */
368 {
369 struct avp * avpi = NULL;
370 struct avp * avpch = NULL;
371 struct msg_hdr * msgdata = NULL;
372 #define ADD_AVP( _parent, _position, _avpi, _avpvendor, _avpname) { \
373 struct dict_object * _avp = NULL; \
374 struct dict_avp_request _req = { (_avpvendor), 0, (_avpname) }; \
375 CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
376 CHECK( 0, fd_msg_avp_new ( _avp, 0, &_avpi ) ); \
377 CHECK( 0, fd_msg_avp_add ( (_parent), (_position), _avpi ) ); \
378 }
379 /* Create a message with many AVP inside */
380 CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
381 CHECK( 0, fd_msg_hdr ( msg, &msgdata ) );
382
383 /* Avp no vendor, float32 => size = 12 */
384 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0, "AVP Test - no vendor - f32" );
385 value.f32 = 3.1415;
386 CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
387
388 /* Add a vendor AVP, integer64 => size = 20 */
389 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - i64" );
390 value.i64 = 0x123456789abcdeLL;
391 CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
392
393 /* Add an AVP with an enum value */
394 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
395 {
396 struct dict_object * type_model = NULL;
397 struct dict_object * value_model = NULL;
398 struct dict_enumval_request request;
399
400 CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
401 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
402 memset(&request, 0, sizeof(request));
403 request.type_obj = type_model;
404 request.search.enum_name = "i32 const test (val 2)";
405 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
406 CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
407 CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
408 }
409
410 /* Add an AVP with an enum value, negative */
411 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
412 {
413 struct dict_object * type_model = NULL;
414 struct dict_object * value_model = NULL;
415 struct dict_enumval_request request;
416
417 CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
418 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
419 memset(&request, 0, sizeof(request));
420 request.type_obj = type_model;
421 request.search.enum_name = "i32 const test (val -5)";
422 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
423 CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
424 CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
425 }
426
427 /* Now add a value which is not a constant into an enumerated AVP */
428 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
429 value.i32 = -10;
430 CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
431
432 /* Add an octetstring AVP */
433 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - os" );
434 {
435 unsigned char buf[90];
436 memcpy(&buf, "This\0 is a buffer of dat\a. It is not a string so we can have any c\0ntr\0l character here...\0\0", 89);
437 value.os.data = buf;
438 value.os.len = 89;
439 CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
440 memset(&buf, 0, sizeof(buf)); /* Test that the OS value is really copied */
441 }
442
443 /* Add an octetstring from an enumerated constant */
444 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
445 {
446 struct dict_object * type_model = NULL;
447 struct dict_object * value_model = NULL;
448 struct dict_enumval_request request;
449
450 CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
451 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
452 memset(&request, 0, sizeof(request));
453 request.type_obj = type_model;
454 request.search.enum_name = "os const test (waaad)";
455 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
456 CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
457 CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
458 }
459
460 /* Add an octetstring from an enumerated constant */
461 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
462 {
463 struct dict_object * type_model = NULL;
464 struct dict_object * value_model = NULL;
465 struct dict_enumval_request request;
466
467 CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
468 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
469 memset(&request, 0, sizeof(request));
470 request.type_obj = type_model;
471 request.search.enum_name = "os const test (waa)";
472 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
473 CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
474 CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
475 }
476
477 /* Now test the grouped AVPs */
478 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
479 ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
480 {
481 value.os.data = (unsigned char *)"12345678";
482 value.os.len = 8;
483 CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
484 }
485 ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
486 {
487 value.os.data = (unsigned char *)"123456789";
488 value.os.len = 9;
489 CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
490 }
491
492 /* Add another similar grouped AVP, to have lot of padding */
493 ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
494 ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
495 {
496 value.os.data = (unsigned char *)"1";
497 value.os.len = 1;
498 CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
499 }
500 ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
501 {
502 value.os.data = (unsigned char *)"1234567";
503 value.os.len = 7;
504 CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
505 }
506
507 /* Set the application to the test application: 73566 */
508 msgdata->msg_appl = 73566;
509
510 /* Set the hop-by-hop ID to a random value: 0x4b44b41d */
511 msgdata->msg_hbhid = 0x4b44b41d;
512 /* Set the end-to-end ID to a random value: 0xe2ee2e1d */
513 msgdata->msg_eteid = 0xe2ee2e1d;
514 }
515
516 CHECK( 0, fd_msg_bufferize( msg, &buf, NULL ) );
517
518 LOG_D( "Test message: %s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, NULL, 0, 1));
519
520 /* Now free the message, we keep only the buffer. */
521 CHECK( 0, fd_msg_free( msg ) );
522
523 }
524
525 /* We have our "buf" now, length is 344 -- cf. testmesg.c. */
526redo:
527 /* Test the throughput of the different functions function */
528 {
529 struct stress_struct {
530 struct msg * m;
531 uint8_t * b;
532 } * stress_array;
533 int i;
534 struct timespec start, end;
535
536 /* Create the copies of the message buffer */
537 stress_array = calloc(test_parameter, sizeof(struct stress_struct));
538 CHECK( stress_array ? 1 : 0, 1);
539
540 for (i=0; i < test_parameter; i++) {
541 stress_array[i].b = malloc(344);
542 if (!stress_array[i].b)
543 break;
544 memcpy(stress_array[i].b, buf, 344);
545 }
546 CHECK( test_parameter, i ); /* if false, a malloc failed */
547
548 /* fd_msg_parse_buffer */
549
550 CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
551
552 /* Test the msg_parse_buffer function */
553 for (i=0; i < test_parameter; i++) {
554 if (0 != fd_msg_parse_buffer( &stress_array[i].b, 344, &stress_array[i].m) )
555 break;
556 }
557 CHECK( test_parameter, i ); /* if false, a call failed */
558
559 CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
560 display_result(test_parameter, &start, &end, "fd_msg_parse_buffer", "buffers", "parsed");
561
562 /* fd_msg_parse_dict */
563
564 CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
565
566 /* Test the fd_msg_parse_dict function */
567 for (i=0; i < test_parameter; i++) {
568 if (0 != fd_msg_parse_dict( stress_array[i].m, fd_g_config->cnf_dict, NULL ) )
569 break;
570 }
571 CHECK( test_parameter, i ); /* if false, a call failed */
572
573 CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
574 display_result(test_parameter, &start, &end, "fd_msg_parse_dict", "messages", "parsed");
575
576
577 /* fd_msg_parse_rules */
578
579 CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
580
581 /* Test the fd_msg_parse_rules function */
582 for (i=0; i < test_parameter; i++) {
583 if (0 != fd_msg_parse_rules( stress_array[i].m, fd_g_config->cnf_dict, NULL ) )
584 break;
585 }
586 CHECK( test_parameter, i ); /* if false, a call failed */
587
588 CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
589 display_result(test_parameter, &start, &end, "fd_msg_parse_rules", "messages", "parsed");
590
591
592 /* fd_msg_new_answer_from_req (0) */
593
594 CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
595
596 /* Test the fd_msg_new_answer_from_req function */
597 for (i=0; i < test_parameter; i++) {
598 if (0 != fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, 0 ) )
599 break;
600 }
601 CHECK( test_parameter, i ); /* if false, a call failed */
602
603 CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
604 display_result(test_parameter, &start, &end, "new_answer(normal)", "messages", "created");
605
606 /* unlink answers and go back to request messages */
607 for (i=0; i < test_parameter; i++) {
608 struct msg * ans = stress_array[i].m;
609 if (0 != fd_msg_answ_getq( ans, &stress_array[i].m ) )
610 break;
611 if (0 != fd_msg_answ_detach( ans ) )
612 break;
613 fd_msg_free( ans );
614 }
615 CHECK( test_parameter, i ); /* if false, a call failed */
616
617
618 /* fd_msg_new_answer_from_req (MSGFL_ANSW_ERROR) */
619
620 CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
621
622 /* Test the fd_msg_new_answer_from_req function */
623 for (i=0; i < test_parameter; i++) {
624 if ( 0 != fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, MSGFL_ANSW_ERROR ) )
625 break;
626 }
627 CHECK( test_parameter, i ); /* if false, a call failed */
628
629 CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
630 display_result(test_parameter, &start, &end, "new_answer(error)", "messages", "created");
631
632 /* unlink answers and go back to request messages */
633 for (i=0; i < test_parameter; i++) {
634 struct msg * ans = stress_array[i].m;
635 if (0 != fd_msg_answ_getq( ans, &stress_array[i].m ) )
636 break;
637 if (0 != fd_msg_answ_detach( ans ) )
638 break;
639 fd_msg_free( ans );
640 }
641
642
643 /* fd_msg_bufferize */
644
645
646 CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
647
648 /* Test the fd_msg_bufferize function */
649 for (i=0; i < test_parameter; i++) {
650 size_t len = 0;
651 if (0 != fd_msg_bufferize( stress_array[i].m, &stress_array[i].b, &len ) )
652 break;
653 }
654 CHECK( test_parameter, i ); /* if false, a call failed */
655
656 CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
657 display_result(test_parameter, &start, &end, "fd_msg_bufferize", "buffers", "created");
658
659
660 /* fd_msg_free */
661
662 CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
663
664 /* Free those messages */
665 for (i=0; i < test_parameter; i++) {
666 fd_msg_free( stress_array[i].m );
667 }
668
669 CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
670 display_result(test_parameter, &start, &end, "fd_msg_free", "messages", "freed");
671
672
673 for (i=0; i < test_parameter; i++) {
674 free(stress_array[i].b);
675 }
676 free(stress_array);
677 }
678
679 if (!dictionaries_loaded) {
680 load_all_extensions("dict_");
681 dictionaries_loaded = 1;
682 printf("Loaded all dictionary extensions, restarting...\n");
683 goto redo;
684 }
685
686 /* That's all for the tests yet */
687 PASSTEST();
688}
689