blob: 9f19b68fb92dbcbbd1bd82614e1b23218070b608 [file] [log] [blame]
Benny Prijono0ca04b62005-12-30 23:50:15 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono0ca04b62005-12-30 23:50:15 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "test.h"
Benny Prijono40f2f642006-01-30 18:40:05 +000022#include <pjsip.h>
Benny Prijono0ca04b62005-12-30 23:50:15 +000023#include <pjlib.h>
24
Benny Prijono85598d92006-01-07 18:44:25 +000025#define THIS_FILE "transport_test.c"
26
Benny Prijono0ca04b62005-12-30 23:50:15 +000027///////////////////////////////////////////////////////////////////////////////
28/*
29 * Generic testing for transport, to make sure that basic
30 * attributes have been initialized properly.
31 */
32int generic_transport_test(pjsip_transport *tp)
33{
Benny Prijono85598d92006-01-07 18:44:25 +000034 PJ_LOG(3,(THIS_FILE, " structure test..."));
Benny Prijono0ca04b62005-12-30 23:50:15 +000035
36 /* Check that local address name is valid. */
37 {
38 struct pj_in_addr addr;
39
40 /* Note: inet_aton() returns non-zero if addr is valid! */
41 if (pj_inet_aton(&tp->local_name.host, &addr) != 0) {
42 if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) {
Benny Prijono85598d92006-01-07 18:44:25 +000043 PJ_LOG(3,(THIS_FILE, " Error: invalid address name"));
Benny Prijono0ca04b62005-12-30 23:50:15 +000044 return -420;
45 }
46 } else {
47 /* It's okay. local_name.host may be a hostname instead of
48 * IP address.
49 */
50 }
51 }
52
53 /* Check that port is valid. */
54 if (tp->local_name.port <= 0) {
55 return -430;
56 }
57
58 /* Check length of address (for now we only check against sockaddr_in). */
59 if (tp->addr_len != sizeof(pj_sockaddr_in))
60 return -440;
61
62 /* Check type. */
63 if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED)
64 return -450;
65
66 /* That's it. */
67 return PJ_SUCCESS;
68}
69
70///////////////////////////////////////////////////////////////////////////////
71/*
72 * Send/receive test.
73 *
74 * This test sends a request to loopback address; as soon as request is
75 * received, response will be sent, and time is recorded.
76 *
77 * The main purpose is to test that the basic transport functionalities works,
78 * before we continue with more complicated tests.
79 */
80#define FROM_HDR "Bob <sip:bob@example.com>"
Benny Prijono0ca04b62005-12-30 23:50:15 +000081#define CONTACT_HDR "Bob <sip:bob@127.0.0.1>"
82#define CALL_ID_HDR "SendRecv-Test"
83#define CSEQ_VALUE 100
84#define BODY "Hello World!"
85
86static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata);
87static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata);
88
89/* Flag to indicate message has been received
90 * (or failed to send)
91 */
92#define NO_STATUS -2
93static int send_status = NO_STATUS;
94static int recv_status = NO_STATUS;
95static pj_timestamp my_send_time, my_recv_time;
96
97/* Module to receive messages for this test. */
98static pjsip_module my_module =
99{
100 NULL, NULL, /* prev and next */
101 { "Transport-Test", 14}, /* Name. */
102 -1, /* Id */
103 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000104 NULL, /* load() */
105 NULL, /* start() */
106 NULL, /* stop() */
107 NULL, /* unload() */
108 &my_on_rx_request, /* on_rx_request() */
109 &my_on_rx_response, /* on_rx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000110 NULL, /* on_tsx_state() */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000111};
112
113
114static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata)
115{
116 /* Check that this is our request. */
Benny Prijono728a9052006-01-18 23:34:15 +0000117 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000118 /* It is! */
119 /* Send response. */
120 pjsip_tx_data *tdata;
121 pjsip_response_addr res_addr;
122 pj_status_t status;
123
Benny Prijono0ca04b62005-12-30 23:50:15 +0000124 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
125 if (status != PJ_SUCCESS) {
126 recv_status = status;
127 return PJ_TRUE;
128 }
129 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
130 if (status != PJ_SUCCESS) {
131 recv_status = status;
132 pjsip_tx_data_dec_ref(tdata);
133 return PJ_TRUE;
134 }
135 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
136 if (status != PJ_SUCCESS) {
137 recv_status = status;
138 pjsip_tx_data_dec_ref(tdata);
139 return PJ_TRUE;
140 }
141 return PJ_TRUE;
142 }
143
144 /* Not ours. */
145 return PJ_FALSE;
146}
147
148static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata)
149{
Benny Prijono728a9052006-01-18 23:34:15 +0000150 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000151 pj_get_timestamp(&my_recv_time);
152 recv_status = PJ_SUCCESS;
153 return PJ_TRUE;
154 }
155 return PJ_FALSE;
156}
157
158/* Transport callback. */
159static void send_msg_callback(pjsip_send_state *stateless_data,
160 pj_ssize_t sent, pj_bool_t *cont)
161{
162 if (sent < 1) {
163 /* Obtain the error code. */
164 send_status = -sent;
165 } else {
166 send_status = PJ_SUCCESS;
167 }
168
169 /* Don't want to continue. */
170 *cont = PJ_FALSE;
171}
172
173
174/* Test that we receive loopback message. */
175int transport_send_recv_test( pjsip_transport_type_e tp_type,
176 pjsip_transport *ref_tp,
Benny Prijonoe93e2872006-06-28 16:46:49 +0000177 char *target_url,
178 int *p_usec_rtt)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000179{
Benny Prijono85598d92006-01-07 18:44:25 +0000180 pj_bool_t msg_log_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000181 pj_status_t status;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000182 pj_str_t target, from, to, contact, call_id, body;
183 pjsip_method method;
184 pjsip_tx_data *tdata;
185 pj_time_val timeout;
186
Benny Prijono85598d92006-01-07 18:44:25 +0000187 PJ_LOG(3,(THIS_FILE, " single message round-trip test..."));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000188
189 /* Register out test module to receive the message (if necessary). */
190 if (my_module.id == -1) {
191 status = pjsip_endpt_register_module( endpt, &my_module );
192 if (status != PJ_SUCCESS) {
193 app_perror(" error: unable to register module", status);
194 return -500;
195 }
196 }
197
Benny Prijono85598d92006-01-07 18:44:25 +0000198 /* Disable message logging. */
199 msg_log_enabled = msg_logger_set_enabled(0);
200
Benny Prijono0ca04b62005-12-30 23:50:15 +0000201 /* Create a request message. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000202 target = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000203 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000204 to = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000205 contact = pj_str(CONTACT_HDR);
206 call_id = pj_str(CALL_ID_HDR);
207 body = pj_str(BODY);
208
209 pjsip_method_set(&method, PJSIP_OPTIONS_METHOD);
210 status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to,
211 &contact, &call_id, CSEQ_VALUE,
212 &body, &tdata );
213 if (status != PJ_SUCCESS) {
214 app_perror(" error: unable to create request", status);
215 return -510;
216 }
217
218 /* Reset statuses */
219 send_status = recv_status = NO_STATUS;
220
221 /* Start time. */
222 pj_get_timestamp(&my_send_time);
223
224 /* Send the message (statelessly). */
Benny Prijonoe93e2872006-06-28 16:46:49 +0000225 PJ_LOG(5,(THIS_FILE, "Sending request to %.*s",
226 (int)target.slen, target.ptr));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000227 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL,
228 &send_msg_callback);
229 if (status != PJ_SUCCESS) {
230 /* Immediate error! */
231 pjsip_tx_data_dec_ref(tdata);
232 send_status = status;
233 }
234
Benny Prijonoe93e2872006-06-28 16:46:49 +0000235 /* Set the timeout (2 seconds from now) */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000236 pj_gettimeofday(&timeout);
Benny Prijonoe93e2872006-06-28 16:46:49 +0000237 timeout.sec += 2;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000238
239 /* Loop handling events until we get status */
240 do {
241 pj_time_val now;
242 pj_time_val poll_interval = { 0, 10 };
243
244 pj_gettimeofday(&now);
245 if (PJ_TIME_VAL_GTE(now, timeout)) {
Benny Prijono85598d92006-01-07 18:44:25 +0000246 PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test"));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000247 status = -540;
248 goto on_return;
249 }
250
251 if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) {
252 app_perror(" error sending message", send_status);
253 status = -550;
254 goto on_return;
255 }
256
257 if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) {
258 app_perror(" error receiving message", recv_status);
259 status = -560;
260 goto on_return;
261 }
262
263 if (send_status!=NO_STATUS && recv_status!=NO_STATUS) {
264 /* Success! */
265 break;
266 }
267
268 pjsip_endpt_handle_events(endpt, &poll_interval);
269
270 } while (1);
271
272 if (status == PJ_SUCCESS) {
273 unsigned usec_rt;
274 usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time);
Benny Prijonoe93e2872006-06-28 16:46:49 +0000275
Benny Prijono85598d92006-01-07 18:44:25 +0000276 PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt));
Benny Prijonoe93e2872006-06-28 16:46:49 +0000277
278 *p_usec_rtt = usec_rt;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000279 }
280
Benny Prijono85598d92006-01-07 18:44:25 +0000281 /* Restore message logging. */
282 msg_logger_set_enabled(msg_log_enabled);
283
Benny Prijono0ca04b62005-12-30 23:50:15 +0000284 status = PJ_SUCCESS;
285
286on_return:
287 return status;
288}
289
290
291///////////////////////////////////////////////////////////////////////////////
292/*
293 * Multithreaded round-trip test
294 *
295 * This test will spawn multiple threads, each of them send a request. As soon
296 * as request is received, response will be sent, and time is recorded.
297 *
298 * The main purpose of this test is to ensure there's no crash when multiple
299 * threads are sending/receiving messages.
300 *
301 */
302static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata);
303static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata);
304
305static pjsip_module rt_module =
306{
307 NULL, NULL, /* prev and next */
308 { "Transport-RT-Test", 17}, /* Name. */
309 -1, /* Id */
310 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000311 NULL, /* load() */
312 NULL, /* start() */
313 NULL, /* stop() */
314 NULL, /* unload() */
315 &rt_on_rx_request, /* on_rx_request() */
316 &rt_on_rx_response, /* on_rx_response() */
317 NULL, /* tsx_handler() */
318};
319
320static struct
321{
322 pj_thread_t *thread;
323 pj_timestamp send_time;
324 pj_timestamp total_rt_time;
325 int sent_request_count, recv_response_count;
326 pj_str_t call_id;
Benny Prijono85598d92006-01-07 18:44:25 +0000327 pj_timer_entry timeout_timer;
328 pj_timer_entry tx_timer;
329 pj_mutex_t *mutex;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000330} rt_test_data[16];
331
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000332static char rt_target_uri[64];
Benny Prijono0ca04b62005-12-30 23:50:15 +0000333static pj_bool_t rt_stop;
334static pj_str_t rt_call_id;
335
336static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata)
337{
Benny Prijono728a9052006-01-18 23:34:15 +0000338 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000339 pjsip_tx_data *tdata;
340 pjsip_response_addr res_addr;
341 pj_status_t status;
342
343 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
344 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000345 app_perror(" error creating response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000346 return PJ_TRUE;
347 }
348 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
349 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000350 app_perror(" error in get response address", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000351 pjsip_tx_data_dec_ref(tdata);
352 return PJ_TRUE;
353 }
354 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
355 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000356 app_perror(" error sending response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000357 pjsip_tx_data_dec_ref(tdata);
358 return PJ_TRUE;
359 }
360 return PJ_TRUE;
361
362 }
363 return PJ_FALSE;
364}
365
366static pj_status_t rt_send_request(int thread_id)
367{
368 pj_status_t status;
369 pj_str_t target, from, to, contact, call_id;
370 pjsip_tx_data *tdata;
Benny Prijono85598d92006-01-07 18:44:25 +0000371 pj_time_val timeout_delay;
372
373 pj_mutex_lock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000374
375 /* Create a request message. */
376 target = pj_str(rt_target_uri);
377 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000378 to = pj_str(rt_target_uri);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000379 contact = pj_str(CONTACT_HDR);
380 call_id = rt_test_data[thread_id].call_id;
381
382 status = pjsip_endpt_create_request( endpt, &pjsip_options_method,
383 &target, &from, &to,
384 &contact, &call_id, -1,
385 NULL, &tdata );
386 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +0000387 app_perror(" error: unable to create request", status);
388 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000389 return -610;
390 }
391
392 /* Start time. */
393 pj_get_timestamp(&rt_test_data[thread_id].send_time);
394
395 /* Send the message (statelessly). */
396 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL);
397 if (status != PJ_SUCCESS) {
398 /* Immediate error! */
Benny Prijono85598d92006-01-07 18:44:25 +0000399 app_perror(" error: send request", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000400 pjsip_tx_data_dec_ref(tdata);
Benny Prijono85598d92006-01-07 18:44:25 +0000401 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000402 return -620;
403 }
404
405 /* Update counter. */
406 rt_test_data[thread_id].sent_request_count++;
407
Benny Prijono85598d92006-01-07 18:44:25 +0000408 /* Set timeout timer. */
409 if (rt_test_data[thread_id].timeout_timer.user_data != NULL) {
410 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
411 }
412 timeout_delay.sec = 100; timeout_delay.msec = 0;
413 rt_test_data[thread_id].timeout_timer.user_data = (void*)1;
414 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer,
415 &timeout_delay);
416
417 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000418 return PJ_SUCCESS;
419}
420
421static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata)
422{
Benny Prijono728a9052006-01-18 23:34:15 +0000423 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
424 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000425 int thread_id = (*pos - '0');
426 pj_timestamp recv_time;
427
Benny Prijono85598d92006-01-07 18:44:25 +0000428 pj_mutex_lock(rt_test_data[thread_id].mutex);
429
430 /* Stop timer. */
431 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
432
Benny Prijono0ca04b62005-12-30 23:50:15 +0000433 /* Update counter and end-time. */
434 rt_test_data[thread_id].recv_response_count++;
435 pj_get_timestamp(&recv_time);
436
437 pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time);
438 pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time);
439
Benny Prijono85598d92006-01-07 18:44:25 +0000440 if (!rt_stop) {
441 pj_time_val tx_delay = { 0, 0 };
442 pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL);
443 rt_test_data[thread_id].tx_timer.user_data = (void*)1;
444 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer,
445 &tx_delay);
446 }
447
448 pj_mutex_unlock(rt_test_data[thread_id].mutex);
449
Benny Prijono0ca04b62005-12-30 23:50:15 +0000450 return PJ_TRUE;
451 }
452 return PJ_FALSE;
453}
454
Benny Prijono85598d92006-01-07 18:44:25 +0000455static void rt_timeout_timer( pj_timer_heap_t *timer_heap,
456 struct pj_timer_entry *entry )
457{
458 pj_mutex_lock(rt_test_data[entry->id].mutex);
459
460 PJ_UNUSED_ARG(timer_heap);
461 PJ_LOG(3,(THIS_FILE, " timeout waiting for response"));
462 rt_test_data[entry->id].timeout_timer.user_data = NULL;
463
464 if (rt_test_data[entry->id].tx_timer.user_data == NULL) {
465 pj_time_val delay = { 0, 0 };
466 rt_test_data[entry->id].tx_timer.user_data = (void*)1;
467 pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer,
468 &delay);
469 }
470
471 pj_mutex_unlock(rt_test_data[entry->id].mutex);
472}
473
474static void rt_tx_timer( pj_timer_heap_t *timer_heap,
475 struct pj_timer_entry *entry )
476{
477 pj_mutex_lock(rt_test_data[entry->id].mutex);
478
479 PJ_UNUSED_ARG(timer_heap);
480 pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL);
481 rt_test_data[entry->id].tx_timer.user_data = NULL;
482 rt_send_request(entry->id);
483
484 pj_mutex_unlock(rt_test_data[entry->id].mutex);
485}
486
487
488static int rt_worker_thread(void *arg)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000489{
Benny Prijonobc331ca2006-09-19 13:32:05 +0000490 int i;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000491 pj_time_val poll_delay = { 0, 10 };
492
493 /* Sleep to allow main threads to run. */
494 pj_thread_sleep(10);
495
Benny Prijono0ca04b62005-12-30 23:50:15 +0000496 while (!rt_stop) {
497 pjsip_endpt_handle_events(endpt, &poll_delay);
498 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000499
500 /* Exhaust responses. */
501 for (i=0; i<100; ++i)
502 pjsip_endpt_handle_events(endpt, &poll_delay);
503
Benny Prijono0ca04b62005-12-30 23:50:15 +0000504 return 0;
505}
506
507int transport_rt_test( pjsip_transport_type_e tp_type,
508 pjsip_transport *ref_tp,
Benny Prijono85598d92006-01-07 18:44:25 +0000509 char *target_url,
510 int *lost)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000511{
512 enum { THREADS = 4, INTERVAL = 10 };
513 int i;
514 pj_status_t status;
515 pj_pool_t *pool;
Benny Prijono85598d92006-01-07 18:44:25 +0000516 pj_bool_t logger_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000517
518 pj_timestamp zero_time, total_time;
519 unsigned usec_rt;
520 unsigned total_sent;
521 unsigned total_recv;
522
Benny Prijono85598d92006-01-07 18:44:25 +0000523 PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...",
Benny Prijono0ca04b62005-12-30 23:50:15 +0000524 THREADS));
Benny Prijono85598d92006-01-07 18:44:25 +0000525 PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..",
526 INTERVAL));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000527
Benny Prijono85598d92006-01-07 18:44:25 +0000528 /* Make sure msg logger is disabled. */
529 logger_enabled = msg_logger_set_enabled(0);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000530
531 /* Register module (if not yet registered) */
532 if (rt_module.id == -1) {
533 status = pjsip_endpt_register_module( endpt, &rt_module );
534 if (status != PJ_SUCCESS) {
535 app_perror(" error: unable to register module", status);
536 return -600;
537 }
538 }
539
540 /* Create pool for this test. */
541 pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
542 if (!pool)
543 return -610;
544
545 /* Initialize static test data. */
Nanang Izzuddin7d1ac292008-09-16 17:02:48 +0000546 pj_ansi_strcpy(rt_target_uri, target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000547 rt_call_id = pj_str("RT-Call-Id/");
548 rt_stop = PJ_FALSE;
549
550 /* Initialize thread data. */
551 for (i=0; i<THREADS; ++i) {
552 char buf[1];
553 pj_str_t str_id = { buf, 1 };
554
Benny Prijonoac623b32006-07-03 15:19:31 +0000555 pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i]));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000556
Benny Prijono85598d92006-01-07 18:44:25 +0000557 /* Init timer entry */
558 rt_test_data[i].tx_timer.id = i;
559 rt_test_data[i].tx_timer.cb = &rt_tx_timer;
560 rt_test_data[i].timeout_timer.id = i;
561 rt_test_data[i].timeout_timer.cb = &rt_timeout_timer;
562
Benny Prijono0ca04b62005-12-30 23:50:15 +0000563 /* Generate Call-ID for each thread. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000564 rt_test_data[i].call_id.ptr = (char*) pj_pool_alloc(pool, rt_call_id.slen+1);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000565 pj_strcpy(&rt_test_data[i].call_id, &rt_call_id);
566 buf[0] = '0' + i;
567 pj_strcat(&rt_test_data[i].call_id, &str_id);
568
Benny Prijono85598d92006-01-07 18:44:25 +0000569 /* Init mutex. */
570 status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex);
571 if (status != PJ_SUCCESS) {
572 app_perror(" error: unable to create mutex", status);
573 return -615;
574 }
575
Benny Prijono0ca04b62005-12-30 23:50:15 +0000576 /* Create thread, suspended. */
Benny Prijono7db431e2006-07-23 14:38:49 +0000577 status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)(long)i, 0,
Benny Prijono0ca04b62005-12-30 23:50:15 +0000578 PJ_THREAD_SUSPENDED, &rt_test_data[i].thread);
579 if (status != PJ_SUCCESS) {
580 app_perror(" error: unable to create thread", status);
581 return -620;
582 }
583 }
584
585 /* Start threads! */
586 for (i=0; i<THREADS; ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +0000587 pj_time_val delay = {0,0};
Benny Prijono0ca04b62005-12-30 23:50:15 +0000588 pj_thread_resume(rt_test_data[i].thread);
Benny Prijono85598d92006-01-07 18:44:25 +0000589
590 /* Schedule first message transmissions. */
591 rt_test_data[i].tx_timer.user_data = (void*)1;
592 pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000593 }
594
595 /* Sleep for some time. */
596 pj_thread_sleep(INTERVAL * 1000);
597
598 /* Signal thread to stop. */
599 rt_stop = PJ_TRUE;
600
601 /* Wait threads to complete. */
602 for (i=0; i<THREADS; ++i) {
603 pj_thread_join(rt_test_data[i].thread);
604 pj_thread_destroy(rt_test_data[i].thread);
605 }
606
Benny Prijono85598d92006-01-07 18:44:25 +0000607 /* Destroy rt_test_data */
608 for (i=0; i<THREADS; ++i) {
609 pj_mutex_destroy(rt_test_data[i].mutex);
610 pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer);
611 }
612
Benny Prijono0ca04b62005-12-30 23:50:15 +0000613 /* Gather statistics. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000614 pj_bzero(&total_time, sizeof(total_time));
615 pj_bzero(&zero_time, sizeof(zero_time));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000616 usec_rt = total_sent = total_recv = 0;
617 for (i=0; i<THREADS; ++i) {
618 total_sent += rt_test_data[i].sent_request_count;
619 total_recv += rt_test_data[i].recv_response_count;
620 pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time);
621 }
622
623 /* Display statistics. */
624 if (total_recv)
625 total_time.u64 = total_time.u64/total_recv;
626 else
627 total_time.u64 = 0;
628 usec_rt = pj_elapsed_usec(&zero_time, &total_time);
Benny Prijono85598d92006-01-07 18:44:25 +0000629 PJ_LOG(3,(THIS_FILE, " done."));
630 PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent));
631 PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000632
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000633 pjsip_endpt_release_pool(endpt, pool);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000634
Benny Prijono85598d92006-01-07 18:44:25 +0000635 *lost = total_sent-total_recv;
636
637 /* Flush events. */
638 flush_events(500);
639
640 /* Restore msg logger. */
641 msg_logger_set_enabled(logger_enabled);
642
Benny Prijono0ca04b62005-12-30 23:50:15 +0000643 return 0;
644}
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000645
646///////////////////////////////////////////////////////////////////////////////
647/*
648 * Transport load testing
649 */
650static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata);
651
652static struct mod_load_test
653{
654 pjsip_module mod;
Benny Prijono3c97d9b2008-09-21 22:01:46 +0000655 pj_int32_t next_seq;
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000656 pj_bool_t err;
657} mod_load =
658{
659 {
660 NULL, NULL, /* prev and next */
661 { "mod-load-test", 13}, /* Name. */
662 -1, /* Id */
663 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
664 NULL, /* load() */
665 NULL, /* start() */
666 NULL, /* stop() */
667 NULL, /* unload() */
668 &load_on_rx_request, /* on_rx_request() */
669 NULL, /* on_rx_response() */
670 NULL, /* tsx_handler() */
671 }
672};
673
674
675static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata)
676{
677 if (rdata->msg_info.cseq->cseq != mod_load.next_seq) {
678 PJ_LOG(1,("THIS_FILE", " err: expecting cseq %u, got %u",
679 mod_load.next_seq, rdata->msg_info.cseq->cseq));
680 mod_load.err = PJ_TRUE;
681 mod_load.next_seq = rdata->msg_info.cseq->cseq + 1;
682 } else
683 mod_load.next_seq++;
684 return PJ_TRUE;
685}
686
687int transport_load_test(char *target_url)
688{
689 enum { COUNT = 2000 };
690 unsigned i;
Nanang Izzuddin838cb322008-12-18 17:52:57 +0000691 pj_status_t status = PJ_SUCCESS;
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000692
693 /* exhaust packets */
694 do {
695 pj_time_val delay = {1, 0};
696 i = 0;
697 pjsip_endpt_handle_events2(endpt, &delay, &i);
698 } while (i != 0);
699
700 PJ_LOG(3,(THIS_FILE, " transport load test..."));
701
702 if (mod_load.mod.id == -1) {
703 status = pjsip_endpt_register_module( endpt, &mod_load.mod);
704 if (status != PJ_SUCCESS) {
705 app_perror("error registering module", status);
706 return -1;
707 }
708 }
709 mod_load.err = PJ_FALSE;
710 mod_load.next_seq = 0;
711
712 for (i=0; i<COUNT && !mod_load.err; ++i) {
713 pj_str_t target, from, call_id;
714 pjsip_tx_data *tdata;
715
716 target = pj_str(target_url);
717 from = pj_str("<sip:user@host>");
718 call_id = pj_str("thecallid");
719 status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
720 &target, &from,
721 &target, &from, &call_id,
722 i, NULL, &tdata );
723 if (status != PJ_SUCCESS) {
724 app_perror("error creating request", status);
725 goto on_return;
726 }
727
728 status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL);
729 if (status != PJ_SUCCESS) {
730 app_perror("error sending request", status);
731 goto on_return;
732 }
733 }
734
735 do {
736 pj_time_val delay = {1, 0};
737 i = 0;
738 pjsip_endpt_handle_events2(endpt, &delay, &i);
739 } while (i != 0);
740
741 if (mod_load.next_seq != COUNT) {
742 PJ_LOG(1,("THIS_FILE", " err: expecting %u msg, got only %u",
743 COUNT, mod_load.next_seq));
744 status = -2;
745 goto on_return;
746 }
747
748on_return:
749 if (mod_load.mod.id != -1) {
750 pjsip_endpt_unregister_module( endpt, &mod_load.mod);
751 mod_load.mod.id = -1;
752 }
753 if (status != PJ_SUCCESS || mod_load.err) {
754 return -2;
755 }
756 PJ_LOG(3,(THIS_FILE, " success"));
757 return 0;
758}
759
760