blob: 2d84efeae1929fc984e37f625c6959cbc2e8d4b4 [file] [log] [blame]
Benny Prijono0ca04b62005-12-30 23:50:15 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include "test.h"
Benny Prijono40f2f642006-01-30 18:40:05 +000021#include <pjsip.h>
Benny Prijono0ca04b62005-12-30 23:50:15 +000022#include <pjlib.h>
23
Benny Prijono85598d92006-01-07 18:44:25 +000024#define THIS_FILE "transport_test.c"
25
Benny Prijono0ca04b62005-12-30 23:50:15 +000026///////////////////////////////////////////////////////////////////////////////
27/*
28 * Generic testing for transport, to make sure that basic
29 * attributes have been initialized properly.
30 */
31int generic_transport_test(pjsip_transport *tp)
32{
Benny Prijono85598d92006-01-07 18:44:25 +000033 PJ_LOG(3,(THIS_FILE, " structure test..."));
Benny Prijono0ca04b62005-12-30 23:50:15 +000034
35 /* Check that local address name is valid. */
36 {
37 struct pj_in_addr addr;
38
39 /* Note: inet_aton() returns non-zero if addr is valid! */
40 if (pj_inet_aton(&tp->local_name.host, &addr) != 0) {
41 if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) {
Benny Prijono85598d92006-01-07 18:44:25 +000042 PJ_LOG(3,(THIS_FILE, " Error: invalid address name"));
Benny Prijono0ca04b62005-12-30 23:50:15 +000043 return -420;
44 }
45 } else {
46 /* It's okay. local_name.host may be a hostname instead of
47 * IP address.
48 */
49 }
50 }
51
52 /* Check that port is valid. */
53 if (tp->local_name.port <= 0) {
54 return -430;
55 }
56
57 /* Check length of address (for now we only check against sockaddr_in). */
58 if (tp->addr_len != sizeof(pj_sockaddr_in))
59 return -440;
60
61 /* Check type. */
62 if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED)
63 return -450;
64
65 /* That's it. */
66 return PJ_SUCCESS;
67}
68
69///////////////////////////////////////////////////////////////////////////////
70/*
71 * Send/receive test.
72 *
73 * This test sends a request to loopback address; as soon as request is
74 * received, response will be sent, and time is recorded.
75 *
76 * The main purpose is to test that the basic transport functionalities works,
77 * before we continue with more complicated tests.
78 */
79#define FROM_HDR "Bob <sip:bob@example.com>"
Benny Prijono0ca04b62005-12-30 23:50:15 +000080#define CONTACT_HDR "Bob <sip:bob@127.0.0.1>"
81#define CALL_ID_HDR "SendRecv-Test"
82#define CSEQ_VALUE 100
83#define BODY "Hello World!"
84
85static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata);
86static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata);
87
88/* Flag to indicate message has been received
89 * (or failed to send)
90 */
91#define NO_STATUS -2
92static int send_status = NO_STATUS;
93static int recv_status = NO_STATUS;
94static pj_timestamp my_send_time, my_recv_time;
95
96/* Module to receive messages for this test. */
97static pjsip_module my_module =
98{
99 NULL, NULL, /* prev and next */
100 { "Transport-Test", 14}, /* Name. */
101 -1, /* Id */
102 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000103 NULL, /* load() */
104 NULL, /* start() */
105 NULL, /* stop() */
106 NULL, /* unload() */
107 &my_on_rx_request, /* on_rx_request() */
108 &my_on_rx_response, /* on_rx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000109 NULL, /* on_tsx_state() */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000110};
111
112
113static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata)
114{
115 /* Check that this is our request. */
Benny Prijono728a9052006-01-18 23:34:15 +0000116 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000117 /* It is! */
118 /* Send response. */
119 pjsip_tx_data *tdata;
120 pjsip_response_addr res_addr;
121 pj_status_t status;
122
Benny Prijono0ca04b62005-12-30 23:50:15 +0000123 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
124 if (status != PJ_SUCCESS) {
125 recv_status = status;
126 return PJ_TRUE;
127 }
128 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
129 if (status != PJ_SUCCESS) {
130 recv_status = status;
131 pjsip_tx_data_dec_ref(tdata);
132 return PJ_TRUE;
133 }
134 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
135 if (status != PJ_SUCCESS) {
136 recv_status = status;
137 pjsip_tx_data_dec_ref(tdata);
138 return PJ_TRUE;
139 }
140 return PJ_TRUE;
141 }
142
143 /* Not ours. */
144 return PJ_FALSE;
145}
146
147static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata)
148{
Benny Prijono728a9052006-01-18 23:34:15 +0000149 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000150 pj_get_timestamp(&my_recv_time);
151 recv_status = PJ_SUCCESS;
152 return PJ_TRUE;
153 }
154 return PJ_FALSE;
155}
156
157/* Transport callback. */
158static void send_msg_callback(pjsip_send_state *stateless_data,
159 pj_ssize_t sent, pj_bool_t *cont)
160{
161 if (sent < 1) {
162 /* Obtain the error code. */
163 send_status = -sent;
164 } else {
165 send_status = PJ_SUCCESS;
166 }
167
168 /* Don't want to continue. */
169 *cont = PJ_FALSE;
170}
171
172
173/* Test that we receive loopback message. */
174int transport_send_recv_test( pjsip_transport_type_e tp_type,
175 pjsip_transport *ref_tp,
Benny Prijonoe93e2872006-06-28 16:46:49 +0000176 char *target_url,
177 int *p_usec_rtt)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000178{
Benny Prijono85598d92006-01-07 18:44:25 +0000179 pj_bool_t msg_log_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000180 pj_status_t status;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000181 pj_str_t target, from, to, contact, call_id, body;
182 pjsip_method method;
183 pjsip_tx_data *tdata;
184 pj_time_val timeout;
185
Benny Prijono85598d92006-01-07 18:44:25 +0000186 PJ_LOG(3,(THIS_FILE, " single message round-trip test..."));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000187
188 /* Register out test module to receive the message (if necessary). */
189 if (my_module.id == -1) {
190 status = pjsip_endpt_register_module( endpt, &my_module );
191 if (status != PJ_SUCCESS) {
192 app_perror(" error: unable to register module", status);
193 return -500;
194 }
195 }
196
Benny Prijono85598d92006-01-07 18:44:25 +0000197 /* Disable message logging. */
198 msg_log_enabled = msg_logger_set_enabled(0);
199
Benny Prijono0ca04b62005-12-30 23:50:15 +0000200 /* Create a request message. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000201 target = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000202 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000203 to = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000204 contact = pj_str(CONTACT_HDR);
205 call_id = pj_str(CALL_ID_HDR);
206 body = pj_str(BODY);
207
208 pjsip_method_set(&method, PJSIP_OPTIONS_METHOD);
209 status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to,
210 &contact, &call_id, CSEQ_VALUE,
211 &body, &tdata );
212 if (status != PJ_SUCCESS) {
213 app_perror(" error: unable to create request", status);
214 return -510;
215 }
216
217 /* Reset statuses */
218 send_status = recv_status = NO_STATUS;
219
220 /* Start time. */
221 pj_get_timestamp(&my_send_time);
222
223 /* Send the message (statelessly). */
Benny Prijonoe93e2872006-06-28 16:46:49 +0000224 PJ_LOG(5,(THIS_FILE, "Sending request to %.*s",
225 (int)target.slen, target.ptr));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000226 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL,
227 &send_msg_callback);
228 if (status != PJ_SUCCESS) {
229 /* Immediate error! */
230 pjsip_tx_data_dec_ref(tdata);
231 send_status = status;
232 }
233
Benny Prijonoe93e2872006-06-28 16:46:49 +0000234 /* Set the timeout (2 seconds from now) */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000235 pj_gettimeofday(&timeout);
Benny Prijonoe93e2872006-06-28 16:46:49 +0000236 timeout.sec += 2;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000237
238 /* Loop handling events until we get status */
239 do {
240 pj_time_val now;
241 pj_time_val poll_interval = { 0, 10 };
242
243 pj_gettimeofday(&now);
244 if (PJ_TIME_VAL_GTE(now, timeout)) {
Benny Prijono85598d92006-01-07 18:44:25 +0000245 PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test"));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000246 status = -540;
247 goto on_return;
248 }
249
250 if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) {
251 app_perror(" error sending message", send_status);
252 status = -550;
253 goto on_return;
254 }
255
256 if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) {
257 app_perror(" error receiving message", recv_status);
258 status = -560;
259 goto on_return;
260 }
261
262 if (send_status!=NO_STATUS && recv_status!=NO_STATUS) {
263 /* Success! */
264 break;
265 }
266
267 pjsip_endpt_handle_events(endpt, &poll_interval);
268
269 } while (1);
270
271 if (status == PJ_SUCCESS) {
272 unsigned usec_rt;
273 usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time);
Benny Prijonoe93e2872006-06-28 16:46:49 +0000274
Benny Prijono85598d92006-01-07 18:44:25 +0000275 PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt));
Benny Prijonoe93e2872006-06-28 16:46:49 +0000276
277 *p_usec_rtt = usec_rt;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000278 }
279
Benny Prijono85598d92006-01-07 18:44:25 +0000280 /* Restore message logging. */
281 msg_logger_set_enabled(msg_log_enabled);
282
Benny Prijono0ca04b62005-12-30 23:50:15 +0000283 status = PJ_SUCCESS;
284
285on_return:
286 return status;
287}
288
289
290///////////////////////////////////////////////////////////////////////////////
291/*
292 * Multithreaded round-trip test
293 *
294 * This test will spawn multiple threads, each of them send a request. As soon
295 * as request is received, response will be sent, and time is recorded.
296 *
297 * The main purpose of this test is to ensure there's no crash when multiple
298 * threads are sending/receiving messages.
299 *
300 */
301static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata);
302static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata);
303
304static pjsip_module rt_module =
305{
306 NULL, NULL, /* prev and next */
307 { "Transport-RT-Test", 17}, /* Name. */
308 -1, /* Id */
309 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000310 NULL, /* load() */
311 NULL, /* start() */
312 NULL, /* stop() */
313 NULL, /* unload() */
314 &rt_on_rx_request, /* on_rx_request() */
315 &rt_on_rx_response, /* on_rx_response() */
316 NULL, /* tsx_handler() */
317};
318
319static struct
320{
321 pj_thread_t *thread;
322 pj_timestamp send_time;
323 pj_timestamp total_rt_time;
324 int sent_request_count, recv_response_count;
325 pj_str_t call_id;
Benny Prijono85598d92006-01-07 18:44:25 +0000326 pj_timer_entry timeout_timer;
327 pj_timer_entry tx_timer;
328 pj_mutex_t *mutex;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000329} rt_test_data[16];
330
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000331static char rt_target_uri[64];
Benny Prijono0ca04b62005-12-30 23:50:15 +0000332static pj_bool_t rt_stop;
333static pj_str_t rt_call_id;
334
335static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata)
336{
Benny Prijono728a9052006-01-18 23:34:15 +0000337 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
338 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/');
Benny Prijono0ca04b62005-12-30 23:50:15 +0000339 int thread_id = (*pos - '0');
340
341 pjsip_tx_data *tdata;
342 pjsip_response_addr res_addr;
343 pj_status_t status;
344
345 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
346 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000347 app_perror(" error creating response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000348 return PJ_TRUE;
349 }
350 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
351 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000352 app_perror(" error in get response address", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000353 pjsip_tx_data_dec_ref(tdata);
354 return PJ_TRUE;
355 }
356 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
357 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000358 app_perror(" error sending response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000359 pjsip_tx_data_dec_ref(tdata);
360 return PJ_TRUE;
361 }
362 return PJ_TRUE;
363
364 }
365 return PJ_FALSE;
366}
367
368static pj_status_t rt_send_request(int thread_id)
369{
370 pj_status_t status;
371 pj_str_t target, from, to, contact, call_id;
372 pjsip_tx_data *tdata;
Benny Prijono85598d92006-01-07 18:44:25 +0000373 pj_time_val timeout_delay;
374
375 pj_mutex_lock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000376
377 /* Create a request message. */
378 target = pj_str(rt_target_uri);
379 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000380 to = pj_str(rt_target_uri);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000381 contact = pj_str(CONTACT_HDR);
382 call_id = rt_test_data[thread_id].call_id;
383
384 status = pjsip_endpt_create_request( endpt, &pjsip_options_method,
385 &target, &from, &to,
386 &contact, &call_id, -1,
387 NULL, &tdata );
388 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +0000389 app_perror(" error: unable to create request", status);
390 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000391 return -610;
392 }
393
394 /* Start time. */
395 pj_get_timestamp(&rt_test_data[thread_id].send_time);
396
397 /* Send the message (statelessly). */
398 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL);
399 if (status != PJ_SUCCESS) {
400 /* Immediate error! */
Benny Prijono85598d92006-01-07 18:44:25 +0000401 app_perror(" error: send request", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000402 pjsip_tx_data_dec_ref(tdata);
Benny Prijono85598d92006-01-07 18:44:25 +0000403 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000404 return -620;
405 }
406
407 /* Update counter. */
408 rt_test_data[thread_id].sent_request_count++;
409
Benny Prijono85598d92006-01-07 18:44:25 +0000410 /* Set timeout timer. */
411 if (rt_test_data[thread_id].timeout_timer.user_data != NULL) {
412 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
413 }
414 timeout_delay.sec = 100; timeout_delay.msec = 0;
415 rt_test_data[thread_id].timeout_timer.user_data = (void*)1;
416 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer,
417 &timeout_delay);
418
419 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000420 return PJ_SUCCESS;
421}
422
423static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata)
424{
Benny Prijono728a9052006-01-18 23:34:15 +0000425 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
426 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000427 int thread_id = (*pos - '0');
428 pj_timestamp recv_time;
429
Benny Prijono85598d92006-01-07 18:44:25 +0000430 pj_mutex_lock(rt_test_data[thread_id].mutex);
431
432 /* Stop timer. */
433 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
434
Benny Prijono0ca04b62005-12-30 23:50:15 +0000435 /* Update counter and end-time. */
436 rt_test_data[thread_id].recv_response_count++;
437 pj_get_timestamp(&recv_time);
438
439 pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time);
440 pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time);
441
Benny Prijono85598d92006-01-07 18:44:25 +0000442 if (!rt_stop) {
443 pj_time_val tx_delay = { 0, 0 };
444 pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL);
445 rt_test_data[thread_id].tx_timer.user_data = (void*)1;
446 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer,
447 &tx_delay);
448 }
449
450 pj_mutex_unlock(rt_test_data[thread_id].mutex);
451
Benny Prijono0ca04b62005-12-30 23:50:15 +0000452 return PJ_TRUE;
453 }
454 return PJ_FALSE;
455}
456
Benny Prijono85598d92006-01-07 18:44:25 +0000457static void rt_timeout_timer( pj_timer_heap_t *timer_heap,
458 struct pj_timer_entry *entry )
459{
460 pj_mutex_lock(rt_test_data[entry->id].mutex);
461
462 PJ_UNUSED_ARG(timer_heap);
463 PJ_LOG(3,(THIS_FILE, " timeout waiting for response"));
464 rt_test_data[entry->id].timeout_timer.user_data = NULL;
465
466 if (rt_test_data[entry->id].tx_timer.user_data == NULL) {
467 pj_time_val delay = { 0, 0 };
468 rt_test_data[entry->id].tx_timer.user_data = (void*)1;
469 pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer,
470 &delay);
471 }
472
473 pj_mutex_unlock(rt_test_data[entry->id].mutex);
474}
475
476static void rt_tx_timer( pj_timer_heap_t *timer_heap,
477 struct pj_timer_entry *entry )
478{
479 pj_mutex_lock(rt_test_data[entry->id].mutex);
480
481 PJ_UNUSED_ARG(timer_heap);
482 pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL);
483 rt_test_data[entry->id].tx_timer.user_data = NULL;
484 rt_send_request(entry->id);
485
486 pj_mutex_unlock(rt_test_data[entry->id].mutex);
487}
488
489
490static int rt_worker_thread(void *arg)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000491{
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000492 int i, thread_id = (int)arg;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000493 pj_time_val poll_delay = { 0, 10 };
494
495 /* Sleep to allow main threads to run. */
496 pj_thread_sleep(10);
497
Benny Prijono0ca04b62005-12-30 23:50:15 +0000498 while (!rt_stop) {
499 pjsip_endpt_handle_events(endpt, &poll_delay);
500 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000501
502 /* Exhaust responses. */
503 for (i=0; i<100; ++i)
504 pjsip_endpt_handle_events(endpt, &poll_delay);
505
Benny Prijono0ca04b62005-12-30 23:50:15 +0000506 return 0;
507}
508
509int transport_rt_test( pjsip_transport_type_e tp_type,
510 pjsip_transport *ref_tp,
Benny Prijono85598d92006-01-07 18:44:25 +0000511 char *target_url,
512 int *lost)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000513{
514 enum { THREADS = 4, INTERVAL = 10 };
515 int i;
516 pj_status_t status;
517 pj_pool_t *pool;
Benny Prijono85598d92006-01-07 18:44:25 +0000518 pj_bool_t logger_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000519
520 pj_timestamp zero_time, total_time;
521 unsigned usec_rt;
522 unsigned total_sent;
523 unsigned total_recv;
524
Benny Prijono85598d92006-01-07 18:44:25 +0000525 PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...",
Benny Prijono0ca04b62005-12-30 23:50:15 +0000526 THREADS));
Benny Prijono85598d92006-01-07 18:44:25 +0000527 PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..",
528 INTERVAL));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000529
Benny Prijono85598d92006-01-07 18:44:25 +0000530 /* Make sure msg logger is disabled. */
531 logger_enabled = msg_logger_set_enabled(0);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000532
533 /* Register module (if not yet registered) */
534 if (rt_module.id == -1) {
535 status = pjsip_endpt_register_module( endpt, &rt_module );
536 if (status != PJ_SUCCESS) {
537 app_perror(" error: unable to register module", status);
538 return -600;
539 }
540 }
541
542 /* Create pool for this test. */
543 pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
544 if (!pool)
545 return -610;
546
547 /* Initialize static test data. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000548 pj_native_strcpy(rt_target_uri, target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000549 rt_call_id = pj_str("RT-Call-Id/");
550 rt_stop = PJ_FALSE;
551
552 /* Initialize thread data. */
553 for (i=0; i<THREADS; ++i) {
554 char buf[1];
555 pj_str_t str_id = { buf, 1 };
556
Benny Prijonoac623b32006-07-03 15:19:31 +0000557 pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i]));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000558
Benny Prijono85598d92006-01-07 18:44:25 +0000559 /* Init timer entry */
560 rt_test_data[i].tx_timer.id = i;
561 rt_test_data[i].tx_timer.cb = &rt_tx_timer;
562 rt_test_data[i].timeout_timer.id = i;
563 rt_test_data[i].timeout_timer.cb = &rt_timeout_timer;
564
Benny Prijono0ca04b62005-12-30 23:50:15 +0000565 /* Generate Call-ID for each thread. */
566 rt_test_data[i].call_id.ptr = pj_pool_alloc(pool, rt_call_id.slen+1);
567 pj_strcpy(&rt_test_data[i].call_id, &rt_call_id);
568 buf[0] = '0' + i;
569 pj_strcat(&rt_test_data[i].call_id, &str_id);
570
Benny Prijono85598d92006-01-07 18:44:25 +0000571 /* Init mutex. */
572 status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex);
573 if (status != PJ_SUCCESS) {
574 app_perror(" error: unable to create mutex", status);
575 return -615;
576 }
577
Benny Prijono0ca04b62005-12-30 23:50:15 +0000578 /* Create thread, suspended. */
Benny Prijono85598d92006-01-07 18:44:25 +0000579 status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)i, 0,
Benny Prijono0ca04b62005-12-30 23:50:15 +0000580 PJ_THREAD_SUSPENDED, &rt_test_data[i].thread);
581 if (status != PJ_SUCCESS) {
582 app_perror(" error: unable to create thread", status);
583 return -620;
584 }
585 }
586
587 /* Start threads! */
588 for (i=0; i<THREADS; ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +0000589 pj_time_val delay = {0,0};
Benny Prijono0ca04b62005-12-30 23:50:15 +0000590 pj_thread_resume(rt_test_data[i].thread);
Benny Prijono85598d92006-01-07 18:44:25 +0000591
592 /* Schedule first message transmissions. */
593 rt_test_data[i].tx_timer.user_data = (void*)1;
594 pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000595 }
596
597 /* Sleep for some time. */
598 pj_thread_sleep(INTERVAL * 1000);
599
600 /* Signal thread to stop. */
601 rt_stop = PJ_TRUE;
602
603 /* Wait threads to complete. */
604 for (i=0; i<THREADS; ++i) {
605 pj_thread_join(rt_test_data[i].thread);
606 pj_thread_destroy(rt_test_data[i].thread);
607 }
608
Benny Prijono85598d92006-01-07 18:44:25 +0000609 /* Destroy rt_test_data */
610 for (i=0; i<THREADS; ++i) {
611 pj_mutex_destroy(rt_test_data[i].mutex);
612 pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer);
613 }
614
Benny Prijono0ca04b62005-12-30 23:50:15 +0000615 /* Gather statistics. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000616 pj_bzero(&total_time, sizeof(total_time));
617 pj_bzero(&zero_time, sizeof(zero_time));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000618 usec_rt = total_sent = total_recv = 0;
619 for (i=0; i<THREADS; ++i) {
620 total_sent += rt_test_data[i].sent_request_count;
621 total_recv += rt_test_data[i].recv_response_count;
622 pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time);
623 }
624
625 /* Display statistics. */
626 if (total_recv)
627 total_time.u64 = total_time.u64/total_recv;
628 else
629 total_time.u64 = 0;
630 usec_rt = pj_elapsed_usec(&zero_time, &total_time);
Benny Prijono85598d92006-01-07 18:44:25 +0000631 PJ_LOG(3,(THIS_FILE, " done."));
632 PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent));
633 PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000634
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000635 pjsip_endpt_release_pool(endpt, pool);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000636
Benny Prijono85598d92006-01-07 18:44:25 +0000637 *lost = total_sent-total_recv;
638
639 /* Flush events. */
640 flush_events(500);
641
642 /* Restore msg logger. */
643 msg_logger_set_enabled(logger_enabled);
644
Benny Prijono0ca04b62005-12-30 23:50:15 +0000645 return 0;
646}