blob: 0cd0d225014e780f0a21007c79d432d0b8c024f1 [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 Prijonofa73e3e2006-01-05 23:35:46 +0000176 char *target_url )
Benny Prijono0ca04b62005-12-30 23:50:15 +0000177{
Benny Prijono85598d92006-01-07 18:44:25 +0000178 pj_bool_t msg_log_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000179 pj_status_t status;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000180 pj_str_t target, from, to, contact, call_id, body;
181 pjsip_method method;
182 pjsip_tx_data *tdata;
183 pj_time_val timeout;
184
Benny Prijono85598d92006-01-07 18:44:25 +0000185 PJ_LOG(3,(THIS_FILE, " single message round-trip test..."));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000186
187 /* Register out test module to receive the message (if necessary). */
188 if (my_module.id == -1) {
189 status = pjsip_endpt_register_module( endpt, &my_module );
190 if (status != PJ_SUCCESS) {
191 app_perror(" error: unable to register module", status);
192 return -500;
193 }
194 }
195
Benny Prijono85598d92006-01-07 18:44:25 +0000196 /* Disable message logging. */
197 msg_log_enabled = msg_logger_set_enabled(0);
198
Benny Prijono0ca04b62005-12-30 23:50:15 +0000199 /* Create a request message. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000200 target = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000201 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000202 to = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000203 contact = pj_str(CONTACT_HDR);
204 call_id = pj_str(CALL_ID_HDR);
205 body = pj_str(BODY);
206
207 pjsip_method_set(&method, PJSIP_OPTIONS_METHOD);
208 status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to,
209 &contact, &call_id, CSEQ_VALUE,
210 &body, &tdata );
211 if (status != PJ_SUCCESS) {
212 app_perror(" error: unable to create request", status);
213 return -510;
214 }
215
216 /* Reset statuses */
217 send_status = recv_status = NO_STATUS;
218
219 /* Start time. */
220 pj_get_timestamp(&my_send_time);
221
222 /* Send the message (statelessly). */
223 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL,
224 &send_msg_callback);
225 if (status != PJ_SUCCESS) {
226 /* Immediate error! */
227 pjsip_tx_data_dec_ref(tdata);
228 send_status = status;
229 }
230
231 /* Set the timeout (1 second from now) */
232 pj_gettimeofday(&timeout);
233 timeout.sec += 1;
234
235 /* Loop handling events until we get status */
236 do {
237 pj_time_val now;
238 pj_time_val poll_interval = { 0, 10 };
239
240 pj_gettimeofday(&now);
241 if (PJ_TIME_VAL_GTE(now, timeout)) {
Benny Prijono85598d92006-01-07 18:44:25 +0000242 PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test"));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000243 status = -540;
244 goto on_return;
245 }
246
247 if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) {
248 app_perror(" error sending message", send_status);
249 status = -550;
250 goto on_return;
251 }
252
253 if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) {
254 app_perror(" error receiving message", recv_status);
255 status = -560;
256 goto on_return;
257 }
258
259 if (send_status!=NO_STATUS && recv_status!=NO_STATUS) {
260 /* Success! */
261 break;
262 }
263
264 pjsip_endpt_handle_events(endpt, &poll_interval);
265
266 } while (1);
267
268 if (status == PJ_SUCCESS) {
269 unsigned usec_rt;
270 usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time);
Benny Prijono85598d92006-01-07 18:44:25 +0000271 PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000272 }
273
Benny Prijono85598d92006-01-07 18:44:25 +0000274 /* Restore message logging. */
275 msg_logger_set_enabled(msg_log_enabled);
276
Benny Prijono0ca04b62005-12-30 23:50:15 +0000277 status = PJ_SUCCESS;
278
279on_return:
280 return status;
281}
282
283
284///////////////////////////////////////////////////////////////////////////////
285/*
286 * Multithreaded round-trip test
287 *
288 * This test will spawn multiple threads, each of them send a request. As soon
289 * as request is received, response will be sent, and time is recorded.
290 *
291 * The main purpose of this test is to ensure there's no crash when multiple
292 * threads are sending/receiving messages.
293 *
294 */
295static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata);
296static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata);
297
298static pjsip_module rt_module =
299{
300 NULL, NULL, /* prev and next */
301 { "Transport-RT-Test", 17}, /* Name. */
302 -1, /* Id */
303 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000304 NULL, /* load() */
305 NULL, /* start() */
306 NULL, /* stop() */
307 NULL, /* unload() */
308 &rt_on_rx_request, /* on_rx_request() */
309 &rt_on_rx_response, /* on_rx_response() */
310 NULL, /* tsx_handler() */
311};
312
313static struct
314{
315 pj_thread_t *thread;
316 pj_timestamp send_time;
317 pj_timestamp total_rt_time;
318 int sent_request_count, recv_response_count;
319 pj_str_t call_id;
Benny Prijono85598d92006-01-07 18:44:25 +0000320 pj_timer_entry timeout_timer;
321 pj_timer_entry tx_timer;
322 pj_mutex_t *mutex;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000323} rt_test_data[16];
324
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000325static char rt_target_uri[64];
Benny Prijono0ca04b62005-12-30 23:50:15 +0000326static pj_bool_t rt_stop;
327static pj_str_t rt_call_id;
328
329static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata)
330{
Benny Prijono728a9052006-01-18 23:34:15 +0000331 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
332 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/');
Benny Prijono0ca04b62005-12-30 23:50:15 +0000333 int thread_id = (*pos - '0');
334
335 pjsip_tx_data *tdata;
336 pjsip_response_addr res_addr;
337 pj_status_t status;
338
339 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
340 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000341 app_perror(" error creating response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000342 return PJ_TRUE;
343 }
344 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
345 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000346 app_perror(" error in get response address", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000347 pjsip_tx_data_dec_ref(tdata);
348 return PJ_TRUE;
349 }
350 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
351 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000352 app_perror(" error sending response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000353 pjsip_tx_data_dec_ref(tdata);
354 return PJ_TRUE;
355 }
356 return PJ_TRUE;
357
358 }
359 return PJ_FALSE;
360}
361
362static pj_status_t rt_send_request(int thread_id)
363{
364 pj_status_t status;
365 pj_str_t target, from, to, contact, call_id;
366 pjsip_tx_data *tdata;
Benny Prijono85598d92006-01-07 18:44:25 +0000367 pj_time_val timeout_delay;
368
369 pj_mutex_lock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000370
371 /* Create a request message. */
372 target = pj_str(rt_target_uri);
373 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000374 to = pj_str(rt_target_uri);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000375 contact = pj_str(CONTACT_HDR);
376 call_id = rt_test_data[thread_id].call_id;
377
378 status = pjsip_endpt_create_request( endpt, &pjsip_options_method,
379 &target, &from, &to,
380 &contact, &call_id, -1,
381 NULL, &tdata );
382 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +0000383 app_perror(" error: unable to create request", status);
384 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000385 return -610;
386 }
387
388 /* Start time. */
389 pj_get_timestamp(&rt_test_data[thread_id].send_time);
390
391 /* Send the message (statelessly). */
392 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL);
393 if (status != PJ_SUCCESS) {
394 /* Immediate error! */
Benny Prijono85598d92006-01-07 18:44:25 +0000395 app_perror(" error: send request", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000396 pjsip_tx_data_dec_ref(tdata);
Benny Prijono85598d92006-01-07 18:44:25 +0000397 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000398 return -620;
399 }
400
401 /* Update counter. */
402 rt_test_data[thread_id].sent_request_count++;
403
Benny Prijono85598d92006-01-07 18:44:25 +0000404 /* Set timeout timer. */
405 if (rt_test_data[thread_id].timeout_timer.user_data != NULL) {
406 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
407 }
408 timeout_delay.sec = 100; timeout_delay.msec = 0;
409 rt_test_data[thread_id].timeout_timer.user_data = (void*)1;
410 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer,
411 &timeout_delay);
412
413 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000414 return PJ_SUCCESS;
415}
416
417static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata)
418{
Benny Prijono728a9052006-01-18 23:34:15 +0000419 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
420 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000421 int thread_id = (*pos - '0');
422 pj_timestamp recv_time;
423
Benny Prijono85598d92006-01-07 18:44:25 +0000424 pj_mutex_lock(rt_test_data[thread_id].mutex);
425
426 /* Stop timer. */
427 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
428
Benny Prijono0ca04b62005-12-30 23:50:15 +0000429 /* Update counter and end-time. */
430 rt_test_data[thread_id].recv_response_count++;
431 pj_get_timestamp(&recv_time);
432
433 pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time);
434 pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time);
435
Benny Prijono85598d92006-01-07 18:44:25 +0000436 if (!rt_stop) {
437 pj_time_val tx_delay = { 0, 0 };
438 pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL);
439 rt_test_data[thread_id].tx_timer.user_data = (void*)1;
440 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer,
441 &tx_delay);
442 }
443
444 pj_mutex_unlock(rt_test_data[thread_id].mutex);
445
Benny Prijono0ca04b62005-12-30 23:50:15 +0000446 return PJ_TRUE;
447 }
448 return PJ_FALSE;
449}
450
Benny Prijono85598d92006-01-07 18:44:25 +0000451static void rt_timeout_timer( pj_timer_heap_t *timer_heap,
452 struct pj_timer_entry *entry )
453{
454 pj_mutex_lock(rt_test_data[entry->id].mutex);
455
456 PJ_UNUSED_ARG(timer_heap);
457 PJ_LOG(3,(THIS_FILE, " timeout waiting for response"));
458 rt_test_data[entry->id].timeout_timer.user_data = NULL;
459
460 if (rt_test_data[entry->id].tx_timer.user_data == NULL) {
461 pj_time_val delay = { 0, 0 };
462 rt_test_data[entry->id].tx_timer.user_data = (void*)1;
463 pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer,
464 &delay);
465 }
466
467 pj_mutex_unlock(rt_test_data[entry->id].mutex);
468}
469
470static void rt_tx_timer( pj_timer_heap_t *timer_heap,
471 struct pj_timer_entry *entry )
472{
473 pj_mutex_lock(rt_test_data[entry->id].mutex);
474
475 PJ_UNUSED_ARG(timer_heap);
476 pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL);
477 rt_test_data[entry->id].tx_timer.user_data = NULL;
478 rt_send_request(entry->id);
479
480 pj_mutex_unlock(rt_test_data[entry->id].mutex);
481}
482
483
484static int rt_worker_thread(void *arg)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000485{
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000486 int i, thread_id = (int)arg;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000487 pj_time_val poll_delay = { 0, 10 };
488
489 /* Sleep to allow main threads to run. */
490 pj_thread_sleep(10);
491
Benny Prijono0ca04b62005-12-30 23:50:15 +0000492 while (!rt_stop) {
493 pjsip_endpt_handle_events(endpt, &poll_delay);
494 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000495
496 /* Exhaust responses. */
497 for (i=0; i<100; ++i)
498 pjsip_endpt_handle_events(endpt, &poll_delay);
499
Benny Prijono0ca04b62005-12-30 23:50:15 +0000500 return 0;
501}
502
503int transport_rt_test( pjsip_transport_type_e tp_type,
504 pjsip_transport *ref_tp,
Benny Prijono85598d92006-01-07 18:44:25 +0000505 char *target_url,
506 int *lost)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000507{
508 enum { THREADS = 4, INTERVAL = 10 };
509 int i;
510 pj_status_t status;
511 pj_pool_t *pool;
Benny Prijono85598d92006-01-07 18:44:25 +0000512 pj_bool_t logger_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000513
514 pj_timestamp zero_time, total_time;
515 unsigned usec_rt;
516 unsigned total_sent;
517 unsigned total_recv;
518
519
Benny Prijono85598d92006-01-07 18:44:25 +0000520 PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...",
Benny Prijono0ca04b62005-12-30 23:50:15 +0000521 THREADS));
Benny Prijono85598d92006-01-07 18:44:25 +0000522 PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..",
523 INTERVAL));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000524
Benny Prijono85598d92006-01-07 18:44:25 +0000525 /* Make sure msg logger is disabled. */
526 logger_enabled = msg_logger_set_enabled(0);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000527
528 /* Register module (if not yet registered) */
529 if (rt_module.id == -1) {
530 status = pjsip_endpt_register_module( endpt, &rt_module );
531 if (status != PJ_SUCCESS) {
532 app_perror(" error: unable to register module", status);
533 return -600;
534 }
535 }
536
537 /* Create pool for this test. */
538 pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
539 if (!pool)
540 return -610;
541
542 /* Initialize static test data. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000543 pj_native_strcpy(rt_target_uri, target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000544 rt_call_id = pj_str("RT-Call-Id/");
545 rt_stop = PJ_FALSE;
546
547 /* Initialize thread data. */
548 for (i=0; i<THREADS; ++i) {
549 char buf[1];
550 pj_str_t str_id = { buf, 1 };
551
552 pj_memset(&rt_test_data[i], 0, sizeof(rt_test_data[i]));
553
Benny Prijono85598d92006-01-07 18:44:25 +0000554 /* Init timer entry */
555 rt_test_data[i].tx_timer.id = i;
556 rt_test_data[i].tx_timer.cb = &rt_tx_timer;
557 rt_test_data[i].timeout_timer.id = i;
558 rt_test_data[i].timeout_timer.cb = &rt_timeout_timer;
559
Benny Prijono0ca04b62005-12-30 23:50:15 +0000560 /* Generate Call-ID for each thread. */
561 rt_test_data[i].call_id.ptr = pj_pool_alloc(pool, rt_call_id.slen+1);
562 pj_strcpy(&rt_test_data[i].call_id, &rt_call_id);
563 buf[0] = '0' + i;
564 pj_strcat(&rt_test_data[i].call_id, &str_id);
565
Benny Prijono85598d92006-01-07 18:44:25 +0000566 /* Init mutex. */
567 status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex);
568 if (status != PJ_SUCCESS) {
569 app_perror(" error: unable to create mutex", status);
570 return -615;
571 }
572
Benny Prijono0ca04b62005-12-30 23:50:15 +0000573 /* Create thread, suspended. */
Benny Prijono85598d92006-01-07 18:44:25 +0000574 status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)i, 0,
Benny Prijono0ca04b62005-12-30 23:50:15 +0000575 PJ_THREAD_SUSPENDED, &rt_test_data[i].thread);
576 if (status != PJ_SUCCESS) {
577 app_perror(" error: unable to create thread", status);
578 return -620;
579 }
580 }
581
582 /* Start threads! */
583 for (i=0; i<THREADS; ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +0000584 pj_time_val delay = {0,0};
Benny Prijono0ca04b62005-12-30 23:50:15 +0000585 pj_thread_resume(rt_test_data[i].thread);
Benny Prijono85598d92006-01-07 18:44:25 +0000586
587 /* Schedule first message transmissions. */
588 rt_test_data[i].tx_timer.user_data = (void*)1;
589 pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000590 }
591
592 /* Sleep for some time. */
593 pj_thread_sleep(INTERVAL * 1000);
594
595 /* Signal thread to stop. */
596 rt_stop = PJ_TRUE;
597
598 /* Wait threads to complete. */
599 for (i=0; i<THREADS; ++i) {
600 pj_thread_join(rt_test_data[i].thread);
601 pj_thread_destroy(rt_test_data[i].thread);
602 }
603
Benny Prijono85598d92006-01-07 18:44:25 +0000604 /* Destroy rt_test_data */
605 for (i=0; i<THREADS; ++i) {
606 pj_mutex_destroy(rt_test_data[i].mutex);
607 pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer);
608 }
609
Benny Prijono0ca04b62005-12-30 23:50:15 +0000610 /* Gather statistics. */
611 pj_memset(&total_time, 0, sizeof(total_time));
612 pj_memset(&zero_time, 0, sizeof(zero_time));
613 usec_rt = total_sent = total_recv = 0;
614 for (i=0; i<THREADS; ++i) {
615 total_sent += rt_test_data[i].sent_request_count;
616 total_recv += rt_test_data[i].recv_response_count;
617 pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time);
618 }
619
620 /* Display statistics. */
621 if (total_recv)
622 total_time.u64 = total_time.u64/total_recv;
623 else
624 total_time.u64 = 0;
625 usec_rt = pj_elapsed_usec(&zero_time, &total_time);
Benny Prijono85598d92006-01-07 18:44:25 +0000626 PJ_LOG(3,(THIS_FILE, " done."));
627 PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent));
628 PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000629
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000630 pjsip_endpt_release_pool(endpt, pool);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000631
Benny Prijono85598d92006-01-07 18:44:25 +0000632 *lost = total_sent-total_recv;
633
634 /* Flush events. */
635 flush_events(500);
636
637 /* Restore msg logger. */
638 msg_logger_set_enabled(logger_enabled);
639
Benny Prijono0ca04b62005-12-30 23:50:15 +0000640 return 0;
641}