blob: ab22c5ef147b5cfbcf5dee8f11bd400261ac5343 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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"
22#include <pjsip.h>
23#include <pjlib.h>
24
25#define THIS_FILE "transport_test.c"
26
27///////////////////////////////////////////////////////////////////////////////
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{
34 PJ_LOG(3,(THIS_FILE, " structure test..."));
35
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) {
43 PJ_LOG(3,(THIS_FILE, " Error: invalid address name"));
44 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>"
81#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 */
104 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() */
110 NULL, /* on_tsx_state() */
111};
112
113
114static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata)
115{
116 /* Check that this is our request. */
117 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
118 /* It is! */
119 /* Send response. */
120 pjsip_tx_data *tdata;
121 pjsip_response_addr res_addr;
122 pj_status_t status;
123
124 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{
150 if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) {
151 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 PJ_UNUSED_ARG(stateless_data);
163
164 if (sent < 1) {
165 /* Obtain the error code. */
166 send_status = (int)-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,
179 char *target_url,
180 int *p_usec_rtt)
181{
182 pj_bool_t msg_log_enabled;
183 pj_status_t status;
184 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
189 PJ_UNUSED_ARG(tp_type);
190 PJ_UNUSED_ARG(ref_tp);
191
192 PJ_LOG(3,(THIS_FILE, " single message round-trip test..."));
193
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
203 /* Disable message logging. */
204 msg_log_enabled = msg_logger_set_enabled(0);
205
206 /* Create a request message. */
207 target = pj_str(target_url);
208 from = pj_str(FROM_HDR);
209 to = pj_str(target_url);
210 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). */
230 PJ_LOG(5,(THIS_FILE, "Sending request to %.*s",
231 (int)target.slen, target.ptr));
232 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
240 /* Set the timeout (2 seconds from now) */
241 pj_gettimeofday(&timeout);
242 timeout.sec += 2;
243
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)) {
251 PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test"));
252 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);
280
281 PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt));
282
283 *p_usec_rtt = usec_rt;
284 }
285
286 /* Restore message logging. */
287 msg_logger_set_enabled(msg_log_enabled);
288
289 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 */
316 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;
332 pj_timer_entry timeout_timer;
333 pj_timer_entry tx_timer;
334 pj_mutex_t *mutex;
335} rt_test_data[16];
336
337static char rt_target_uri[64];
338static 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{
343 if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) {
344 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) {
350 app_perror(" error creating response", status);
351 return PJ_TRUE;
352 }
353 status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr);
354 if (status != PJ_SUCCESS) {
355 app_perror(" error in get response address", status);
356 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) {
361 app_perror(" error sending response", status);
362 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;
376 pj_time_val timeout_delay;
377
378 pj_mutex_lock(rt_test_data[thread_id].mutex);
379
380 /* Create a request message. */
381 target = pj_str(rt_target_uri);
382 from = pj_str(FROM_HDR);
383 to = pj_str(rt_target_uri);
384 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) {
392 app_perror(" error: unable to create request", status);
393 pj_mutex_unlock(rt_test_data[thread_id].mutex);
394 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! */
404 app_perror(" error: send request", status);
405 pjsip_tx_data_dec_ref(tdata);
406 pj_mutex_unlock(rt_test_data[thread_id].mutex);
407 return -620;
408 }
409
410 /* Update counter. */
411 rt_test_data[thread_id].sent_request_count++;
412
413 /* 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*)(pj_ssize_t)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);
423 return PJ_SUCCESS;
424}
425
426static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata)
427{
428 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;
430 int thread_id = (*pos - '0');
431 pj_timestamp recv_time;
432
433 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
438 /* 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
445 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*)(pj_ssize_t)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
455 return PJ_TRUE;
456 }
457 return PJ_FALSE;
458}
459
460static 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*)(pj_ssize_t)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)
494{
495 int i;
496 pj_time_val poll_delay = { 0, 10 };
497
498 PJ_UNUSED_ARG(arg);
499
500 /* Sleep to allow main threads to run. */
501 pj_thread_sleep(10);
502
503 while (!rt_stop) {
504 pjsip_endpt_handle_events(endpt, &poll_delay);
505 }
506
507 /* Exhaust responses. */
508 for (i=0; i<100; ++i)
509 pjsip_endpt_handle_events(endpt, &poll_delay);
510
511 return 0;
512}
513
514int transport_rt_test( pjsip_transport_type_e tp_type,
515 pjsip_transport *ref_tp,
516 char *target_url,
517 int *lost)
518{
519 enum { THREADS = 4, INTERVAL = 10 };
520 int i;
521 pj_status_t status;
522 pj_pool_t *pool;
523 pj_bool_t logger_enabled;
524
525 pj_timestamp zero_time, total_time;
526 unsigned usec_rt;
527 unsigned total_sent;
528 unsigned total_recv;
529
530 PJ_UNUSED_ARG(tp_type);
531 PJ_UNUSED_ARG(ref_tp);
532
533 PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...",
534 THREADS));
535 PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..",
536 INTERVAL));
537
538 /* Make sure msg logger is disabled. */
539 logger_enabled = msg_logger_set_enabled(0);
540
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. */
556 pj_ansi_strcpy(rt_target_uri, target_url);
557 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];
563 pj_str_t str_id;
564
565 pj_strset(&str_id, buf, 1);
566 pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i]));
567
568 /* 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
574 /* Generate Call-ID for each thread. */
575 rt_test_data[i].call_id.ptr = (char*) pj_pool_alloc(pool, rt_call_id.slen+1);
576 pj_strcpy(&rt_test_data[i].call_id, &rt_call_id);
577 buf[0] = '0' + (char)i;
578 pj_strcat(&rt_test_data[i].call_id, &str_id);
579
580 /* 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
587 /* Create thread, suspended. */
588 status = pj_thread_create(pool, "rttest%p", &rt_worker_thread,
589 (void*)(pj_ssize_t)i, 0,
590 PJ_THREAD_SUSPENDED, &rt_test_data[i].thread);
591 if (status != PJ_SUCCESS) {
592 app_perror(" error: unable to create thread", status);
593 return -620;
594 }
595 }
596
597 /* Start threads! */
598 for (i=0; i<THREADS; ++i) {
599 pj_time_val delay = {0,0};
600 pj_thread_resume(rt_test_data[i].thread);
601
602 /* Schedule first message transmissions. */
603 rt_test_data[i].tx_timer.user_data = (void*)(pj_ssize_t)1;
604 pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay);
605 }
606
607 /* Sleep for some time. */
608 pj_thread_sleep(INTERVAL * 1000);
609
610 /* Signal thread to stop. */
611 rt_stop = PJ_TRUE;
612
613 /* Wait threads to complete. */
614 for (i=0; i<THREADS; ++i) {
615 pj_thread_join(rt_test_data[i].thread);
616 pj_thread_destroy(rt_test_data[i].thread);
617 }
618
619 /* Destroy rt_test_data */
620 for (i=0; i<THREADS; ++i) {
621 pj_mutex_destroy(rt_test_data[i].mutex);
622 pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer);
623 }
624
625 /* Gather statistics. */
626 pj_bzero(&total_time, sizeof(total_time));
627 pj_bzero(&zero_time, sizeof(zero_time));
628 usec_rt = total_sent = total_recv = 0;
629 for (i=0; i<THREADS; ++i) {
630 total_sent += rt_test_data[i].sent_request_count;
631 total_recv += rt_test_data[i].recv_response_count;
632 pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time);
633 }
634
635 /* Display statistics. */
636 if (total_recv)
637 total_time.u64 = total_time.u64/total_recv;
638 else
639 total_time.u64 = 0;
640 usec_rt = pj_elapsed_usec(&zero_time, &total_time);
641 PJ_LOG(3,(THIS_FILE, " done."));
642 PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent));
643 PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt));
644
645 pjsip_endpt_release_pool(endpt, pool);
646
647 *lost = total_sent-total_recv;
648
649 /* Flush events. */
650 flush_events(500);
651
652 /* Restore msg logger. */
653 msg_logger_set_enabled(logger_enabled);
654
655 return 0;
656}
657
658///////////////////////////////////////////////////////////////////////////////
659/*
660 * Transport load testing
661 */
662static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata);
663
664static struct mod_load_test
665{
666 pjsip_module mod;
667 pj_int32_t next_seq;
668 pj_bool_t err;
669} mod_load =
670{
671 {
672 NULL, NULL, /* prev and next */
673 { "mod-load-test", 13}, /* Name. */
674 -1, /* Id */
675 PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
676 NULL, /* load() */
677 NULL, /* start() */
678 NULL, /* stop() */
679 NULL, /* unload() */
680 &load_on_rx_request, /* on_rx_request() */
681 NULL, /* on_rx_response() */
682 NULL, /* tsx_handler() */
683 }
684};
685
686
687static pj_bool_t load_on_rx_request(pjsip_rx_data *rdata)
688{
689 if (rdata->msg_info.cseq->cseq != mod_load.next_seq) {
690 PJ_LOG(1,("THIS_FILE", " err: expecting cseq %u, got %u",
691 mod_load.next_seq, rdata->msg_info.cseq->cseq));
692 mod_load.err = PJ_TRUE;
693 mod_load.next_seq = rdata->msg_info.cseq->cseq + 1;
694 } else
695 mod_load.next_seq++;
696 return PJ_TRUE;
697}
698
699int transport_load_test(char *target_url)
700{
701 enum { COUNT = 2000 };
702 unsigned i;
703 pj_status_t status = PJ_SUCCESS;
704
705 /* exhaust packets */
706 do {
707 pj_time_val delay = {1, 0};
708 i = 0;
709 pjsip_endpt_handle_events2(endpt, &delay, &i);
710 } while (i != 0);
711
712 PJ_LOG(3,(THIS_FILE, " transport load test..."));
713
714 if (mod_load.mod.id == -1) {
715 status = pjsip_endpt_register_module( endpt, &mod_load.mod);
716 if (status != PJ_SUCCESS) {
717 app_perror("error registering module", status);
718 return -1;
719 }
720 }
721 mod_load.err = PJ_FALSE;
722 mod_load.next_seq = 0;
723
724 for (i=0; i<COUNT && !mod_load.err; ++i) {
725 pj_str_t target, from, call_id;
726 pjsip_tx_data *tdata;
727
728 target = pj_str(target_url);
729 from = pj_str("<sip:user@host>");
730 call_id = pj_str("thecallid");
731 status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
732 &target, &from,
733 &target, &from, &call_id,
734 i, NULL, &tdata );
735 if (status != PJ_SUCCESS) {
736 app_perror("error creating request", status);
737 goto on_return;
738 }
739
740 status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL);
741 if (status != PJ_SUCCESS) {
742 app_perror("error sending request", status);
743 goto on_return;
744 }
745 }
746
747 do {
748 pj_time_val delay = {1, 0};
749 i = 0;
750 pjsip_endpt_handle_events2(endpt, &delay, &i);
751 } while (i != 0);
752
753 if (mod_load.next_seq != COUNT) {
754 PJ_LOG(1,("THIS_FILE", " err: expecting %u msg, got only %u",
755 COUNT, mod_load.next_seq));
756 status = -2;
757 goto on_return;
758 }
759
760on_return:
761 if (mod_load.mod.id != -1) {
762 pjsip_endpt_unregister_module( endpt, &mod_load.mod);
763 mod_load.mod.id = -1;
764 }
765 if (status != PJ_SUCCESS || mod_load.err) {
766 return -2;
767 }
768 PJ_LOG(3,(THIS_FILE, " success"));
769 return 0;
770}
771
772