From 72a1098e21f5b7d797655afe7ddb275969a192bd Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Wed, 28 Jun 2006 16:46:49 +0000 Subject: Major improvements in PJSIP to support TCP. The changes fall into these categories: (1) the TCP transport implementation itself (*.[hc]), (2) bug-fix in SIP transaction when using reliable transports, (3) support for TCP transport in PJSUA-LIB/PJSUA, and (4) changes in PJSIP-TEST to support TCP testing. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@563 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/src/test-pjsip/main.c | 15 +- pjsip/src/test-pjsip/msg_logger.c | 12 +- pjsip/src/test-pjsip/msg_test.c | 191 +++++++++++++---- pjsip/src/test-pjsip/test.c | 195 ++++++++++++++++- pjsip/src/test-pjsip/test.h | 37 +++- pjsip/src/test-pjsip/transport_loop_test.c | 29 ++- pjsip/src/test-pjsip/transport_tcp_test.c | 143 +++++++++++++ pjsip/src/test-pjsip/transport_test.c | 13 +- pjsip/src/test-pjsip/transport_udp_test.c | 16 +- pjsip/src/test-pjsip/tsx_basic_test.c | 19 +- pjsip/src/test-pjsip/tsx_bench.c | 273 ++++++++++++++++++++++++ pjsip/src/test-pjsip/tsx_uac_test.c | 210 +++++++++++++------ pjsip/src/test-pjsip/tsx_uas_test.c | 168 ++++++++++----- pjsip/src/test-pjsip/txdata_test.c | 323 ++++++++++++++++++++++++++++- pjsip/src/test-pjsip/uri_test.c | 185 +++++++++++++---- 15 files changed, 1600 insertions(+), 229 deletions(-) create mode 100644 pjsip/src/test-pjsip/transport_tcp_test.c create mode 100644 pjsip/src/test-pjsip/tsx_bench.c (limited to 'pjsip/src/test-pjsip') diff --git a/pjsip/src/test-pjsip/main.c b/pjsip/src/test-pjsip/main.c index 7994504d..ddfb1e7d 100644 --- a/pjsip/src/test-pjsip/main.c +++ b/pjsip/src/test-pjsip/main.c @@ -21,6 +21,8 @@ #include #include +extern const char *system_name; + static void usage() { puts("Usage: test-pjsip"); @@ -57,6 +59,15 @@ int main(int argc, char *argv[]) return 1; } log_level = atoi(*opt_arg); + } else if (strcmp(*opt_arg, "-s") == 0 || + strcmp(*opt_arg, "--system") == 0) + { + ++opt_arg; + if (!opt_arg) { + usage(); + return 1; + } + system_name = *opt_arg; } else { usage(); return 1; @@ -67,9 +78,9 @@ int main(int argc, char *argv[]) retval = test_main(); - if (argc != 1) { + if (interractive) { char s[10]; - printf("\n"); + printf("\n"); fflush(stdout); fgets(s, sizeof(s), stdin); } diff --git a/pjsip/src/test-pjsip/msg_logger.c b/pjsip/src/test-pjsip/msg_logger.c index a4eac0da..e517ae05 100644 --- a/pjsip/src/test-pjsip/msg_logger.c +++ b/pjsip/src/test-pjsip/msg_logger.c @@ -27,13 +27,15 @@ static pj_bool_t msg_log_enabled; static pj_bool_t on_rx_msg(pjsip_rx_data *rdata) { if (msg_log_enabled) { - PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" - "%s\n" + PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%s:%d:\n" + "%.*s\n" "--end msg--", rdata->msg_info.len, pjsip_rx_data_get_info(rdata), + rdata->tp_info.transport->type_name, rdata->pkt_info.src_name, rdata->pkt_info.src_port, + rdata->msg_info.len, rdata->msg_info.msg_buf)); } @@ -43,13 +45,15 @@ static pj_bool_t on_rx_msg(pjsip_rx_data *rdata) static pj_status_t on_tx_msg(pjsip_tx_data *tdata) { if (msg_log_enabled) { - PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" - "%s\n" + PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%s:%d:\n" + "%.*s\n" "--end msg--", (tdata->buf.cur - tdata->buf.start), pjsip_tx_data_get_info(tdata), + tdata->tp_info.transport->type_name, tdata->tp_info.dst_name, tdata->tp_info.dst_port, + (tdata->buf.cur - tdata->buf.start), tdata->buf.start)); } return PJ_SUCCESS; diff --git a/pjsip/src/test-pjsip/msg_test.c b/pjsip/src/test-pjsip/msg_test.c index f5debe84..ebe43025 100644 --- a/pjsip/src/test-pjsip/msg_test.c +++ b/pjsip/src/test-pjsip/msg_test.c @@ -21,7 +21,11 @@ #include #define POOL_SIZE 8000 -#define LOOP 10000 +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP 10000 +#else +# define LOOP 100000 +#endif #define AVERAGE_MSG_LEN 800 #define THIS_FILE "msg_test.c" @@ -35,8 +39,6 @@ static pjsip_msg *create_msg1(pj_pool_t *pool); #define FLAG_PARSE_ONLY 4 #define FLAG_PRINT_ONLY 8 -static int flag = 0; - struct test_msg { char msg[1024]; @@ -101,8 +103,12 @@ struct test_msg } }; -static pj_highprec_t detect_len, parse_len, print_len; -static pj_timestamp detect_time, parse_time, print_time; +static struct +{ + int flag; + pj_highprec_t detect_len, parse_len, print_len; + pj_timestamp detect_time, parse_time, print_time; +} var; static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) { @@ -121,17 +127,17 @@ static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) entry->len = pj_native_strlen(entry->msg); - if (flag & FLAG_PARSE_ONLY) + if (var.flag & FLAG_PARSE_ONLY) goto parse_msg; - if (flag & FLAG_PRINT_ONLY) { + if (var.flag & FLAG_PRINT_ONLY) { if (print_msg == NULL) print_msg = entry->creator(pool); goto print_msg; } /* Detect message. */ - detect_len = detect_len + entry->len; + var.detect_len = var.detect_len + entry->len; pj_get_timestamp(&t1); status = pjsip_find_msg(entry->msg, entry->len, PJ_FALSE, &msg_size); if (status != PJ_SUCCESS) { @@ -148,14 +154,14 @@ static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&detect_time, &t2); + pj_add_timestamp(&var.detect_time, &t2); - if (flag & FLAG_DETECT_ONLY) + if (var.flag & FLAG_DETECT_ONLY) return PJ_SUCCESS; /* Parse message. */ parse_msg: - parse_len = parse_len + entry->len; + var.parse_len = var.parse_len + entry->len; pj_get_timestamp(&t1); pj_list_init(&err_list); parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, &err_list); @@ -171,9 +177,9 @@ parse_msg: } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&parse_time, &t2); + pj_add_timestamp(&var.parse_time, &t2); - if (flag & FLAG_PARSE_ONLY) + if (var.flag & FLAG_PARSE_ONLY) return PJ_SUCCESS; /* Create reference message. */ @@ -306,9 +312,9 @@ parse_msg: /* Print message. */ print_msg: - print_len = print_len + entry->len; + var.print_len = var.print_len + entry->len; pj_get_timestamp(&t1); - if (flag && FLAG_PRINT_ONLY) + if (var.flag && FLAG_PRINT_ONLY) ref_msg = print_msg; len = pjsip_msg_print(ref_msg, msgbuf1, PJSIP_MAX_PKT_LEN); if (len < 1) { @@ -317,7 +323,7 @@ print_msg: } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&print_time, &t2); + pj_add_timestamp(&var.print_time, &t2); status = PJ_SUCCESS; @@ -674,17 +680,14 @@ static pjsip_msg *create_msg1(pj_pool_t *pool) /*****************************************************************************/ -int msg_test(void) +static pj_status_t simple_test(void) { + unsigned i; pj_status_t status; - pj_pool_t *pool; - int i, loop; - pj_timestamp zero; - pj_time_val elapsed; - pj_highprec_t avg_detect, avg_parse, avg_print, kbytes; PJ_LOG(3,(THIS_FILE, " simple test..")); for (i=0; i max) max = run[i].detect; + + PJ_LOG(3,("", " Maximum message detection/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be pre-parse by pjsip_find_msg() " + "per second (tested with %d message sets with " + "average message length of " + "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); + report_ival("msg-detect-per-sec", max, "msg/sec", desc); + + /* Print maximum parse/sec */ + for (i=0, max=0; i max) max = run[i].parse; + + PJ_LOG(3,("", " Maximum message parsing/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be parsed by pjsip_parse_msg() " + "per second (tested with %d message sets with " + "average message length of " + "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); + report_ival("msg-parse-per-sec", max, "msg/sec", desc); + + /* Msg parsing bandwidth */ + report_ival("msg-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "Message parsing bandwidth in megabytes (number of megabytes" + " worth of SIP messages that can be parsed per second). " + "The value is derived from msg-parse-per-sec above."); + + + /* Print maximum print/sec */ + for (i=0, max=0; i max) max = run[i].print; + + PJ_LOG(3,("", " Maximum message print/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be printed by pjsip_msg_print()" + " per second (tested with %d message sets with " + "average message length of " + "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); + + report_ival("msg-print-per-sec", max, "msg/sec", desc); + + /* Msg print bandwidth */ + report_ival("msg-printed-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "Message print bandwidth in megabytes (total size of " + "SIP messages printed per second). " + "The value is derived from msg-print-per-sec above."); + + + return PJ_SUCCESS; +} + diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c index b8707332..3ae58daa 100644 --- a/pjsip/src/test-pjsip/test.c +++ b/pjsip/src/test-pjsip/test.c @@ -33,11 +33,24 @@ if (rc!=0) goto on_return; \ } while (0) +#define DO_TSX_TEST(test, param) \ + do { \ + PJ_LOG(3, (THIS_FILE, "Running %s(%s)...", #test, (param)->tp_type)); \ + rc = test(param); \ + PJ_LOG(3, (THIS_FILE, \ + "%s(%d)", \ + (rc ? "..ERROR" : "..success"), rc)); \ + if (rc!=0) goto on_return; \ + } while (0) pjsip_endpoint *endpt; int log_level = 3; +static pj_oshandle_t fd_report; +const char *system_name = "Unknown"; +static char buf[1024]; + void app_perror(const char *msg, pj_status_t rc) { char errbuf[256]; @@ -75,11 +88,142 @@ pj_status_t register_static_modules(pj_size_t *count, pjsip_module **modules) return PJ_SUCCESS; } +static pj_status_t init_report(void) +{ + char tmp[80]; + pj_time_val timestamp; + pj_parsed_time date_time; + pj_ssize_t len; + pj_status_t status; + + pj_ansi_sprintf(tmp, "pjsip-static-bench-%s-%s.htm", PJ_OS_NAME, PJ_CC_NAME); + + status = pj_file_open(NULL, tmp, PJ_O_WRONLY, &fd_report); + if (status != PJ_SUCCESS) + return status; + + /* Title */ + len = pj_ansi_sprintf(buf, "\n" + " \n" + " PJSIP %s (%s) - Static Benchmark\n" + " \n" + "\n" + "\n", + PJ_VERSION, + (PJ_DEBUG ? "Debug" : "Release")); + pj_file_write(fd_report, buf, &len); + + + /* Title */ + len = pj_ansi_sprintf(buf, "

