blob: a17dca82fdb879ecfe5d5037d135f8a5b5e0698e [file] [log] [blame]
Benny Prijono0ca04b62005-12-30 23:50:15 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono0ca04b62005-12-30 23:50:15 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "test.h"
Benny Prijono40f2f642006-01-30 18:40:05 +000022#include <pjsip.h>
Benny Prijono0ca04b62005-12-30 23:50:15 +000023#include <pjlib.h>
24
Benny Prijono85598d92006-01-07 18:44:25 +000025#define THIS_FILE "transport_test.c"
26
Benny Prijono0ca04b62005-12-30 23:50:15 +000027///////////////////////////////////////////////////////////////////////////////
28/*
29 * Generic testing for transport, to make sure that basic
30 * attributes have been initialized properly.
31 */
32int generic_transport_test(pjsip_transport *tp)
33{
Benny Prijono85598d92006-01-07 18:44:25 +000034 PJ_LOG(3,(THIS_FILE, " structure test..."));
Benny Prijono0ca04b62005-12-30 23:50:15 +000035
36 /* Check that local address name is valid. */
37 {
38 struct pj_in_addr addr;
39
40 /* Note: inet_aton() returns non-zero if addr is valid! */
41 if (pj_inet_aton(&tp->local_name.host, &addr) != 0) {
42 if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) {
Benny Prijono85598d92006-01-07 18:44:25 +000043 PJ_LOG(3,(THIS_FILE, " Error: invalid address name"));
Benny Prijono0ca04b62005-12-30 23:50:15 +000044 return -420;
45 }
46 } else {
47 /* It's okay. local_name.host may be a hostname instead of
48 * IP address.
49 */
50 }
51 }
52
53 /* Check that port is valid. */
54 if (tp->local_name.port <= 0) {
55 return -430;
56 }
57
58 /* Check length of address (for now we only check against sockaddr_in). */
59 if (tp->addr_len != sizeof(pj_sockaddr_in))
60 return -440;
61
62 /* Check type. */
63 if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED)
64 return -450;
65
66 /* That's it. */
67 return PJ_SUCCESS;
68}
69
70///////////////////////////////////////////////////////////////////////////////
71/*
72 * Send/receive test.
73 *
74 * This test sends a request to loopback address; as soon as request is
75 * received, response will be sent, and time is recorded.
76 *
77 * The main purpose is to test that the basic transport functionalities works,
78 * before we continue with more complicated tests.
79 */
80#define FROM_HDR "Bob <sip:bob@example.com>"
Benny Prijono0ca04b62005-12-30 23:50:15 +000081#define CONTACT_HDR "Bob <sip:bob@127.0.0.1>"
82#define CALL_ID_HDR "SendRecv-Test"
83#define CSEQ_VALUE 100
84#define BODY "Hello World!"
85
86static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata);
87static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata);
88
89/* Flag to indicate message has been received
90 * (or failed to send)
91 */
92#define NO_STATUS -2
93static int send_status = NO_STATUS;
94static int recv_status = NO_STATUS;
95static pj_timestamp my_send_time, my_recv_time;
96
97/* Module to receive messages for this test. */
98static pjsip_module my_module =
99{
100 NULL, NULL, /* prev and next */
101 { "Transport-Test", 14}, /* Name. */
102 -1, /* Id */
103 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000104 NULL, /* load() */
105 NULL, /* start() */
106 NULL, /* stop() */
107 NULL, /* unload() */
108 &my_on_rx_request, /* on_rx_request() */
109 &my_on_rx_response, /* on_rx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000110 NULL, /* on_tsx_state() */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000111};
112
113
114static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata)
115{
116 /* Check that this is our request. */
Benny Prijono728a9052006-01-18 23:34:15 +0000117 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000118 /* It is! */
119 /* Send response. */
120 pjsip_tx_data *tdata;
121 pjsip_response_addr res_addr;
122 pj_status_t status;
123
Benny Prijono0ca04b62005-12-30 23:50:15 +0000124 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
125 if (status != PJ_SUCCESS) {
126 recv_status = status;
127 return PJ_TRUE;
128 }
129 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
130 if (status != PJ_SUCCESS) {
131 recv_status = status;
132 pjsip_tx_data_dec_ref(tdata);
133 return PJ_TRUE;
134 }
135 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
136 if (status != PJ_SUCCESS) {
137 recv_status = status;
138 pjsip_tx_data_dec_ref(tdata);
139 return PJ_TRUE;
140 }
141 return PJ_TRUE;
142 }
143
144 /* Not ours. */
145 return PJ_FALSE;
146}
147
148static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata)
149{
Benny Prijono728a9052006-01-18 23:34:15 +0000150 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000151 pj_get_timestamp(&my_recv_time);
152 recv_status = PJ_SUCCESS;
153 return PJ_TRUE;
154 }
155 return PJ_FALSE;
156}
157
158/* Transport callback. */
159static void send_msg_callback(pjsip_send_state *stateless_data,
160 pj_ssize_t sent, pj_bool_t *cont)
161{
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000162 PJ_UNUSED_ARG(stateless_data);
163
Benny Prijono0ca04b62005-12-30 23:50:15 +0000164 if (sent < 1) {
165 /* Obtain the error code. */
166 send_status = -sent;
167 } else {
168 send_status = PJ_SUCCESS;
169 }
170
171 /* Don't want to continue. */
172 *cont = PJ_FALSE;
173}
174
175
176/* Test that we receive loopback message. */
177int transport_send_recv_test( pjsip_transport_type_e tp_type,
178 pjsip_transport *ref_tp,
Benny Prijonoe93e2872006-06-28 16:46:49 +0000179 char *target_url,
180 int *p_usec_rtt)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000181{
Benny Prijono85598d92006-01-07 18:44:25 +0000182 pj_bool_t msg_log_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000183 pj_status_t status;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000184 pj_str_t target, from, to, contact, call_id, body;
185 pjsip_method method;
186 pjsip_tx_data *tdata;
187 pj_time_val timeout;
188
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000189 PJ_UNUSED_ARG(tp_type);
190 PJ_UNUSED_ARG(ref_tp);
191
Benny Prijono85598d92006-01-07 18:44:25 +0000192 PJ_LOG(3,(THIS_FILE, " single message round-trip test..."));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000193
194 /* Register out test module to receive the message (if necessary). */
195 if (my_module.id == -1) {
196 status = pjsip_endpt_register_module( endpt, &my_module );
197 if (status != PJ_SUCCESS) {
198 app_perror(" error: unable to register module", status);
199 return -500;
200 }
201 }
202
Benny Prijono85598d92006-01-07 18:44:25 +0000203 /* Disable message logging. */
204 msg_log_enabled = msg_logger_set_enabled(0);
205
Benny Prijono0ca04b62005-12-30 23:50:15 +0000206 /* Create a request message. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000207 target = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000208 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000209 to = pj_str(target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000210 contact = pj_str(CONTACT_HDR);
211 call_id = pj_str(CALL_ID_HDR);
212 body = pj_str(BODY);
213
214 pjsip_method_set(&method, PJSIP_OPTIONS_METHOD);
215 status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to,
216 &contact, &call_id, CSEQ_VALUE,
217 &body, &tdata );
218 if (status != PJ_SUCCESS) {
219 app_perror(" error: unable to create request", status);
220 return -510;
221 }
222
223 /* Reset statuses */
224 send_status = recv_status = NO_STATUS;
225
226 /* Start time. */
227 pj_get_timestamp(&my_send_time);
228
229 /* Send the message (statelessly). */
Benny Prijonoe93e2872006-06-28 16:46:49 +0000230 PJ_LOG(5,(THIS_FILE, "Sending request to %.*s",
231 (int)target.slen, target.ptr));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000232 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL,
233 &send_msg_callback);
234 if (status != PJ_SUCCESS) {
235 /* Immediate error! */
236 pjsip_tx_data_dec_ref(tdata);
237 send_status = status;
238 }
239
Benny Prijonoe93e2872006-06-28 16:46:49 +0000240 /* Set the timeout (2 seconds from now) */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000241 pj_gettimeofday(&timeout);
Benny Prijonoe93e2872006-06-28 16:46:49 +0000242 timeout.sec += 2;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000243
244 /* Loop handling events until we get status */
245 do {
246 pj_time_val now;
247 pj_time_val poll_interval = { 0, 10 };
248
249 pj_gettimeofday(&now);
250 if (PJ_TIME_VAL_GTE(now, timeout)) {
Benny Prijono85598d92006-01-07 18:44:25 +0000251 PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test"));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000252 status = -540;
253 goto on_return;
254 }
255
256 if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) {
257 app_perror(" error sending message", send_status);
258 status = -550;
259 goto on_return;
260 }
261
262 if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) {
263 app_perror(" error receiving message", recv_status);
264 status = -560;
265 goto on_return;
266 }
267
268 if (send_status!=NO_STATUS && recv_status!=NO_STATUS) {
269 /* Success! */
270 break;
271 }
272
273 pjsip_endpt_handle_events(endpt, &poll_interval);
274
275 } while (1);
276
277 if (status == PJ_SUCCESS) {
278 unsigned usec_rt;
279 usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time);
Benny Prijonoe93e2872006-06-28 16:46:49 +0000280
Benny Prijono85598d92006-01-07 18:44:25 +0000281 PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt));
Benny Prijonoe93e2872006-06-28 16:46:49 +0000282
283 *p_usec_rtt = usec_rt;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000284 }
285
Benny Prijono85598d92006-01-07 18:44:25 +0000286 /* Restore message logging. */
287 msg_logger_set_enabled(msg_log_enabled);
288
Benny Prijono0ca04b62005-12-30 23:50:15 +0000289 status = PJ_SUCCESS;
290
291on_return:
292 return status;
293}
294
295
296///////////////////////////////////////////////////////////////////////////////
297/*
298 * Multithreaded round-trip test
299 *
300 * This test will spawn multiple threads, each of them send a request. As soon
301 * as request is received, response will be sent, and time is recorded.
302 *
303 * The main purpose of this test is to ensure there's no crash when multiple
304 * threads are sending/receiving messages.
305 *
306 */
307static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata);
308static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata);
309
310static pjsip_module rt_module =
311{
312 NULL, NULL, /* prev and next */
313 { "Transport-RT-Test", 17}, /* Name. */
314 -1, /* Id */
315 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
Benny Prijono0ca04b62005-12-30 23:50:15 +0000316 NULL, /* load() */
317 NULL, /* start() */
318 NULL, /* stop() */
319 NULL, /* unload() */
320 &rt_on_rx_request, /* on_rx_request() */
321 &rt_on_rx_response, /* on_rx_response() */
322 NULL, /* tsx_handler() */
323};
324
325static struct
326{
327 pj_thread_t *thread;
328 pj_timestamp send_time;
329 pj_timestamp total_rt_time;
330 int sent_request_count, recv_response_count;
331 pj_str_t call_id;
Benny Prijono85598d92006-01-07 18:44:25 +0000332 pj_timer_entry timeout_timer;
333 pj_timer_entry tx_timer;
334 pj_mutex_t *mutex;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000335} rt_test_data[16];
336
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000337static char rt_target_uri[64];
Benny Prijono0ca04b62005-12-30 23:50:15 +0000338static pj_bool_t rt_stop;
339static pj_str_t rt_call_id;
340
341static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata)
342{
Benny Prijono728a9052006-01-18 23:34:15 +0000343 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
Benny Prijono0ca04b62005-12-30 23:50:15 +0000344 pjsip_tx_data *tdata;
345 pjsip_response_addr res_addr;
346 pj_status_t status;
347
348 status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata);
349 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000350 app_perror(" error creating response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000351 return PJ_TRUE;
352 }
353 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
354 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000355 app_perror(" error in get response address", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000356 pjsip_tx_data_dec_ref(tdata);
357 return PJ_TRUE;
358 }
359 status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL);
360 if (status != PJ_SUCCESS) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000361 app_perror(" error sending response", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000362 pjsip_tx_data_dec_ref(tdata);
363 return PJ_TRUE;
364 }
365 return PJ_TRUE;
366
367 }
368 return PJ_FALSE;
369}
370
371static pj_status_t rt_send_request(int thread_id)
372{
373 pj_status_t status;
374 pj_str_t target, from, to, contact, call_id;
375 pjsip_tx_data *tdata;
Benny Prijono85598d92006-01-07 18:44:25 +0000376 pj_time_val timeout_delay;
377
378 pj_mutex_lock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000379
380 /* Create a request message. */
381 target = pj_str(rt_target_uri);
382 from = pj_str(FROM_HDR);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000383 to = pj_str(rt_target_uri);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000384 contact = pj_str(CONTACT_HDR);
385 call_id = rt_test_data[thread_id].call_id;
386
387 status = pjsip_endpt_create_request( endpt, &pjsip_options_method,
388 &target, &from, &to,
389 &contact, &call_id, -1,
390 NULL, &tdata );
391 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +0000392 app_perror(" error: unable to create request", status);
393 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000394 return -610;
395 }
396
397 /* Start time. */
398 pj_get_timestamp(&rt_test_data[thread_id].send_time);
399
400 /* Send the message (statelessly). */
401 status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL);
402 if (status != PJ_SUCCESS) {
403 /* Immediate error! */
Benny Prijono85598d92006-01-07 18:44:25 +0000404 app_perror(" error: send request", status);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000405 pjsip_tx_data_dec_ref(tdata);
Benny Prijono85598d92006-01-07 18:44:25 +0000406 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000407 return -620;
408 }
409
410 /* Update counter. */
411 rt_test_data[thread_id].sent_request_count++;
412
Benny Prijono85598d92006-01-07 18:44:25 +0000413 /* Set timeout timer. */
414 if (rt_test_data[thread_id].timeout_timer.user_data != NULL) {
415 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
416 }
417 timeout_delay.sec = 100; timeout_delay.msec = 0;
418 rt_test_data[thread_id].timeout_timer.user_data = (void*)1;
419 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer,
420 &timeout_delay);
421
422 pj_mutex_unlock(rt_test_data[thread_id].mutex);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000423 return PJ_SUCCESS;
424}
425
426static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata)
427{
Benny Prijono728a9052006-01-18 23:34:15 +0000428 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
429 char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000430 int thread_id = (*pos - '0');
431 pj_timestamp recv_time;
432
Benny Prijono85598d92006-01-07 18:44:25 +0000433 pj_mutex_lock(rt_test_data[thread_id].mutex);
434
435 /* Stop timer. */
436 pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer);
437
Benny Prijono0ca04b62005-12-30 23:50:15 +0000438 /* Update counter and end-time. */
439 rt_test_data[thread_id].recv_response_count++;
440 pj_get_timestamp(&recv_time);
441
442 pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time);
443 pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time);
444
Benny Prijono85598d92006-01-07 18:44:25 +0000445 if (!rt_stop) {
446 pj_time_val tx_delay = { 0, 0 };
447 pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL);
448 rt_test_data[thread_id].tx_timer.user_data = (void*)1;
449 pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer,
450 &tx_delay);
451 }
452
453 pj_mutex_unlock(rt_test_data[thread_id].mutex);
454
Benny Prijono0ca04b62005-12-30 23:50:15 +0000455 return PJ_TRUE;
456 }
457 return PJ_FALSE;
458}
459
Benny Prijono85598d92006-01-07 18:44:25 +0000460static void rt_timeout_timer( pj_timer_heap_t *timer_heap,
461 struct pj_timer_entry *entry )
462{
463 pj_mutex_lock(rt_test_data[entry->id].mutex);
464
465 PJ_UNUSED_ARG(timer_heap);
466 PJ_LOG(3,(THIS_FILE, " timeout waiting for response"));
467 rt_test_data[entry->id].timeout_timer.user_data = NULL;
468
469 if (rt_test_data[entry->id].tx_timer.user_data == NULL) {
470 pj_time_val delay = { 0, 0 };
471 rt_test_data[entry->id].tx_timer.user_data = (void*)1;
472 pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer,
473 &delay);
474 }
475
476 pj_mutex_unlock(rt_test_data[entry->id].mutex);
477}
478
479static void rt_tx_timer( pj_timer_heap_t *timer_heap,
480 struct pj_timer_entry *entry )
481{
482 pj_mutex_lock(rt_test_data[entry->id].mutex);
483
484 PJ_UNUSED_ARG(timer_heap);
485 pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL);
486 rt_test_data[entry->id].tx_timer.user_data = NULL;
487 rt_send_request(entry->id);
488
489 pj_mutex_unlock(rt_test_data[entry->id].mutex);
490}
491
492
493static int rt_worker_thread(void *arg)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000494{
Benny Prijonobc331ca2006-09-19 13:32:05 +0000495 int i;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000496 pj_time_val poll_delay = { 0, 10 };
497
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000498 PJ_UNUSED_ARG(arg);
499
Benny Prijono0ca04b62005-12-30 23:50:15 +0000500 /* Sleep to allow main threads to run. */
501 pj_thread_sleep(10);
502
Benny Prijono0ca04b62005-12-30 23:50:15 +0000503 while (!rt_stop) {
504 pjsip_endpt_handle_events(endpt, &poll_delay);
505 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000506
507 /* Exhaust responses. */
508 for (i=0; i<100; ++i)
509 pjsip_endpt_handle_events(endpt, &poll_delay);
510
Benny Prijono0ca04b62005-12-30 23:50:15 +0000511 return 0;
512}
513
514int transport_rt_test( pjsip_transport_type_e tp_type,
515 pjsip_transport *ref_tp,
Benny Prijono85598d92006-01-07 18:44:25 +0000516 char *target_url,
517 int *lost)
Benny Prijono0ca04b62005-12-30 23:50:15 +0000518{
519 enum { THREADS = 4, INTERVAL = 10 };
520 int i;
521 pj_status_t status;
522 pj_pool_t *pool;
Benny Prijono85598d92006-01-07 18:44:25 +0000523 pj_bool_t logger_enabled;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000524
525 pj_timestamp zero_time, total_time;
526 unsigned usec_rt;
527 unsigned total_sent;
528 unsigned total_recv;
529
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000530 PJ_UNUSED_ARG(tp_type);
531 PJ_UNUSED_ARG(ref_tp);
532
Benny Prijono85598d92006-01-07 18:44:25 +0000533 PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...",
Benny Prijono0ca04b62005-12-30 23:50:15 +0000534 THREADS));
Benny Prijono85598d92006-01-07 18:44:25 +0000535 PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..",
536 INTERVAL));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000537
Benny Prijono85598d92006-01-07 18:44:25 +0000538 /* Make sure msg logger is disabled. */
539 logger_enabled = msg_logger_set_enabled(0);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000540
541 /* Register module (if not yet registered) */
542 if (rt_module.id == -1) {
543 status = pjsip_endpt_register_module( endpt, &rt_module );
544 if (status != PJ_SUCCESS) {
545 app_perror(" error: unable to register module", status);
546 return -600;
547 }
548 }
549
550 /* Create pool for this test. */
551 pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
552 if (!pool)
553 return -610;
554
555 /* Initialize static test data. */
Nanang Izzuddin7d1ac292008-09-16 17:02:48 +0000556 pj_ansi_strcpy(rt_target_uri, target_url);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000557 rt_call_id = pj_str("RT-Call-Id/");
558 rt_stop = PJ_FALSE;
559
560 /* Initialize thread data. */
561 for (i=0; i<THREADS; ++i) {
562 char buf[1];
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000563 pj_str_t str_id;
564
565 pj_strset(&str_id, buf, 1);
Benny Prijonoac623b32006-07-03 15:19:31 +0000566 pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i]));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000567
Benny Prijono85598d92006-01-07 18:44:25 +0000568 /* Init timer entry */
569 rt_test_data[i].tx_timer.id = i;
570 rt_test_data[i].tx_timer.cb = &rt_tx_timer;
571 rt_test_data[i].timeout_timer.id = i;
572 rt_test_data[i].timeout_timer.cb = &rt_timeout_timer;
573
Benny Prijono0ca04b62005-12-30 23:50:15 +0000574 /* Generate Call-ID for each thread. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000575 rt_test_data[i].call_id.ptr = (char*) pj_pool_alloc(pool, rt_call_id.slen+1);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000576 pj_strcpy(&rt_test_data[i].call_id, &rt_call_id);
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000577 buf[0] = '0' + (char)i;
Benny Prijono0ca04b62005-12-30 23:50:15 +0000578 pj_strcat(&rt_test_data[i].call_id, &str_id);
579
Benny Prijono85598d92006-01-07 18:44:25 +0000580 /* Init mutex. */
581 status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex);
582 if (status != PJ_SUCCESS) {
583 app_perror(" error: unable to create mutex", status);
584 return -615;
585 }
586
Benny Prijono0ca04b62005-12-30 23:50:15 +0000587 /* Create thread, suspended. */
Benny Prijono7db431e2006-07-23 14:38:49 +0000588 status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)(long)i, 0,
Benny Prijono0ca04b62005-12-30 23:50:15 +0000589 PJ_THREAD_SUSPENDED, &rt_test_data[i].thread);
590 if (status != PJ_SUCCESS) {
591 app_perror(" error: unable to create thread", status);
592 return -620;
593 }
594 }
595
596 /* Start threads! */
597 for (i=0; i<THREADS; ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +0000598 pj_time_val delay = {0,0};
Benny Prijono0ca04b62005-12-30 23:50:15 +0000599 pj_thread_resume(rt_test_data[i].thread);
Benny Prijono85598d92006-01-07 18:44:25 +0000600
601 /* Schedule first message transmissions. */
602 rt_test_data[i].tx_timer.user_data = (void*)1;
603 pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000604 }
605
606 /* Sleep for some time. */
607 pj_thread_sleep(INTERVAL * 1000);
608
609 /* Signal thread to stop. */
610 rt_stop = PJ_TRUE;
611
612 /* Wait threads to complete. */
613 for (i=0; i<THREADS; ++i) {
614 pj_thread_join(rt_test_data[i].thread);
615 pj_thread_destroy(rt_test_data[i].thread);
616 }
617
Benny Prijono85598d92006-01-07 18:44:25 +0000618 /* Destroy rt_test_data */
619 for (i=0; i<THREADS; ++i) {
620 pj_mutex_destroy(rt_test_data[i].mutex);
621 pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer);
622 }
623
Benny Prijono0ca04b62005-12-30 23:50:15 +0000624 /* Gather statistics. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000625 pj_bzero(&total_time, sizeof(total_time));
626 pj_bzero(&zero_time, sizeof(zero_time));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000627 usec_rt = total_sent = total_recv = 0;
628 for (i=0; i<THREADS; ++i) {
629 total_sent += rt_test_data[i].sent_request_count;
630 total_recv += rt_test_data[i].recv_response_count;
631 pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time);
632 }
633
634 /* Display statistics. */
635 if (total_recv)
636 total_time.u64 = total_time.u64/total_recv;
637 else
638 total_time.u64 = 0;
639 usec_rt = pj_elapsed_usec(&zero_time, &total_time);
Benny Prijono85598d92006-01-07 18:44:25 +0000640 PJ_LOG(3,(THIS_FILE, " done."));
641 PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent));
642 PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt));
Benny Prijono0ca04b62005-12-30 23:50:15 +0000643
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000644 pjsip_endpt_release_pool(endpt, pool);
Benny Prijono0ca04b62005-12-30 23:50:15 +0000645
Benny Prijono85598d92006-01-07 18:44:25 +0000646 *lost = total_sent-total_recv;
647
648 /* Flush events. */
649 flush_events(500);
650
651 /* Restore msg logger. */
652 msg_logger_set_enabled(logger_enabled);
653
Benny Prijono0ca04b62005-12-30 23:50:15 +0000654 return 0;
655}
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000656
657///////////////////////////////////////////////////////////////////////////////
658/*
659 * Transport load testing
660 */
661static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata);
662
663static struct mod_load_test
664{
665 pjsip_module mod;
Benny Prijono3c97d9b2008-09-21 22:01:46 +0000666 pj_int32_t next_seq;
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000667 pj_bool_t err;
668} mod_load =
669{
670 {
671 NULL, NULL, /* prev and next */
672 { "mod-load-test", 13}, /* Name. */
673 -1, /* Id */
674 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
675 NULL, /* load() */
676 NULL, /* start() */
677 NULL, /* stop() */
678 NULL, /* unload() */
679 &load_on_rx_request, /* on_rx_request() */
680 NULL, /* on_rx_response() */
681 NULL, /* tsx_handler() */
682 }
683};
684
685
686static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata)
687{
688 if (rdata->msg_info.cseq->cseq != mod_load.next_seq) {
689 PJ_LOG(1,("THIS_FILE", " err: expecting cseq %u, got %u",
690 mod_load.next_seq, rdata->msg_info.cseq->cseq));
691 mod_load.err = PJ_TRUE;
692 mod_load.next_seq = rdata->msg_info.cseq->cseq + 1;
693 } else
694 mod_load.next_seq++;
695 return PJ_TRUE;
696}
697
698int transport_load_test(char *target_url)
699{
700 enum { COUNT = 2000 };
701 unsigned i;
Nanang Izzuddin838cb322008-12-18 17:52:57 +0000702 pj_status_t status = PJ_SUCCESS;
Benny Prijonoed3bd6f2008-08-04 10:52:51 +0000703
704 /* exhaust packets */
705 do {
706 pj_time_val delay = {1, 0};
707 i = 0;
708 pjsip_endpt_handle_events2(endpt, &delay, &i);
709 } while (i != 0);
710
711 PJ_LOG(3,(THIS_FILE, " transport load test..."));
712
713 if (mod_load.mod.id == -1) {
714 status = pjsip_endpt_register_module( endpt, &mod_load.mod);
715 if (status != PJ_SUCCESS) {
716 app_perror("error registering module", status);
717 return -1;
718 }
719 }
720 mod_load.err = PJ_FALSE;
721 mod_load.next_seq = 0;
722
723 for (i=0; i<COUNT && !mod_load.err; ++i) {
724 pj_str_t target, from, call_id;
725 pjsip_tx_data *tdata;
726
727 target = pj_str(target_url);
728 from = pj_str("<sip:user@host>");
729 call_id = pj_str("thecallid");
730 status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
731 &target, &from,
732 &target, &from, &call_id,
733 i, NULL, &tdata );
734 if (status != PJ_SUCCESS) {
735 app_perror("error creating request", status);
736 goto on_return;
737 }
738
739 status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL);
740 if (status != PJ_SUCCESS) {
741 app_perror("error sending request", status);
742 goto on_return;
743 }
744 }
745
746 do {
747 pj_time_val delay = {1, 0};
748 i = 0;
749 pjsip_endpt_handle_events2(endpt, &delay, &i);
750 } while (i != 0);
751
752 if (mod_load.next_seq != COUNT) {
753 PJ_LOG(1,("THIS_FILE", " err: expecting %u msg, got only %u",
754 COUNT, mod_load.next_seq));
755 status = -2;
756 goto on_return;
757 }
758
759on_return:
760 if (mod_load.mod.id != -1) {
761 pjsip_endpt_unregister_module( endpt, &mod_load.mod);
762 mod_load.mod.id = -1;
763 }
764 if (status != PJ_SUCCESS || mod_load.err) {
765 return -2;
766 }
767 PJ_LOG(3,(THIS_FILE, " success"));
768 return 0;
769}
770
771