blob: 9e0ac69e1448d6bab835dc0f4ece339071f68092 [file] [log] [blame]
Benny Prijono0ca04b62005-12-30 23:50:15 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono0ca04b62005-12-30 23:50:15 +00004 *
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)) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000338 pjsip_tx_data *tdata;
339 pjsip_response_addr res_addr;
340 pj_status_t status;
341
342 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
343 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000344 app_perror(" error creating response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000345 return PJ_TRUE;
346 }
347 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
348 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000349 app_perror(" error in get response address", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000350 pjsip_tx_data_dec_ref(tdata);
351 return PJ_TRUE;
352 }
353 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
354 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000355 app_perror(" error sending response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000356 pjsip_tx_data_dec_ref(tdata);
357 return PJ_TRUE;
358 }
359 return PJ_TRUE;
360
361 }
362 return PJ_FALSE;
363}
364
365static pj_status_t rt_send_request(int thread_id)
366{
367 pj_status_t status;
368 pj_str_t target, from, to, contact, call_id;
369 pjsip_tx_data *tdata;
Benny Prijono85598d92006-01-07 18:44:25 +0000370 pj_time_val timeout_delay;
371
372 pj_mutex_lock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000373
374 /* Create a request message. */
375 target = pj_str(rt_target_uri);
376 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000377 to = pj_str(rt_target_uri);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000378 contact = pj_str(CONTACT_HDR);
379 call_id = rt_test_data[thread_id].call_id;
380
381 status = pjsip_endpt_create_request( endpt, &pjsip_options_method,
382 &target, &from, &to,
383 &contact, &call_id, -1,
384 NULL, &tdata );
385 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +0000386 app_perror(" error: unable to create request", status);
387 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000388 return -610;
389 }
390
391 /* Start time. */
392 pj_get_timestamp(&rt_test_data[thread_id].send_time);
393
394 /* Send the message (statelessly). */
395 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL);
396 if (status != PJ_SUCCESS) {
397 /* Immediate error! */
Benny Prijono85598d92006-01-07 18:44:25 +0000398 app_perror(" error: send request", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000399 pjsip_tx_data_dec_ref(tdata);
Benny Prijono85598d92006-01-07 18:44:25 +0000400 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000401 return -620;
402 }
403
404 /* Update counter. */
405 rt_test_data[thread_id].sent_request_count++;
406
Benny Prijono85598d92006-01-07 18:44:25 +0000407 /* Set timeout timer. */
408 if (rt_test_data[thread_id].timeout_timer.user_data != NULL) {
409 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
410 }
411 timeout_delay.sec = 100; timeout_delay.msec = 0;
412 rt_test_data[thread_id].timeout_timer.user_data = (void*)1;
413 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer,
414 &timeout_delay);
415
416 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000417 return PJ_SUCCESS;
418}
419
420static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata)
421{
Benny Prijono728a9052006-01-18 23:34:15 +0000422 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
423 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000424 int thread_id = (*pos - '0');
425 pj_timestamp recv_time;
426
Benny Prijono85598d92006-01-07 18:44:25 +0000427 pj_mutex_lock(rt_test_data[thread_id].mutex);
428
429 /* Stop timer. */
430 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
431
Benny Prijono0ca04b62005-12-30 23:50:15 +0000432 /* Update counter and end-time. */
433 rt_test_data[thread_id].recv_response_count++;
434 pj_get_timestamp(&recv_time);
435
436 pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time);
437 pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time);
438
Benny Prijono85598d92006-01-07 18:44:25 +0000439 if (!rt_stop) {
440 pj_time_val tx_delay = { 0, 0 };
441 pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL);
442 rt_test_data[thread_id].tx_timer.user_data = (void*)1;
443 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer,
444 &tx_delay);
445 }
446
447 pj_mutex_unlock(rt_test_data[thread_id].mutex);
448
Benny Prijono0ca04b62005-12-30 23:50:15 +0000449 return PJ_TRUE;
450 }
451 return PJ_FALSE;
452}
453
Benny Prijono85598d92006-01-07 18:44:25 +0000454static void rt_timeout_timer( pj_timer_heap_t *timer_heap,
455 struct pj_timer_entry *entry )
456{
457 pj_mutex_lock(rt_test_data[entry->id].mutex);
458
459 PJ_UNUSED_ARG(timer_heap);
460 PJ_LOG(3,(THIS_FILE, " timeout waiting for response"));
461 rt_test_data[entry->id].timeout_timer.user_data = NULL;
462
463 if (rt_test_data[entry->id].tx_timer.user_data == NULL) {
464 pj_time_val delay = { 0, 0 };
465 rt_test_data[entry->id].tx_timer.user_data = (void*)1;
466 pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer,
467 &delay);
468 }
469
470 pj_mutex_unlock(rt_test_data[entry->id].mutex);
471}
472
473static void rt_tx_timer( pj_timer_heap_t *timer_heap,
474 struct pj_timer_entry *entry )
475{
476 pj_mutex_lock(rt_test_data[entry->id].mutex);
477
478 PJ_UNUSED_ARG(timer_heap);
479 pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL);
480 rt_test_data[entry->id].tx_timer.user_data = NULL;
481 rt_send_request(entry->id);
482
483 pj_mutex_unlock(rt_test_data[entry->id].mutex);
484}
485
486
487static int rt_worker_thread(void *arg)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000488{
Benny Prijonobc331ca2006-09-19 13:32:05 +0000489 int i;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000490 pj_time_val poll_delay = { 0, 10 };
491
492 /* Sleep to allow main threads to run. */
493 pj_thread_sleep(10);
494
Benny Prijono0ca04b62005-12-30 23:50:15 +0000495 while (!rt_stop) {
496 pjsip_endpt_handle_events(endpt, &poll_delay);
497 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000498
499 /* Exhaust responses. */
500 for (i=0; i<100; ++i)
501 pjsip_endpt_handle_events(endpt, &poll_delay);
502
Benny Prijono0ca04b62005-12-30 23:50:15 +0000503 return 0;
504}
505
506int transport_rt_test( pjsip_transport_type_e tp_type,
507 pjsip_transport *ref_tp,
Benny Prijono85598d92006-01-07 18:44:25 +0000508 char *target_url,
509 int *lost)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000510{
511 enum { THREADS = 4, INTERVAL = 10 };
512 int i;
513 pj_status_t status;
514 pj_pool_t *pool;
Benny Prijono85598d92006-01-07 18:44:25 +0000515 pj_bool_t logger_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000516
517 pj_timestamp zero_time, total_time;
518 unsigned usec_rt;
519 unsigned total_sent;
520 unsigned total_recv;
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. */
Nanang Izzuddin7d1ac292008-09-16 17:02:48 +0000545 pj_ansi_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
Benny Prijonoac623b32006-07-03 15:19:31 +0000554 pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i]));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000555
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. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000563 rt_test_data[i].call_id.ptr = (char*) pj_pool_alloc(pool, rt_call_id.slen+1);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000564 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 Prijono7db431e2006-07-23 14:38:49 +0000576 status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)(long)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. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000613 pj_bzero(&total_time, sizeof(total_time));
614 pj_bzero(&zero_time, sizeof(zero_time));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000615 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}
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000644
645///////////////////////////////////////////////////////////////////////////////
646/*
647 * Transport load testing
648 */
649static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata);
650
651static struct mod_load_test
652{
653 pjsip_module mod;
Benny Prijono3c97d9b2008-09-21 22:01:46 +0000654 pj_int32_t next_seq;
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000655 pj_bool_t err;
656} mod_load =
657{
658 {
659 NULL, NULL, /* prev and next */
660 { "mod-load-test", 13}, /* Name. */
661 -1, /* Id */
662 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
663 NULL, /* load() */
664 NULL, /* start() */
665 NULL, /* stop() */
666 NULL, /* unload() */
667 &load_on_rx_request, /* on_rx_request() */
668 NULL, /* on_rx_response() */
669 NULL, /* tsx_handler() */
670 }
671};
672
673
674static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata)
675{
676 if (rdata->msg_info.cseq->cseq != mod_load.next_seq) {
677 PJ_LOG(1,("THIS_FILE", " err: expecting cseq %u, got %u",
678 mod_load.next_seq, rdata->msg_info.cseq->cseq));
679 mod_load.err = PJ_TRUE;
680 mod_load.next_seq = rdata->msg_info.cseq->cseq + 1;
681 } else
682 mod_load.next_seq++;
683 return PJ_TRUE;
684}
685
686int transport_load_test(char *target_url)
687{
688 enum { COUNT = 2000 };
689 unsigned i;
690 pj_status_t status;
691
692 /* exhaust packets */
693 do {
694 pj_time_val delay = {1, 0};
695 i = 0;
696 pjsip_endpt_handle_events2(endpt, &delay, &i);
697 } while (i != 0);
698
699 PJ_LOG(3,(THIS_FILE, " transport load test..."));
700
701 if (mod_load.mod.id == -1) {
702 status = pjsip_endpt_register_module( endpt, &mod_load.mod);
703 if (status != PJ_SUCCESS) {
704 app_perror("error registering module", status);
705 return -1;
706 }
707 }
708 mod_load.err = PJ_FALSE;
709 mod_load.next_seq = 0;
710
711 for (i=0; i<COUNT && !mod_load.err; ++i) {
712 pj_str_t target, from, call_id;
713 pjsip_tx_data *tdata;
714
715 target = pj_str(target_url);
716 from = pj_str("<sip:user@host>");
717 call_id = pj_str("thecallid");
718 status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
719 &target, &from,
720 &target, &from, &call_id,
721 i, NULL, &tdata );
722 if (status != PJ_SUCCESS) {
723 app_perror("error creating request", status);
724 goto on_return;
725 }
726
727 status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL);
728 if (status != PJ_SUCCESS) {
729 app_perror("error sending request", status);
730 goto on_return;
731 }
732 }
733
734 do {
735 pj_time_val delay = {1, 0};
736 i = 0;
737 pjsip_endpt_handle_events2(endpt, &delay, &i);
738 } while (i != 0);
739
740 if (mod_load.next_seq != COUNT) {
741 PJ_LOG(1,("THIS_FILE", " err: expecting %u msg, got only %u",
742 COUNT, mod_load.next_seq));
743 status = -2;
744 goto on_return;
745 }
746
747on_return:
748 if (mod_load.mod.id != -1) {
749 pjsip_endpt_unregister_module( endpt, &mod_load.mod);
750 mod_load.mod.id = -1;
751 }
752 if (status != PJ_SUCCESS || mod_load.err) {
753 return -2;
754 }
755 PJ_LOG(3,(THIS_FILE, " success"));
756 return 0;
757}
758
759