PJSIP %s (%s) - Static Benchmark

\n", + PJ_VERSION, + (PJ_DEBUG ? "Debug" : "Release")); + pj_file_write(fd_report, buf, &len); + + len = pj_ansi_sprintf(buf, "

Below is the benchmark result generated " + "by test-pjsip program. The program " + "is single-threaded only.

\n"); + pj_file_write(fd_report, buf, &len); + + + /* Write table heading */ + len = pj_ansi_sprintf(buf, "\n" + " \n" + " \n" + " \n" + " \n"); + pj_file_write(fd_report, buf, &len); + + + /* Write version */ + report_sval("version", PJ_VERSION, "", "PJLIB/PJSIP version"); + + + /* Debug or release */ + report_sval("build-type", (PJ_DEBUG ? "Debug" : "Release"), "", "Build type"); + + + /* Write timestamp */ + pj_gettimeofday(×tamp); + report_ival("timestamp", timestamp.sec, "", "System timestamp of the test"); + + + /* Write time of day */ + pj_time_decode(×tamp, &date_time); + len = pj_ansi_sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", + date_time.year, date_time.mon+1, date_time.day, + date_time.hour, date_time.min, date_time.sec); + report_sval("date-time", tmp, "", "Date/time of the test"); + + + /* Write System */ + report_sval("system", system_name, "", "System description"); + + + /* Write OS type */ + report_sval("os-family", PJ_OS_NAME, "", "Operating system family"); + + + /* Write CC name */ + len = pj_ansi_sprintf(tmp, "%s-%d.%d.%d", PJ_CC_NAME, + PJ_CC_VER_1, PJ_CC_VER_2, PJ_CC_VER_2); + report_sval("cc-name", tmp, "", "Compiler name and version"); + + + return PJ_SUCCESS; +} + +void report_sval(const char *name, const char* value, const char *valname, + const char *desc) +{ + pj_ssize_t len; + + len = pj_ansi_sprintf(buf, " \n" + " \n" + " \n" + " \n", + name, value, valname, desc); + pj_file_write(fd_report, buf, &len); +} + + +void report_ival(const char *name, int value, const char *valname, + const char *desc) +{ + pj_ssize_t len; + + len = pj_ansi_sprintf(buf, " \n" + " \n" + " \n" + " \n", + name, value, valname, desc); + pj_file_write(fd_report, buf, &len); + +} + +static void close_report(void) +{ + pj_ssize_t len; + + if (fd_report) { + len = pj_ansi_sprintf(buf, "
VariableValueDescription
%s%s %s%s
%s%d %s%s
\n\n\n"); + pj_file_write(fd_report, buf, &len); + + pj_file_close(fd_report); + } +} + + int test_main(void) { pj_status_t rc; pj_caching_pool caching_pool; const char *filename; + unsigned i, tsx_test_cnt=0; + struct tsx_test_param tsx_test[10]; + pj_status_t status; + pjsip_transport *tp; + pjsip_tpfactory *tpfactory; int line; pj_log_set_level(log_level); @@ -93,6 +237,10 @@ int test_main(void) return rc; } + status = init_report(); + if (status != PJ_SUCCESS) + return status; + pj_dump_config(); pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); @@ -124,6 +272,11 @@ int test_main(void) rc); goto on_return; } + tsx_test[tsx_test_cnt].port = 5060; + tsx_test[tsx_test_cnt].tp_type = "loop-dgram"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_LOOP_DGRAM; + ++tsx_test_cnt; + #if INCLUDE_URI_TEST DO_TEST(uri_test()); @@ -138,6 +291,10 @@ int test_main(void) DO_TEST(txdata_test()); #endif +#if INCLUDE_TSX_BENCH + DO_TEST(tsx_bench()); +#endif + #if INCLUDE_UDP_TEST DO_TEST(transport_udp_test()); #endif @@ -146,15 +303,43 @@ int test_main(void) DO_TEST(transport_loop_test()); #endif +#if INCLUDE_TCP_TEST + DO_TEST(transport_tcp_test()); +#endif + + #if INCLUDE_TSX_TEST - DO_TEST(tsx_basic_test()); - DO_TEST(tsx_uac_test()); - DO_TEST(tsx_uas_test()); + status = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &tp); + if (status == PJ_SUCCESS) { + tsx_test[tsx_test_cnt].port = tp->local_name.port; + tsx_test[tsx_test_cnt].tp_type = "udp"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_UDP; + ++tsx_test_cnt; + } + + status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); + if (status == PJ_SUCCESS) { + tsx_test[tsx_test_cnt].port = tpfactory->addr_name.port; + tsx_test[tsx_test_cnt].tp_type = "tcp"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_TCP; + ++tsx_test_cnt; + } else { + app_perror("Unable to create TCP", status); + rc = -4; + goto on_return; + } + + + for (i=0; iref_cnt); + /* Test basic transport attributes */ status = generic_transport_test(loop); if (status != PJ_SUCCESS) return status; /* Basic transport's send/receive loopback test. */ - for (i=0; i<2; ++i) { + for (i=0; iref_cnt) != 1) { - return -50; + /* Check reference counter. */ + if (pj_atomic_get(loop->ref_cnt) != ref_cnt) { + PJ_LOG(3,(THIS_FILE, " error: ref counter is not %d (%d)", + ref_cnt, pj_atomic_get(loop->ref_cnt))); + return -51; } /* Decrement reference. */ diff --git a/pjsip/src/test-pjsip/transport_tcp_test.c b/pjsip/src/test-pjsip/transport_tcp_test.c new file mode 100644 index 00000000..70f1bc92 --- /dev/null +++ b/pjsip/src/test-pjsip/transport_tcp_test.c @@ -0,0 +1,143 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "transport_tcp_test.c" + + +/* + * TCP transport test. + */ +int transport_tcp_test(void) +{ + enum { SEND_RECV_LOOP = 8 }; + pjsip_tpfactory *tpfactory; + pjsip_transport *tcp; + pj_sockaddr_in rem_addr; + pj_status_t status; + char url[64]; + unsigned rtt[SEND_RECV_LOOP], min_rtt; + int i, pkt_lost; + + /* Start TCP listener on arbitrary port. */ + status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to start TCP transport", status); + return -10; + } + + + /* Get the listener address */ + status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, + (pj_uint16_t)tpfactory->addr_name.port); + if (status != PJ_SUCCESS) { + app_perror(" Error: possibly invalid TCP address name", status); + return -14; + } + + pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp", + pj_inet_ntoa(rem_addr.sin_addr), + pj_ntohs(rem_addr.sin_port)); + + + /* Acquire one TCP transport. */ + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, + &rem_addr, sizeof(rem_addr), + &tcp); + if (status != PJ_SUCCESS || tcp == NULL) { + app_perror(" Error: unable to acquire TCP transport", status); + return -17; + } + + /* After pjsip_endpt_acquire_transport, TCP transport must have + * reference counter 1. + */ + if (pj_atomic_get(tcp->ref_cnt) != 1) + return -20; + + /* Test basic transport attributes */ + status = generic_transport_test(tcp); + if (status != PJ_SUCCESS) + return status; + + + /* Check again that reference counter is 1. */ + if (pj_atomic_get(tcp->ref_cnt) != 1) + return -70; + + /* Basic transport's send/receive loopback test. */ + for (i=0; iref_cnt) != 1) + return -80; + + /* Destroy this transport. */ + pjsip_transport_dec_ref(tcp); + + /* Force destroy this transport. */ + status = pjsip_transport_destroy(tcp); + if (status != PJ_SUCCESS) + return -90; + + /* Unregister factory */ + status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), + tpfactory); + if (status != PJ_SUCCESS) + return -95; + + /* Flush events. */ + PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); + flush_events(1000); + + /* Done */ + return 0; +} diff --git a/pjsip/src/test-pjsip/transport_test.c b/pjsip/src/test-pjsip/transport_test.c index 0cd0d225..5aa491a2 100644 --- a/pjsip/src/test-pjsip/transport_test.c +++ b/pjsip/src/test-pjsip/transport_test.c @@ -173,7 +173,8 @@ static void send_msg_callback(pjsip_send_state *stateless_data, /* Test that we receive loopback message. */ int transport_send_recv_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, - char *target_url ) + char *target_url, + int *p_usec_rtt) { pj_bool_t msg_log_enabled; pj_status_t status; @@ -220,6 +221,8 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, pj_get_timestamp(&my_send_time); /* Send the message (statelessly). */ + PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", + (int)target.slen, target.ptr)); status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, &send_msg_callback); if (status != PJ_SUCCESS) { @@ -228,9 +231,9 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, send_status = status; } - /* Set the timeout (1 second from now) */ + /* Set the timeout (2 seconds from now) */ pj_gettimeofday(&timeout); - timeout.sec += 1; + timeout.sec += 2; /* Loop handling events until we get status */ do { @@ -268,7 +271,10 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, if (status == PJ_SUCCESS) { unsigned usec_rt; usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); + PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt)); + + *p_usec_rtt = usec_rt; } /* Restore message logging. */ @@ -516,7 +522,6 @@ int transport_rt_test( pjsip_transport_type_e tp_type, unsigned total_sent; unsigned total_recv; - PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...", THREADS)); PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..", diff --git a/pjsip/src/test-pjsip/transport_udp_test.c b/pjsip/src/test-pjsip/transport_udp_test.c index 4db0a7ca..34bb02c4 100644 --- a/pjsip/src/test-pjsip/transport_udp_test.c +++ b/pjsip/src/test-pjsip/transport_udp_test.c @@ -29,11 +29,12 @@ */ int transport_udp_test(void) { - enum { SEND_RECV_LOOP = 2 }; + enum { SEND_RECV_LOOP = 8 }; pjsip_transport *udp_tp, *tp; pj_sockaddr_in addr, rem_addr; pj_str_t s; pj_status_t status; + unsigned rtt[SEND_RECV_LOOP], min_rtt; int i, pkt_lost; pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT); @@ -79,11 +80,22 @@ int transport_udp_test(void) pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT); for (i=0; iport, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + status = tsx_layer_test(); if (status != 0) return status; diff --git a/pjsip/src/test-pjsip/tsx_bench.c b/pjsip/src/test-pjsip/tsx_bench.c new file mode 100644 index 00000000..53c950cb --- /dev/null +++ b/pjsip/src/test-pjsip/tsx_bench.c @@ -0,0 +1,273 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" +#include +#include + +#define THIS_FILE "tsx_uas_test.c" + + +static pjsip_module mod_tsx_user; + +static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) +{ + unsigned i; + pjsip_tx_data *request; + pjsip_transaction **tsx; + pj_timestamp t1, t2, elapsed; + pj_status_t status; + + /* Create the request first. */ + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" "); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create transaction array */ + tsx = pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); + + pj_memset(&mod_tsx_user, 0, sizeof(mod_tsx_user)); + mod_tsx_user.id = -1; + + /* Benchmark */ + elapsed.u64 = 0; + pj_get_timestamp(&t1); + for (i=0; iu64 = elapsed.u64; + status = PJ_SUCCESS; + +on_error: + for (i=0; i"); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create Via */ + via = pjsip_via_hdr_create(request->pool); + via->sent_by.host = pj_str("192.168.0.7"); + via->sent_by.port = 5061; + via->transport = pj_str("udp"); + via->rport_param = 1; + via->recvd_param = pj_str("192.168.0.7"); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); + + + /* Create "dummy" rdata from the tdata */ + pj_memset(&rdata, 0, sizeof(pjsip_rx_data)); + rdata.tp_info.pool = request->pool; + rdata.msg_info.msg = request->msg; + rdata.msg_info.from = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.to = pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); + rdata.msg_info.cseq = pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); + rdata.msg_info.cid = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.via = via; + + pj_sockaddr_in_init(&remote, 0, 0); + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, + &remote, sizeof(pj_sockaddr_in), + &rdata.tp_info.transport); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to get loop transport", status); + return status; + } + + + /* Create transaction array */ + tsx = pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); + + pj_memset(&mod_tsx_user, 0, sizeof(mod_tsx_user)); + mod_tsx_user.id = -1; + + + /* Benchmark */ + elapsed.u64 = 0; + pj_get_timestamp(&t1); + for (i=0; ibranch_param.ptr = branch_buf; + via->branch_param.slen = PJSIP_RFC3261_BRANCH_LEN + + pj_ansi_sprintf(branch_buf+PJSIP_RFC3261_BRANCH_LEN, + "-%d", i); + status = pjsip_tsx_create_uas(&mod_tsx_user, &rdata, &tsx[i]); + if (status != PJ_SUCCESS) + goto on_error; + + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&elapsed, &t2); + + p_elapsed->u64 = elapsed.u64; + status = PJ_SUCCESS; + +on_error: + for (i=0; ipjsip_tsx_create_uac(), based on the time " + "to create %d simultaneous transactions above.", + WORKING_SET); + + report_ival("create-uac-tsx-per-sec", + speed, "tsx/sec", desc); + + + + /* + * Benchmark UAS + */ + PJ_LOG(3,(THIS_FILE, " benchmarking UAS transaction creation:")); + for (i=0; ipjsip_tsx_create_uas(), based on the time " + "to create %d simultaneous transactions above.", + WORKING_SET); + + report_ival("create-uas-tsx-per-sec", + speed, "tsx/sec", desc); + + return PJ_SUCCESS; +} + diff --git a/pjsip/src/test-pjsip/tsx_uac_test.c b/pjsip/src/test-pjsip/tsx_uac_test.c index d2717fec..b97b01a9 100644 --- a/pjsip/src/test-pjsip/tsx_uac_test.c +++ b/pjsip/src/test-pjsip/tsx_uac_test.c @@ -91,6 +91,10 @@ static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test9"; #define TEST4_RETRANSMIT_CNT 3 #define TEST5_RETRANSMIT_CNT 3 +static char TARGET_URI[128]; +static char FROM_URI[128]; +static unsigned tp_flag; +static struct tsx_test_param *test_param; static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e); static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata); @@ -140,7 +144,12 @@ static pj_bool_t test_complete; static pjsip_transport *loop; /* General timer entry to be used by tests. */ -static pj_timer_entry timer; +static struct my_timer +{ + pj_timer_entry entry; + char key_buf[1024]; + pj_str_t tsx_key; +} timer; /* * This is the handler to receive state changed notification from the @@ -166,6 +175,41 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) tsx->status_code, PJSIP_SC_TSX_TIMEOUT)); test_complete = -710; } + + + /* If transport is reliable, then there must not be any + * retransmissions. + */ + if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { + if (recv_count != 1) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -715; + } + } else { + /* Check the number of transmissions, which must be + * 6 for INVITE and 10 for non-INVITE + */ + if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -716; + } else + if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -717; + } else + if (tsx->method.id!=PJSIP_INVITE_METHOD && + tsx->method.id!=PJSIP_OPTIONS_METHOD) + { + PJ_LOG(3,(THIS_FILE, " error: unexpected method")); + test_complete = -718; + } + } } } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) { @@ -515,7 +559,8 @@ static void send_response_callback( pj_timer_heap_t *timer_heap, static void terminate_tsx_callback( pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry) { - pjsip_transaction *tsx = entry->user_data; + struct my_timer *m = (struct my_timer *)entry; + pjsip_transaction *tsx = pjsip_tsx_layer_find_tsx(&m->tsx_key, PJ_FALSE); int status_code = entry->id; if (tsx) { @@ -720,9 +765,9 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) if (r->res_addr.transport) pjsip_transport_add_ref(r->res_addr.transport); - timer.cb = &send_response_callback; - timer.user_data = r; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + timer.entry.cb = &send_response_callback; + timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); return PJ_TRUE; @@ -768,11 +813,11 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); - timer.user_data = pjsip_tsx_layer_find_tsx(&key, PJ_FALSE); - timer.id = 301; - timer.cb = &terminate_tsx_callback; + pj_strcpy(&timer.tsx_key, &key); + timer.entry.id = 301; + timer.entry.cb = &terminate_tsx_callback; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } if (recv_count > 2) { @@ -841,9 +886,9 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) if (r->res_addr.transport) pjsip_transport_add_ref(r->res_addr.transport); - timer.cb = &send_response_callback; - timer.user_data = r; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + timer.entry.cb = &send_response_callback; + timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } else if (method->id == PJSIP_ACK_METHOD) { @@ -859,11 +904,11 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); - timer.user_data = pjsip_tsx_layer_find_tsx(&key, PJ_FALSE); - timer.id = 302; - timer.cb = &terminate_tsx_callback; + pj_strcpy(&timer.tsx_key, &key); + timer.entry.id = 302; + timer.entry.cb = &terminate_tsx_callback; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } if (recv_count > 2) { @@ -980,10 +1025,23 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, } pjsip_tx_data_dec_ref(tdata); return test_complete; - } - /* Allow transaction to destroy itself */ - flush_events(500); + } else { + pj_time_val now; + + /* Allow transaction to destroy itself */ + flush_events(500); + + /* Wait until test completes */ + pj_gettimeofday(&now); + + if (PJ_TIME_VAL_LT(now, timeout)) { + pj_time_val interval; + interval = timeout; + PJ_TIME_VAL_SUB(interval, now); + flush_events(PJ_TIME_VAL_MSEC(interval)); + } + } /* Make sure transaction has been destroyed. */ if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) { @@ -1052,8 +1110,7 @@ static int tsx_uac_retransmit_test(void) pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL); /* Do the test. */ - status = perform_tsx_test(-500, "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-500, TARGET_URI, FROM_URI, TEST1_BRANCH_ID, 35, sub_test[i].method); if (status != 0) @@ -1093,9 +1150,8 @@ static int tsx_resolve_error_test(void) PJ_LOG(3,(THIS_FILE, " variant a: immediate resolving error")); status = perform_tsx_test(-800, - "sip:bob@unresolved-host;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", - TEST2_BRANCH_ID, 10, + "sip:bob@unresolved-host", + FROM_URI, TEST2_BRANCH_ID, 10, &pjsip_options_method); if (status != 0) return status; @@ -1105,20 +1161,22 @@ static int tsx_resolve_error_test(void) */ PJ_LOG(3,(THIS_FILE, " variant b: error via callback")); - /* Set loop transport to return delayed error. */ - pjsip_loop_set_failure(loop, 2, NULL); - pjsip_loop_set_send_callback_delay(loop, 10, NULL); + /* This only applies to "loop-dgram" transport */ + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + /* Set loop transport to return delayed error. */ + pjsip_loop_set_failure(loop, 2, NULL); + pjsip_loop_set_send_callback_delay(loop, 10, NULL); - status = perform_tsx_test(-800, "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", - TEST2_BRANCH_ID, 2, - &pjsip_options_method); - if (status != 0) - return status; + status = perform_tsx_test(-800, TARGET_URI, FROM_URI, + TEST2_BRANCH_ID, 2, + &pjsip_options_method); + if (status != 0) + return status; - /* Restore loop transport settings. */ - pjsip_loop_set_failure(loop, 0, NULL); - pjsip_loop_set_send_callback_delay(loop, 0, NULL); + /* Restore loop transport settings. */ + pjsip_loop_set_failure(loop, 0, NULL); + pjsip_loop_set_send_callback_delay(loop, 0, NULL); + } return status; } @@ -1143,8 +1201,7 @@ static int tsx_terminate_resolving_test(void) pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay); /* Start the test. */ - status = perform_tsx_test(-900, "sip:127.0.0.1;transport=loop-dgram", - "sip:127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-900, TARGET_URI, FROM_URI, TEST3_BRANCH_ID, 2, &pjsip_options_method); /* Restore delay. */ @@ -1186,8 +1243,7 @@ static int tsx_retransmit_fail_test(void) pjsip_loop_set_failure(loop, 0, 0); /* Start the test. */ - status = perform_tsx_test(-1000, "sip:127.0.0.1;transport=loop-dgram", - "sip:127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-1000, TARGET_URI, FROM_URI, TEST4_BRANCH_ID, 6, &pjsip_options_method); if (status != 0) @@ -1218,8 +1274,7 @@ static int tsx_terminate_after_retransmit_test(void) PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions")); /* Do the test. */ - status = perform_tsx_test(-1100, "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-1100, TARGET_URI, FROM_URI, TEST5_BRANCH_ID, 6, &pjsip_options_method); @@ -1249,18 +1304,20 @@ static int perform_generic_test( const char *title, /* Do the test. */ for (i=0; itype == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay", + ('a'+i), delay[i])); - pjsip_loop_set_delay(loop, delay[i]); + pjsip_loop_set_delay(loop, delay[i]); + } - status = perform_tsx_test(-1200, - "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", - branch_id, - 10, method); + status = perform_tsx_test(-1200, TARGET_URI, FROM_URI, + branch_id, 10, method); if (status != 0) return status; + + if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM) + break; } pjsip_loop_set_delay(loop, 0); @@ -1276,11 +1333,23 @@ static int perform_generic_test( const char *title, ** ***************************************************************************** */ -int tsx_uac_test(void) +int tsx_uac_test(struct tsx_test_param *param) { pj_sockaddr_in addr; pj_status_t status; + timer.tsx_key.ptr = timer.key_buf; + + test_param = param; + + /* Get transport flag */ + tp_flag = pjsip_transport_get_flag_from_type(test_param->type); + + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + /* Check if loop transport is configured. */ status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, &addr, sizeof(addr), &loop); @@ -1316,15 +1385,23 @@ int tsx_uac_test(void) if (status != 0) return status; - /* TEST4_BRANCH_ID: Transport failed after several retransmissions */ - status = tsx_retransmit_fail_test(); - if (status != 0) - return status; + /* TEST4_BRANCH_ID: Transport failed after several retransmissions. + * Only applies to loop transport. + */ + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + status = tsx_retransmit_fail_test(); + if (status != 0) + return status; + } - /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions */ - status = tsx_terminate_after_retransmit_test(); - if (status != 0) - return status; + /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions + * Only applicable to non-reliable transports. + */ + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_terminate_after_retransmit_test(); + if (status != 0) + return status; + } /* TEST6_BRANCH_ID: Successfull non-invite transaction */ status = perform_generic_test("test6: successfull non-invite transaction", @@ -1352,8 +1429,21 @@ int tsx_uac_test(void) if (status != 0) return status; - pjsip_transport_dec_ref(loop); + flush_events(500); + + /* Unregister modules. */ + status = pjsip_endpt_unregister_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -31; + } + status = pjsip_endpt_unregister_module(endpt, &msg_receiver); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -41; + } + return 0; } diff --git a/pjsip/src/test-pjsip/tsx_uas_test.c b/pjsip/src/test-pjsip/tsx_uas_test.c index 3ff2e18e..42cb075f 100644 --- a/pjsip/src/test-pjsip/tsx_uas_test.c +++ b/pjsip/src/test-pjsip/tsx_uas_test.c @@ -35,6 +35,8 @@ ** TEST1_BRANCH_ID ** Test that non-INVITE transaction returns 2xx response to the correct ** transport and correctly terminates the transaction. + ** This also checks that transaction is destroyed immediately after + ** it sends final response when reliable transport is used. ** ** TEST2_BRANCH_ID ** As above, for non-2xx final response. @@ -53,6 +55,7 @@ ** ** TEST6_BRANCH_ID ** As above, in COMPLETED state, with first sending provisional response. + ** (Only applicable for non-reliable transports). ** ** TEST7_BRANCH_ID ** INVITE transaction MUST retransmit non-2xx final response. @@ -65,6 +68,7 @@ ** ACK is received. (Note: PJSIP also retransmit 2xx final response ** until it's terminated by user). ** Transaction also MUST terminate in T4 seconds. + ** (Only applicable for non-reliable transports). ** ** TEST11_BRANCH_ID ** Test scenario where transport fails before response is sent (i.e. @@ -128,6 +132,12 @@ static char *TEST13_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test13"; #define TEST6_TITLE "test6: retransmit last response in COMPLETED state" +static char TARGET_URI[128]; +static char FROM_URI[128]; +static struct tsx_test_param *test_param; +static unsigned tp_flag; + + #define TEST_TIMEOUT_ERROR -30 #define MAX_ALLOWED_DIFF 150 @@ -521,7 +531,9 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* Check that status code is status_code. */ if (tsx->status_code != TEST6_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + PJ_LOG(3,(THIS_FILE, " error: incorrect status code %d " + "(expecting %d)", tsx->status_code, + TEST6_STATUS_CODE)); test_complete = -140; } @@ -577,6 +589,26 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) test_complete = -151; } + /* Check the number of retransmissions */ + if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { + + if (tsx->retransmit_count != 0) { + PJ_LOG(3,(THIS_FILE, " error: should not retransmit")); + test_complete = -1510; + } + + } else { + + if (tsx->retransmit_count != 10) { + PJ_LOG(3,(THIS_FILE, + " error: incorrect retransmit count %d " + "(expecting 10)", + tsx->retransmit_count)); + test_complete = -1510; + } + + } + } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { /* Check that status code is status_code. */ @@ -814,6 +846,8 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) /* On received request, create UAS. */ pjsip_transaction *tsx; + PJ_LOG(4,(THIS_FILE, " received request (probably retransmission)")); + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); @@ -830,13 +864,17 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) send_response(rdata, tsx, TEST5_PROVISIONAL_CODE); } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) { + PJ_LOG(4,(THIS_FILE, " sending provisional response")); send_response(rdata, tsx, TEST6_PROVISIONAL_CODE); + PJ_LOG(4,(THIS_FILE, " sending final response")); send_response(rdata, tsx, TEST6_STATUS_CODE); } } else { /* Verify the response received. */ + PJ_LOG(4,(THIS_FILE, " received response number %d", recv_count)); + ++recv_count; if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) { @@ -869,7 +907,8 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) case 2: case 3: if (code != TEST6_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: invalid code!")); + PJ_LOG(3,(THIS_FILE, " error: invalid code %d " + "(expecting %d)", code, TEST6_STATUS_CODE)); test_complete = -136; } break; @@ -1183,6 +1222,8 @@ static int perform_test( char *target_uri, char *from_uri, pjsip_tx_data_add_ref(tdata); /* (Re)Send the request. */ + PJ_LOG(4,(THIS_FILE, " (re)sending request %d", sent_cnt)); + status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0); if (status != PJ_SUCCESS) { app_perror(" Error: unable to send request", status); @@ -1255,25 +1296,25 @@ static int perform_test( char *target_uri, char *from_uri, */ static int tsx_basic_final_response_test(void) { + unsigned duration; int status; PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST1_BRANCH_ID, - 33, /* Test duration must be greater than 32 secs */ - &pjsip_options_method, 1, 0, 0); + /* Test duration must be greater than 32 secs if unreliable transport + * is used. + */ + duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + + status = perform_test(TARGET_URI, FROM_URI, TEST1_BRANCH_ID, + duration, &pjsip_options_method, 1, 0, 0); if (status != 0) return status; PJ_LOG(3,(THIS_FILE," test2: basic sending non-2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST2_BRANCH_ID, - 33, /* Test duration must be greater than 32 secs */ - &pjsip_options_method, 1, 0, 0); + status = perform_test(TARGET_URI, FROM_URI, TEST2_BRANCH_ID, + duration, &pjsip_options_method, 1, 0, 0); if (status != 0) return status; @@ -1289,14 +1330,15 @@ static int tsx_basic_final_response_test(void) */ static int tsx_basic_provisional_response_test(void) { + unsigned duration; int status; PJ_LOG(3,(THIS_FILE," test3: basic sending 2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST3_BRANCH_ID, - 35, + duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + duration += 2; + + status = perform_test(TARGET_URI, FROM_URI, TEST3_BRANCH_ID, duration, &pjsip_options_method, 1, 0, 0); return status; @@ -1320,10 +1362,7 @@ static int tsx_retransmit_last_response_test(const char *title, PJ_LOG(3,(THIS_FILE," %s", title)); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - branch_id, - 5, + status = perform_test(TARGET_URI, FROM_URI, branch_id, 5, &pjsip_options_method, request_cnt, 1000, 1); if (status && status != TEST_TIMEOUT_ERROR) @@ -1357,9 +1396,7 @@ static int tsx_final_response_retransmission_test(void) PJ_LOG(3,(THIS_FILE, " test7: INVITE non-2xx final response retransmission")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST7_BRANCH_ID, + status = perform_test(TARGET_URI, FROM_URI, TEST7_BRANCH_ID, 33, /* Test duration must be greater than 32 secs */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1368,9 +1405,7 @@ static int tsx_final_response_retransmission_test(void) PJ_LOG(3,(THIS_FILE, " test8: INVITE 2xx final response retransmission")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST8_BRANCH_ID, + status = perform_test(TARGET_URI, FROM_URI, TEST8_BRANCH_ID, 33, /* Test duration must be greater than 32 secs */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1394,9 +1429,7 @@ static int tsx_ack_test(void) PJ_LOG(3,(THIS_FILE, " test9: receiving ACK for non-2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST9_BRANCH_ID, + status = perform_test(TARGET_URI, FROM_URI, TEST9_BRANCH_ID, 20, /* allow 5 retransmissions */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1443,11 +1476,8 @@ static int tsx_transport_failure_test(void) pjsip_loop_set_failure(loop, 0, NULL); pjsip_loop_set_delay(loop, tests[i].transport_delay); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - tests[i].branch_id, - 0, - &pjsip_invite_method, 1, 0, 1); + status = perform_test(TARGET_URI, FROM_URI, tests[i].branch_id, + 0, &pjsip_invite_method, 1, 0, 1); if (status && status != TEST_TIMEOUT_ERROR) return status; if (!status) { @@ -1494,19 +1524,26 @@ static int tsx_transport_failure_test(void) ** ***************************************************************************** */ -int tsx_uas_test(void) +int tsx_uas_test(struct tsx_test_param *param) { pj_sockaddr_in addr; pj_status_t status; + test_param = param; + tp_flag = pjsip_transport_get_flag_from_type(param->type); + + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + /* Check if loop transport is configured. */ status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, &addr, sizeof(addr), &loop); if (status != PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!")); - return -1; + return -10; } - /* Register modules. */ status = pjsip_endpt_register_module(endpt, &tsx_user); if (status != PJ_SUCCESS) { @@ -1550,42 +1587,67 @@ int tsx_uas_test(void) if (status != 0) return status; - /* TEST6_BRANCH_ID: retransmit last response in PROCEEDING state + /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state + * This only applies to non-reliable transports, + * since UAS transaction is destroyed as soon + * as final response is sent for reliable transports. */ - status = tsx_retransmit_last_response_test(TEST6_TITLE, - TEST6_BRANCH_ID, - TEST6_REQUEST_COUNT, - TEST6_STATUS_CODE); - if (status != 0) - return status; + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_retransmit_last_response_test(TEST6_TITLE, + TEST6_BRANCH_ID, + TEST6_REQUEST_COUNT, + TEST6_STATUS_CODE); + if (status != 0) + return status; + } /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test */ - status = tsx_final_response_retransmission_test(); if (status != 0) return status; /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must * cease when ACK is received + * Only applicable for non-reliable transports. */ - status = tsx_ack_test(); - if (status != 0) - return status; + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_ack_test(); + if (status != 0) + return status; + } + /* TEST10_BRANCH_ID: test transport failure in TRYING state. * TEST11_BRANCH_ID: test transport failure in PROCEEDING state. * TEST12_BRANCH_ID: test transport failure in CONNECTED state. * TEST13_BRANCH_ID: test transport failure in CONFIRMED state. */ - status = tsx_transport_failure_test(); - if (status != 0) - return status; + /* Only valid for loop-dgram */ + if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + status = tsx_transport_failure_test(); + if (status != 0) + return status; + } - pjsip_transport_dec_ref(loop); - return 0; + /* Register modules. */ + status = pjsip_endpt_unregister_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -8; + } + status = pjsip_endpt_unregister_module(endpt, &msg_sender); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -9; + } + + if (loop) + pjsip_transport_dec_ref(loop); + + return 0; } diff --git a/pjsip/src/test-pjsip/txdata_test.c b/pjsip/src/test-pjsip/txdata_test.c index d39fad42..a7f0fb0b 100644 --- a/pjsip/src/test-pjsip/txdata_test.c +++ b/pjsip/src/test-pjsip/txdata_test.c @@ -21,11 +21,19 @@ #include #include -#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) #define THIS_FILE "txdata_test.c" +#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) + +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP 10000 +#else +# define LOOP 100000 +#endif + + /* * This tests various core message creation functions. */ @@ -323,6 +331,77 @@ static int core_txdata_test(void) return 0; } + + +/* + * This test demonstrate the bug as reported in: + * http://bugzilla.pjproject.net/show_bug.cgi?id=49 + */ +static int gcc_test() +{ + char msgbuf[512]; + pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" + "?X-Hdr-1=Header%201" + "&X-Empty-Hdr="); + pjsip_tx_data *tdata; + pjsip_parser_err_report err_list; + pjsip_msg *msg; + int len; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " header param in URI to create request")); + + /* Create request with header param in target URI. */ + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, + &target, &target, &target, NULL, -1, + NULL, &tdata); + if (status != 0) { + app_perror(" error: Unable to create request", status); + return -200; + } + + /* Print and parse the request. + * We'll check that header params are not present in + */ + len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); + if (len < 1) { + PJ_LOG(3,(THIS_FILE, " error: printing message")); + pjsip_tx_data_dec_ref(tdata); + return -250; + } + msgbuf[len] = '\0'; + + PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" + "%s\n" + "--end-msg--", len, msgbuf)); + + /* Now parse the message. */ + pj_list_init(&err_list); + msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); + if (msg == NULL) { + pjsip_parser_err_report *e; + + PJ_LOG(3,(THIS_FILE, " error: parsing message message")); + + e = err_list.next; + while (e != &err_list) { + PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", + pj_exception_id_name(e->except_code), + e->line, e->col+1, + (int)e->hname.slen, + e->hname.ptr)); + e = e->next; + } + + pjsip_tx_data_dec_ref(tdata); + return -255; + } + + pjsip_tx_data_dec_ref(tdata); + return 0; +} + + /* This tests the request creating functions against the following * requirements: * - header params in URI creates header in the request. @@ -345,6 +424,8 @@ static int txdata_test_uri_params(void) pjsip_tx_data *tdata; pjsip_sip_uri *uri; pjsip_param *param; + pjsip_via_hdr *via; + pjsip_parser_err_report err_list; pjsip_msg *msg; int len; pj_status_t status; @@ -360,6 +441,11 @@ static int txdata_test_uri_params(void) return -200; } + /* Fill up the Via header to prevent syntax error on parsing */ + via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); + via->transport = pj_str("TCP"); + via->sent_by.host = pj_str("127.0.0.1"); + /* Print and parse the request. * We'll check that header params are not present in */ @@ -376,11 +462,25 @@ static int txdata_test_uri_params(void) "--end-msg--", len, msgbuf)); /* Now parse the message. */ - msg = pjsip_parse_msg( tdata->pool, msgbuf, len, NULL); + pj_list_init(&err_list); + msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); if (msg == NULL) { - app_perror(" error: parsing message message", status); + pjsip_parser_err_report *e; + + PJ_LOG(3,(THIS_FILE, " error: parsing message message")); + + e = err_list.next; + while (e != &err_list) { + PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", + pj_exception_id_name(e->except_code), + e->line, e->col+1, + (int)e->hname.slen, + e->hname.ptr)); + e = e->next; + } + pjsip_tx_data_dec_ref(tdata); - return -250; + return -256; } /* Check the existence of port, other_param, and header param. @@ -512,18 +612,233 @@ static int txdata_test_uri_params(void) return 0; } + +/* + * create request benchmark + */ +static int create_request_bench(pj_timestamp *p_elapsed) +{ + enum { COUNT = 100 }; + unsigned i, j; + pjsip_tx_data *tdata[COUNT]; + pj_timestamp t1, t2, elapsed; + pj_status_t status; + + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" "); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + elapsed.u64 = 0; + + for (i=0; iu64 = elapsed.u64; + return PJ_SUCCESS; + +on_error: + for (i=0; i"); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create several Via headers */ + via = pjsip_via_hdr_create(request->pool); + via->sent_by.host = pj_str("192.168.0.7"); + via->sent_by.port = 5061; + via->transport = pj_str("udp"); + via->rport_param = 0; + via->branch_param = pj_str("012345678901234567890123456789"); + via->recvd_param = pj_str("192.168.0.7"); + pjsip_msg_insert_first_hdr(request->msg, pjsip_hdr_clone(request->pool, via)); + pjsip_msg_insert_first_hdr(request->msg, pjsip_hdr_clone(request->pool, via)); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); + + + /* Create "dummy" rdata from the tdata */ + pj_memset(&rdata, 0, sizeof(pjsip_rx_data)); + rdata.tp_info.pool = request->pool; + rdata.msg_info.msg = request->msg; + rdata.msg_info.from = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.to = pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); + rdata.msg_info.cseq = pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); + rdata.msg_info.cid = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.via = via; + + /* + * Now benchmark create_response + */ + elapsed.u64 = 0; + + for (i=0; iu64 = elapsed.u64; + pjsip_tx_data_dec_ref(request); + return PJ_SUCCESS; + +on_error: + for (i=0; ipjsip_endpt_create_request()"); + + + /* + * Benchmark create_response() + */ + PJ_LOG(3,(THIS_FILE, " benchmarking response creation:")); + for (i=0; ipjsip_endpt_create_response()"); + + return 0; } + diff --git a/pjsip/src/test-pjsip/uri_test.c b/pjsip/src/test-pjsip/uri_test.c index a221f4ca..916a30f4 100644 --- a/pjsip/src/test-pjsip/uri_test.c +++ b/pjsip/src/test-pjsip/uri_test.c @@ -32,12 +32,19 @@ #define PARAM_CHAR ALPHANUM MARK "[]/:&+$" #define POOL_SIZE 8000 -#define LOOP_COUNT 10000 +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP_COUNT 10000 +#else +# define LOOP_COUNT 40000 +#endif #define AVERAGE_URL_LEN 80 #define THREAD_COUNT 4 -static pj_highprec_t parse_len, print_len, cmp_len; -static pj_timestamp parse_time, print_time, cmp_time; +static struct +{ + pj_highprec_t parse_len, print_len, cmp_len; + pj_timestamp parse_time, print_time, cmp_time; +} var; /* URI creator functions. */ @@ -686,7 +693,7 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) /* Parse URI text. */ pj_get_timestamp(&t1); - parse_len = parse_len + entry->len; + var.parse_len = var.parse_len + entry->len; parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0); if (!parsed_uri) { /* Parsing failed. If the entry says that this is expected, then @@ -702,7 +709,7 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&parse_time, &t2); + pj_add_timestamp(&var.parse_time, &t2); /* Create the reference URI. */ ref_uri = entry->creator(pool); @@ -720,10 +727,10 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) s1.ptr[len] = '\0'; s1.slen = len; - print_len = print_len + len; + var.print_len = var.print_len + len; pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&print_time, &t2); + pj_add_timestamp(&var.print_time, &t2); len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE); if (len < 1) { @@ -755,10 +762,10 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) } } - cmp_len = cmp_len + len; + var.cmp_len = var.cmp_len + len; pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&cmp_time, &t2); + pj_add_timestamp(&var.cmp_time, &t2); /* Compare text. */ if (entry->printed) { @@ -785,16 +792,12 @@ on_return: return status; } -int uri_test() + +static int simple_uri_test(void) { - unsigned i, loop; + unsigned i; pj_pool_t *pool; pj_status_t status; - pj_timestamp zero; - pj_time_val elapsed; - pj_highprec_t avg_parse, avg_print, avg_cmp, kbytes; - - zero.u32.hi = zero.u32.lo = 0; PJ_LOG(3,(THIS_FILE, " simple test")); pool = pjsip_endpt_create_pool(endpt, "", POOL_SIZE, POOL_SIZE); @@ -803,16 +806,31 @@ int uri_test() if (status != PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, " error %d when testing entry %d", status, i)); - goto on_return; + return status; } } pjsip_endpt_release_pool(endpt, pool); - PJ_LOG(3,(THIS_FILE, " benchmarking...")); - parse_len = print_len = cmp_len = 0; - parse_time.u32.hi = parse_time.u32.lo = 0; - print_time.u32.hi = print_time.u32.lo = 0; - cmp_time.u32.hi = cmp_time.u32.lo = 0; + return 0; +} + +static int uri_benchmark(unsigned *p_parse, unsigned *p_print, unsigned *p_cmp) +{ + unsigned i, loop; + pj_pool_t *pool; + pj_status_t status; + pj_timestamp zero; + pj_time_val elapsed; + pj_highprec_t avg_parse, avg_print, avg_cmp, kbytes; + + pj_memset(&var, 0, sizeof(var)); + + zero.u32.hi = zero.u32.lo = 0; + + var.parse_len = var.print_len = var.cmp_len = 0; + var.parse_time.u32.hi = var.parse_time.u32.lo = 0; + var.print_time.u32.hi = var.print_time.u32.lo = 0; + var.cmp_time.u32.hi = var.cmp_time.u32.lo = 0; for (loop=0; loop max) max = run[i].parse; + + PJ_LOG(3,("", " Maximum URI parse/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be parsed with " + "pjsip_parse_uri() per second " + "(tested with %d URI set, with average length of " + "%d chars)", + PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-parse-per-sec", max, "URI/sec", desc); + + /* URI parsing bandwidth */ + report_ival("uri-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "URI parsing bandwidth in megabytes (number of megabytes " + "worth of URI that can be parsed per second)"); + + + /* Print maximum print/sec */ + for (i=0, max=0; i max) max = run[i].print; + + PJ_LOG(3,("", " Maximum URI print/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be printed with " + "pjsip_uri_print() per second " + "(tested with %d URI set, with average length of " + "%d chars)", + PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-print-per-sec", max, "URI/sec", desc); + + /* Print maximum detect/sec */ + for (i=0, max=0; i max) max = run[i].cmp; + + PJ_LOG(3,("", " Maximum URI comparison/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be compared with " + "pjsip_uri_cmp() per second " + "(tested with %d URI set, with average length of " + "%d chars)", + PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-cmp-per-sec", max, "URI/sec", desc); + + return PJ_SUCCESS; +} + -- cgit v1.2.3