blob: df6f55eb742668e46b747028520a82d84b171607 [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 */
103 NULL, /* User data. */
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 Prijonofa73e3e2006-01-05 23:35:46 +0000177 char *target_url )
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). */
224 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL,
225 &send_msg_callback);
226 if (status != PJ_SUCCESS) {
227 /* Immediate error! */
228 pjsip_tx_data_dec_ref(tdata);
229 send_status = status;
230 }
231
232 /* Set the timeout (1 second from now) */
233 pj_gettimeofday(&timeout);
234 timeout.sec += 1;
235
236 /* Loop handling events until we get status */
237 do {
238 pj_time_val now;
239 pj_time_val poll_interval = { 0, 10 };
240
241 pj_gettimeofday(&now);
242 if (PJ_TIME_VAL_GTE(now, timeout)) {
Benny Prijono85598d92006-01-07 18:44:25 +0000243 PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test"));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000244 status = -540;
245 goto on_return;
246 }
247
248 if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) {
249 app_perror(" error sending message", send_status);
250 status = -550;
251 goto on_return;
252 }
253
254 if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) {
255 app_perror(" error receiving message", recv_status);
256 status = -560;
257 goto on_return;
258 }
259
260 if (send_status!=NO_STATUS && recv_status!=NO_STATUS) {
261 /* Success! */
262 break;
263 }
264
265 pjsip_endpt_handle_events(endpt, &poll_interval);
266
267 } while (1);
268
269 if (status == PJ_SUCCESS) {
270 unsigned usec_rt;
271 usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time);
Benny Prijono85598d92006-01-07 18:44:25 +0000272 PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000273 }
274
Benny Prijono85598d92006-01-07 18:44:25 +0000275 /* Restore message logging. */
276 msg_logger_set_enabled(msg_log_enabled);
277
Benny Prijono0ca04b62005-12-30 23:50:15 +0000278 status = PJ_SUCCESS;
279
280on_return:
281 return status;
282}
283
284
285///////////////////////////////////////////////////////////////////////////////
286/*
287 * Multithreaded round-trip test
288 *
289 * This test will spawn multiple threads, each of them send a request. As soon
290 * as request is received, response will be sent, and time is recorded.
291 *
292 * The main purpose of this test is to ensure there's no crash when multiple
293 * threads are sending/receiving messages.
294 *
295 */
296static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata);
297static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata);
298
299static pjsip_module rt_module =
300{
301 NULL, NULL, /* prev and next */
302 { "Transport-RT-Test", 17}, /* Name. */
303 -1, /* Id */
304 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
305 NULL, /* User data. */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000306 NULL, /* load() */
307 NULL, /* start() */
308 NULL, /* stop() */
309 NULL, /* unload() */
310 &rt_on_rx_request, /* on_rx_request() */
311 &rt_on_rx_response, /* on_rx_response() */
312 NULL, /* tsx_handler() */
313};
314
315static struct
316{
317 pj_thread_t *thread;
318 pj_timestamp send_time;
319 pj_timestamp total_rt_time;
320 int sent_request_count, recv_response_count;
321 pj_str_t call_id;
Benny Prijono85598d92006-01-07 18:44:25 +0000322 pj_timer_entry timeout_timer;
323 pj_timer_entry tx_timer;
324 pj_mutex_t *mutex;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000325} rt_test_data[16];
326
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000327static char rt_target_uri[64];
Benny Prijono0ca04b62005-12-30 23:50:15 +0000328static pj_bool_t rt_stop;
329static pj_str_t rt_call_id;
330
331static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata)
332{
Benny Prijono728a9052006-01-18 23:34:15 +0000333 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
334 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/');
Benny Prijono0ca04b62005-12-30 23:50:15 +0000335 int thread_id = (*pos - '0');
336
337 pjsip_tx_data *tdata;
338 pjsip_response_addr res_addr;
339 pj_status_t status;
340
341 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
342 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000343 app_perror(" error creating response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000344 return PJ_TRUE;
345 }
346 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
347 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000348 app_perror(" error in get response address", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000349 pjsip_tx_data_dec_ref(tdata);
350 return PJ_TRUE;
351 }
352 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
353 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000354 app_perror(" error sending response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000355 pjsip_tx_data_dec_ref(tdata);
356 return PJ_TRUE;
357 }
358 return PJ_TRUE;
359
360 }
361 return PJ_FALSE;
362}
363
364static pj_status_t rt_send_request(int thread_id)
365{
366 pj_status_t status;
367 pj_str_t target, from, to, contact, call_id;
368 pjsip_tx_data *tdata;
Benny Prijono85598d92006-01-07 18:44:25 +0000369 pj_time_val timeout_delay;
370
371 pj_mutex_lock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000372
373 /* Create a request message. */
374 target = pj_str(rt_target_uri);
375 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000376 to = pj_str(rt_target_uri);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000377 contact = pj_str(CONTACT_HDR);
378 call_id = rt_test_data[thread_id].call_id;
379
380 status = pjsip_endpt_create_request( endpt, &pjsip_options_method,
381 &target, &from, &to,
382 &contact, &call_id, -1,
383 NULL, &tdata );
384 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +0000385 app_perror(" error: unable to create request", status);
386 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000387 return -610;
388 }
389
390 /* Start time. */
391 pj_get_timestamp(&rt_test_data[thread_id].send_time);
392
393 /* Send the message (statelessly). */
394 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL);
395 if (status != PJ_SUCCESS) {
396 /* Immediate error! */
Benny Prijono85598d92006-01-07 18:44:25 +0000397 app_perror(" error: send request", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000398 pjsip_tx_data_dec_ref(tdata);
Benny Prijono85598d92006-01-07 18:44:25 +0000399 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000400 return -620;
401 }
402
403 /* Update counter. */
404 rt_test_data[thread_id].sent_request_count++;
405
Benny Prijono85598d92006-01-07 18:44:25 +0000406 /* Set timeout timer. */
407 if (rt_test_data[thread_id].timeout_timer.user_data != NULL) {
408 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
409 }
410 timeout_delay.sec = 100; timeout_delay.msec = 0;
411 rt_test_data[thread_id].timeout_timer.user_data = (void*)1;
412 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer,
413 &timeout_delay);
414
415 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000416 return PJ_SUCCESS;
417}
418
419static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata)
420{
Benny Prijono728a9052006-01-18 23:34:15 +0000421 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
422 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000423 int thread_id = (*pos - '0');
424 pj_timestamp recv_time;
425
Benny Prijono85598d92006-01-07 18:44:25 +0000426 pj_mutex_lock(rt_test_data[thread_id].mutex);
427
428 /* Stop timer. */
429 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
430
Benny Prijono0ca04b62005-12-30 23:50:15 +0000431 /* Update counter and end-time. */
432 rt_test_data[thread_id].recv_response_count++;
433 pj_get_timestamp(&recv_time);
434
435 pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time);
436 pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time);
437
Benny Prijono85598d92006-01-07 18:44:25 +0000438 if (!rt_stop) {
439 pj_time_val tx_delay = { 0, 0 };
440 pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL);
441 rt_test_data[thread_id].tx_timer.user_data = (void*)1;
442 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer,
443 &tx_delay);
444 }
445
446 pj_mutex_unlock(rt_test_data[thread_id].mutex);
447
Benny Prijono0ca04b62005-12-30 23:50:15 +0000448 return PJ_TRUE;
449 }
450 return PJ_FALSE;
451}
452
Benny Prijono85598d92006-01-07 18:44:25 +0000453static void rt_timeout_timer( pj_timer_heap_t *timer_heap,
454 struct pj_timer_entry *entry )
455{
456 pj_mutex_lock(rt_test_data[entry->id].mutex);
457
458 PJ_UNUSED_ARG(timer_heap);
459 PJ_LOG(3,(THIS_FILE, " timeout waiting for response"));
460 rt_test_data[entry->id].timeout_timer.user_data = NULL;
461
462 if (rt_test_data[entry->id].tx_timer.user_data == NULL) {
463 pj_time_val delay = { 0, 0 };
464 rt_test_data[entry->id].tx_timer.user_data = (void*)1;
465 pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer,
466 &delay);
467 }
468
469 pj_mutex_unlock(rt_test_data[entry->id].mutex);
470}
471
472static void rt_tx_timer( pj_timer_heap_t *timer_heap,
473 struct pj_timer_entry *entry )
474{
475 pj_mutex_lock(rt_test_data[entry->id].mutex);
476
477 PJ_UNUSED_ARG(timer_heap);
478 pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL);
479 rt_test_data[entry->id].tx_timer.user_data = NULL;
480 rt_send_request(entry->id);
481
482 pj_mutex_unlock(rt_test_data[entry->id].mutex);
483}
484
485
486static int rt_worker_thread(void *arg)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000487{
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000488 int i, thread_id = (int)arg;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000489 pj_time_val poll_delay = { 0, 10 };
490
491 /* Sleep to allow main threads to run. */
492 pj_thread_sleep(10);
493
Benny Prijono0ca04b62005-12-30 23:50:15 +0000494 while (!rt_stop) {
495 pjsip_endpt_handle_events(endpt, &poll_delay);
496 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000497
498 /* Exhaust responses. */
499 for (i=0; i<100; ++i)
500 pjsip_endpt_handle_events(endpt, &poll_delay);
501
Benny Prijono0ca04b62005-12-30 23:50:15 +0000502 return 0;
503}
504
505int transport_rt_test( pjsip_transport_type_e tp_type,
506 pjsip_transport *ref_tp,
Benny Prijono85598d92006-01-07 18:44:25 +0000507 char *target_url,
508 int *lost)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000509{
510 enum { THREADS = 4, INTERVAL = 10 };
511 int i;
512 pj_status_t status;
513 pj_pool_t *pool;
Benny Prijono85598d92006-01-07 18:44:25 +0000514 pj_bool_t logger_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000515
516 pj_timestamp zero_time, total_time;
517 unsigned usec_rt;
518 unsigned total_sent;
519 unsigned total_recv;
520
521
Benny Prijono85598d92006-01-07 18:44:25 +0000522 PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...",
Benny Prijono0ca04b62005-12-30 23:50:15 +0000523 THREADS));
Benny Prijono85598d92006-01-07 18:44:25 +0000524 PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..",
525 INTERVAL));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000526
Benny Prijono85598d92006-01-07 18:44:25 +0000527 /* Make sure msg logger is disabled. */
528 logger_enabled = msg_logger_set_enabled(0);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000529
530 /* Register module (if not yet registered) */
531 if (rt_module.id == -1) {
532 status = pjsip_endpt_register_module( endpt, &rt_module );
533 if (status != PJ_SUCCESS) {
534 app_perror(" error: unable to register module", status);
535 return -600;
536 }
537 }
538
539 /* Create pool for this test. */
540 pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
541 if (!pool)
542 return -610;
543
544 /* Initialize static test data. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000545 pj_native_strcpy(rt_target_uri, target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000546 rt_call_id = pj_str("RT-Call-Id/");
547 rt_stop = PJ_FALSE;
548
549 /* Initialize thread data. */
550 for (i=0; i<THREADS; ++i) {
551 char buf[1];
552 pj_str_t str_id = { buf, 1 };
553
554 pj_memset(&rt_test_data[i], 0, sizeof(rt_test_data[i]));
555
Benny Prijono85598d92006-01-07 18:44:25 +0000556 /* Init timer entry */
557 rt_test_data[i].tx_timer.id = i;
558 rt_test_data[i].tx_timer.cb = &rt_tx_timer;
559 rt_test_data[i].timeout_timer.id = i;
560 rt_test_data[i].timeout_timer.cb = &rt_timeout_timer;
561
Benny Prijono0ca04b62005-12-30 23:50:15 +0000562 /* Generate Call-ID for each thread. */
563 rt_test_data[i].call_id.ptr = pj_pool_alloc(pool, rt_call_id.slen+1);
564 pj_strcpy(&rt_test_data[i].call_id, &rt_call_id);
565 buf[0] = '0' + i;
566 pj_strcat(&rt_test_data[i].call_id, &str_id);
567
Benny Prijono85598d92006-01-07 18:44:25 +0000568 /* Init mutex. */
569 status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex);
570 if (status != PJ_SUCCESS) {
571 app_perror(" error: unable to create mutex", status);
572 return -615;
573 }
574
Benny Prijono0ca04b62005-12-30 23:50:15 +0000575 /* Create thread, suspended. */
Benny Prijono85598d92006-01-07 18:44:25 +0000576 status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)i, 0,
Benny Prijono0ca04b62005-12-30 23:50:15 +0000577 PJ_THREAD_SUSPENDED, &rt_test_data[i].thread);
578 if (status != PJ_SUCCESS) {
579 app_perror(" error: unable to create thread", status);
580 return -620;
581 }
582 }
583
584 /* Start threads! */
585 for (i=0; i<THREADS; ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +0000586 pj_time_val delay = {0,0};
Benny Prijono0ca04b62005-12-30 23:50:15 +0000587 pj_thread_resume(rt_test_data[i].thread);
Benny Prijono85598d92006-01-07 18:44:25 +0000588
589 /* Schedule first message transmissions. */
590 rt_test_data[i].tx_timer.user_data = (void*)1;
591 pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000592 }
593
594 /* Sleep for some time. */
595 pj_thread_sleep(INTERVAL * 1000);
596
597 /* Signal thread to stop. */
598 rt_stop = PJ_TRUE;
599
600 /* Wait threads to complete. */
601 for (i=0; i<THREADS; ++i) {
602 pj_thread_join(rt_test_data[i].thread);
603 pj_thread_destroy(rt_test_data[i].thread);
604 }
605
Benny Prijono85598d92006-01-07 18:44:25 +0000606 /* Destroy rt_test_data */
607 for (i=0; i<THREADS; ++i) {
608 pj_mutex_destroy(rt_test_data[i].mutex);
609 pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer);
610 }
611
Benny Prijono0ca04b62005-12-30 23:50:15 +0000612 /* Gather statistics. */
613 pj_memset(&total_time, 0, sizeof(total_time));
614 pj_memset(&zero_time, 0, sizeof(zero_time));
615 usec_rt = total_sent = total_recv = 0;
616 for (i=0; i<THREADS; ++i) {
617 total_sent += rt_test_data[i].sent_request_count;
618 total_recv += rt_test_data[i].recv_response_count;
619 pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time);
620 }
621
622 /* Display statistics. */
623 if (total_recv)
624 total_time.u64 = total_time.u64/total_recv;
625 else
626 total_time.u64 = 0;
627 usec_rt = pj_elapsed_usec(&zero_time, &total_time);
Benny Prijono85598d92006-01-07 18:44:25 +0000628 PJ_LOG(3,(THIS_FILE, " done."));
629 PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent));
630 PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000631
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000632 pjsip_endpt_release_pool(endpt, pool);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000633
Benny Prijono85598d92006-01-07 18:44:25 +0000634 *lost = total_sent-total_recv;
635
636 /* Flush events. */
637 flush_events(500);
638
639 /* Restore msg logger. */
640 msg_logger_set_enabled(logger_enabled);
641
Benny Prijono0ca04b62005-12-30 23:50:15 +0000642 return 0;
643}