summaryrefslogtreecommitdiff
path: root/pjsip/src/test-pjsip
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip/src/test-pjsip')
-rw-r--r--pjsip/src/test-pjsip/main.c15
-rw-r--r--pjsip/src/test-pjsip/msg_logger.c12
-rw-r--r--pjsip/src/test-pjsip/msg_test.c191
-rw-r--r--pjsip/src/test-pjsip/test.c195
-rw-r--r--pjsip/src/test-pjsip/test.h37
-rw-r--r--pjsip/src/test-pjsip/transport_loop_test.c29
-rw-r--r--pjsip/src/test-pjsip/transport_tcp_test.c143
-rw-r--r--pjsip/src/test-pjsip/transport_test.c13
-rw-r--r--pjsip/src/test-pjsip/transport_udp_test.c16
-rw-r--r--pjsip/src/test-pjsip/tsx_basic_test.c19
-rw-r--r--pjsip/src/test-pjsip/tsx_bench.c273
-rw-r--r--pjsip/src/test-pjsip/tsx_uac_test.c210
-rw-r--r--pjsip/src/test-pjsip/tsx_uas_test.c168
-rw-r--r--pjsip/src/test-pjsip/txdata_test.c323
-rw-r--r--pjsip/src/test-pjsip/uri_test.c185
15 files changed, 1600 insertions, 229 deletions
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 <string.h>
#include <stdlib.h>
+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("<Press ENTER to quit>\n");
+ printf("<Press ENTER to quit>\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 <pjlib.h>
#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<PJ_ARRAY_SIZE(test_array); ++i) {
+ pj_pool_t *pool;
pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE);
status = test_entry( pool, &test_array[i] );
pjsip_endpt_release_pool(endpt, pool);
@@ -693,10 +696,24 @@ int msg_test(void)
return status;
}
- PJ_LOG(3,(THIS_FILE, " benchmarking.."));
- detect_len = parse_len = print_len = 0;
- zero.u64 = detect_time.u64 = parse_time.u64 = print_time.u64 = 0;
-
+ return PJ_SUCCESS;
+}
+
+
+static int msg_benchmark(unsigned *p_detect, unsigned *p_parse,
+ unsigned *p_print)
+{
+ 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_memset(&var, 0, sizeof(var));
+ zero.u64 = 0;
+
for (loop=0; loop<LOOP; ++loop) {
for (i=0; i<PJ_ARRAY_SIZE(test_array); ++i) {
pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE);
@@ -708,52 +725,144 @@ int msg_test(void)
}
}
- kbytes = detect_len;
+ kbytes = var.detect_len;
pj_highprec_mod(kbytes, 1000000);
pj_highprec_div(kbytes, 100000);
- elapsed = pj_elapsed_time(&zero, &detect_time);
- avg_detect = pj_elapsed_usec(&zero, &detect_time);
+ elapsed = pj_elapsed_time(&zero, &var.detect_time);
+ avg_detect = pj_elapsed_usec(&zero, &var.detect_time);
pj_highprec_mul(avg_detect, AVERAGE_MSG_LEN);
- pj_highprec_div(avg_detect, detect_len);
+ pj_highprec_div(avg_detect, var.detect_len);
avg_detect = 1000000 / avg_detect;
PJ_LOG(3,(THIS_FILE,
" %u.%u MB detected in %d.%03ds (avg=%d msg detection/sec)",
- (unsigned)(detect_len/1000000), (unsigned)kbytes,
+ (unsigned)(var.detect_len/1000000), (unsigned)kbytes,
elapsed.sec, elapsed.msec,
(unsigned)avg_detect));
+ *p_detect = (unsigned)avg_detect;
- kbytes = parse_len;
+ kbytes = var.parse_len;
pj_highprec_mod(kbytes, 1000000);
pj_highprec_div(kbytes, 100000);
- elapsed = pj_elapsed_time(&zero, &parse_time);
- avg_parse = pj_elapsed_usec(&zero, &parse_time);
+ elapsed = pj_elapsed_time(&zero, &var.parse_time);
+ avg_parse = pj_elapsed_usec(&zero, &var.parse_time);
pj_highprec_mul(avg_parse, AVERAGE_MSG_LEN);
- pj_highprec_div(avg_parse, parse_len);
+ pj_highprec_div(avg_parse, var.parse_len);
avg_parse = 1000000 / avg_parse;
PJ_LOG(3,(THIS_FILE,
" %u.%u MB parsed in %d.%03ds (avg=%d msg parsing/sec)",
- (unsigned)(parse_len/1000000), (unsigned)kbytes,
+ (unsigned)(var.parse_len/1000000), (unsigned)kbytes,
elapsed.sec, elapsed.msec,
(unsigned)avg_parse));
+ *p_parse = (unsigned)avg_parse;
- kbytes = print_len;
+ kbytes = var.print_len;
pj_highprec_mod(kbytes, 1000000);
pj_highprec_div(kbytes, 100000);
- elapsed = pj_elapsed_time(&zero, &print_time);
- avg_print = pj_elapsed_usec(&zero, &print_time);
+ elapsed = pj_elapsed_time(&zero, &var.print_time);
+ avg_print = pj_elapsed_usec(&zero, &var.print_time);
pj_highprec_mul(avg_print, AVERAGE_MSG_LEN);
- pj_highprec_div(avg_print, print_len);
+ pj_highprec_div(avg_print, var.print_len);
avg_print = 1000000 / avg_print;
PJ_LOG(3,(THIS_FILE,
" %u.%u MB printed in %d.%03ds (avg=%d msg print/sec)",
- (unsigned)(print_len/1000000), (unsigned)kbytes,
+ (unsigned)(var.print_len/1000000), (unsigned)kbytes,
elapsed.sec, elapsed.msec,
(unsigned)avg_print));
+ *p_print = (unsigned)avg_print;
return status;
}
/*****************************************************************************/
+
+int msg_test(void)
+{
+ enum { COUNT = 4, DETECT=0, PARSE=1, PRINT=2 };
+ struct {
+ unsigned detect;
+ unsigned parse;
+ unsigned print;
+ } run[COUNT];
+ unsigned i, max, avg_len;
+ char desc[250];
+ pj_status_t status;
+
+
+ status = simple_test();
+ if (status != PJ_SUCCESS)
+ return status;
+
+ for (i=0; i<COUNT; ++i) {
+ PJ_LOG(3,(THIS_FILE, " benchmarking (%d of %d)..", i+1, COUNT));
+ status = msg_benchmark(&run[i].detect, &run[i].parse, &run[i].print);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ /* Calculate average message length */
+ for (i=0, avg_len=0; i<PJ_ARRAY_SIZE(test_array); ++i) {
+ avg_len += test_array[i].len;
+ }
+ avg_len /= PJ_ARRAY_SIZE(test_array);
+
+
+ /* Print maximum detect/sec */
+ for (i=0, max=0; i<COUNT; ++i)
+ if (run[i].detect > 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 <tt>pjsip_find_msg()</tt> "
+ "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<COUNT; ++i)
+ if (run[i].parse > max) max = run[i].parse;
+
+ PJ_LOG(3,("", " Maximum message parsing/sec=%u", max));
+
+ pj_ansi_sprintf(desc, "Number of SIP messages "
+ "can be <b>parsed</b> by <tt>pjsip_parse_msg()</tt> "
+ "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<COUNT; ++i)
+ if (run[i].print > max) max = run[i].print;
+
+ PJ_LOG(3,("", " Maximum message print/sec=%u", max));
+
+ pj_ansi_sprintf(desc, "Number of SIP messages "
+ "can be <b>printed</b> by <tt>pjsip_msg_print()</tt>"
+ " 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, "<HTML>\n"
+ " <HEAD>\n"
+ " <TITLE>PJSIP %s (%s) - Static Benchmark</TITLE>\n"
+ " </HEAD>\n"
+ "<BODY>\n"
+ "\n",
+ PJ_VERSION,
+ (PJ_DEBUG ? "Debug" : "Release"));
+ pj_file_write(fd_report, buf, &len);
+
+
+ /* Title */
+ len = pj_ansi_sprintf(buf, "<H1>PJSIP %s (%s) - Static Benchmark</H1>\n",
+ PJ_VERSION,
+ (PJ_DEBUG ? "Debug" : "Release"));
+ pj_file_write(fd_report, buf, &len);
+
+ len = pj_ansi_sprintf(buf, "<P>Below is the benchmark result generated "
+ "by <b>test-pjsip</b> program. The program "
+ "is single-threaded only.</P>\n");
+ pj_file_write(fd_report, buf, &len);
+
+
+ /* Write table heading */
+ len = pj_ansi_sprintf(buf, "<TABLE border=\"1\" cellpadding=\"4\">\n"
+ " <TR><TD bgColor=\"aqua\" align=\"center\">Variable</TD>\n"
+ " <TD bgColor=\"aqua\" align=\"center\">Value</TD>\n"
+ " <TD bgColor=\"aqua\" align=\"center\">Description</TD>\n"
+ " </TR>\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(&timestamp);
+ report_ival("timestamp", timestamp.sec, "", "System timestamp of the test");
+
+
+ /* Write time of day */
+ pj_time_decode(&timestamp, &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, " <TR><TD><TT>%s</TT></TD>\n"
+ " <TD align=\"right\"><B>%s %s</B></TD>\n"
+ " <TD>%s</TD>\n"
+ " </TR>\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, " <TR><TD><TT>%s</TT></TD>\n"
+ " <TD align=\"right\"><B>%d %s</B></TD>\n"
+ " <TD>%s</TD>\n"
+ " </TR>\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, "</TABLE>\n</BODY>\n</HTML>\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; i<tsx_test_cnt; ++i) {
+ DO_TSX_TEST(tsx_basic_test, &tsx_test[i]);
+ DO_TSX_TEST(tsx_uac_test, &tsx_test[i]);
+ DO_TSX_TEST(tsx_uas_test, &tsx_test[i]);
+ }
#endif
on_return:
-
+ flush_events(500);
pjsip_endpt_destroy(endpt);
pj_caching_pool_destroy(&caching_pool);
@@ -169,6 +354,8 @@ on_return:
else
PJ_LOG(3,(THIS_FILE, "Test completed with error(s)"));
+ report_ival("test-status", rc, "", "Overall test status/result (0==success)");
+ close_report();
return rc;
}
diff --git a/pjsip/src/test-pjsip/test.h b/pjsip/src/test-pjsip/test.h
index f2b6b91d..969b341a 100644
--- a/pjsip/src/test-pjsip/test.h
+++ b/pjsip/src/test-pjsip/test.h
@@ -31,13 +31,22 @@ extern pjsip_endpoint *endpt;
#define INCLUDE_TRANSPORT_GROUP 1
#define INCLUDE_TSX_GROUP 1
+/*
+ * Include tests that normally would fail under certain gcc
+ * optimization levels.
+ */
+#ifndef INCLUDE_GCC_TEST
+# define INCLUDE_GCC_TEST 0
+#endif
#define INCLUDE_URI_TEST INCLUDE_MESSAGING_GROUP
#define INCLUDE_MSG_TEST INCLUDE_MESSAGING_GROUP
#define INCLUDE_TXDATA_TEST INCLUDE_MESSAGING_GROUP
+#define INCLUDE_TSX_BENCH INCLUDE_MESSAGING_GROUP
#define INCLUDE_UDP_TEST INCLUDE_TRANSPORT_GROUP
#define INCLUDE_LOOP_TEST INCLUDE_TRANSPORT_GROUP
+#define INCLUDE_TCP_TEST INCLUDE_TRANSPORT_GROUP
#define INCLUDE_TSX_TEST INCLUDE_TSX_GROUP
@@ -47,17 +56,28 @@ int uri_test(void);
int msg_test(void);
int msg_err_test(void);
int txdata_test(void);
+int tsx_bench(void);
int transport_udp_test(void);
int transport_loop_test(void);
-int tsx_basic_test(void);
-int tsx_uac_test(void);
-int tsx_uas_test(void);
+int transport_tcp_test(void);
+
+struct tsx_test_param
+{
+ int type;
+ int port;
+ char *tp_type;
+};
+
+int tsx_basic_test(struct tsx_test_param *param);
+int tsx_uac_test(struct tsx_test_param *param);
+int tsx_uas_test(struct tsx_test_param *param);
/* Transport test helpers (transport_test.c). */
int generic_transport_test(pjsip_transport *tp);
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);
int transport_rt_test( pjsip_transport_type_e tp_type,
pjsip_transport *ref_tp,
char *target_url,
@@ -68,10 +88,15 @@ int test_main(void);
/* Test utilities. */
void app_perror(const char *msg, pj_status_t status);
-int init_msg_logger(void);
-int msg_logger_set_enabled(pj_bool_t enabled);
+int init_msg_logger(void);
+int msg_logger_set_enabled(pj_bool_t enabled);
void flush_events(unsigned duration);
+
+void report_ival(const char *name, int value, const char *valname, const char *desc);
+void report_sval(const char *name, const char* value, const char *valname, const char *desc);
+
+
/* Settings. */
extern int log_level;
diff --git a/pjsip/src/test-pjsip/transport_loop_test.c b/pjsip/src/test-pjsip/transport_loop_test.c
index 351fb7b6..3e378832 100644
--- a/pjsip/src/test-pjsip/transport_loop_test.c
+++ b/pjsip/src/test-pjsip/transport_loop_test.c
@@ -25,10 +25,13 @@
static int datagram_loop_test()
{
+ enum { LOOP = 8 };
pjsip_transport *loop;
int i, pkt_lost;
pj_sockaddr_in addr;
pj_status_t status;
+ long ref_cnt;
+ unsigned rtt[LOOP], min_rtt;
PJ_LOG(3,(THIS_FILE, "testing datagram loop transport"));
@@ -40,19 +43,33 @@ static int datagram_loop_test()
return -20;
}
+ /* Get initial reference counter */
+ ref_cnt = pj_atomic_get(loop->ref_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; i<LOOP; ++i) {
status = transport_send_recv_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop,
- "sip:bob@130.0.0.1;transport=loop-dgram");
+ "sip:bob@130.0.0.1;transport=loop-dgram",
+ &rtt[i]);
if (status != 0)
return status;
}
+ min_rtt = 0xFFFFFFF;
+ for (i=0; i<LOOP; ++i)
+ if (rtt[i] < min_rtt) min_rtt = rtt[i];
+
+ report_ival("loop-rtt-usec", min_rtt, "usec",
+ "Best Loopback transport round trip time, in microseconds "
+ "(time from sending request until response is received. "
+ "Tests were performed on local machine only)");
+
+
/* Multi-threaded round-trip test. */
status = transport_rt_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop,
"sip:bob@130.0.0.1;transport=loop-dgram",
@@ -84,9 +101,11 @@ static int datagram_loop_test()
/* Restore delay. */
pjsip_loop_set_delay(loop, 0);
- /* Check that reference counter is one. */
- if (pj_atomic_get(loop->ref_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 <benny@prijono.org>
+ *
+ * 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 <pjsip.h>
+#include <pjlib.h>
+
+#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; i<SEND_RECV_LOOP; ++i) {
+ status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp, url, &rtt[i]);
+
+ if (status != 0) {
+ pjsip_transport_dec_ref(tcp);
+ flush_events(500);
+ return -72;
+ }
+ }
+
+ min_rtt = 0xFFFFFFF;
+ for (i=0; i<SEND_RECV_LOOP; ++i)
+ if (rtt[i] < min_rtt) min_rtt = rtt[i];
+
+ report_ival("tcp-rtt-usec", min_rtt, "usec",
+ "Best TCP transport round trip time, in microseconds "
+ "(time from sending request until response is received. "
+ "Tests were performed on local machine only, and after "
+ "TCP socket has been established by previous test)");
+
+
+ /* Multi-threaded round-trip test. */
+ status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp, url, &pkt_lost);
+ if (status != 0) {
+ pjsip_transport_dec_ref(tcp);
+ return status;
+ }
+
+ if (pkt_lost != 0)
+ PJ_LOG(3,(THIS_FILE, " note: %d packet(s) was lost", pkt_lost));
+
+ /* Check again that reference counter is still 1. */
+ if (pj_atomic_get(tcp->ref_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; i<SEND_RECV_LOOP; ++i) {
status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp,
- "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR);
+ "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR,
+ &rtt[i]);
if (status != 0)
return status;
}
+ min_rtt = 0xFFFFFFF;
+ for (i=0; i<SEND_RECV_LOOP; ++i)
+ if (rtt[i] < min_rtt) min_rtt = rtt[i];
+
+ report_ival("udp-rtt-usec", min_rtt, "usec",
+ "Best UDP transport round trip time, in microseconds "
+ "(time from sending request until response is received. "
+ "Tests were performed on local machine only)");
+
+
/* Multi-threaded round-trip test. */
status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp,
"sip:alice@127.0.0.1:"TEST_UDP_PORT_STR,
diff --git a/pjsip/src/test-pjsip/tsx_basic_test.c b/pjsip/src/test-pjsip/tsx_basic_test.c
index 6be0ea2a..afe72279 100644
--- a/pjsip/src/test-pjsip/tsx_basic_test.c
+++ b/pjsip/src/test-pjsip/tsx_basic_test.c
@@ -23,6 +23,10 @@
#define THIS_FILE "tsx_basic_test.c"
+static char TARGET_URI[128];
+static char FROM_URI[128];
+
+
/* Test transaction layer. */
static int tsx_layer_test(void)
{
@@ -33,8 +37,8 @@ static int tsx_layer_test(void)
PJ_LOG(3,(THIS_FILE, " transaction layer test"));
- target = pj_str("sip:alice@localhost");
- from = pj_str("sip:bob@localhost");
+ target = pj_str(TARGET_URI);
+ from = pj_str(FROM_URI);
status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target,
&from, &target, NULL, NULL, -1, NULL,
@@ -77,8 +81,8 @@ static int double_terminate(void)
PJ_LOG(3,(THIS_FILE, " double terminate test"));
- target = pj_str("sip:alice@localhost;transport=loop-dgram");
- from = pj_str("sip:bob@localhost");
+ target = pj_str(TARGET_URI);
+ from = pj_str(FROM_URI);
/* Create request. */
status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target,
@@ -131,10 +135,15 @@ static int double_terminate(void)
return PJ_SUCCESS;
}
-int tsx_basic_test(void)
+int tsx_basic_test(struct tsx_test_param *param)
{
int status;
+ 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);
+
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 <benny@prijono.org>
+ *
+ * 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 <pjsip.h>
+#include <pjlib.h>
+
+#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\" <sip:localuser@serviceprovider.com>");
+ pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>");
+ 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; i<working_set; ++i) {
+ status = pjsip_tsx_create_uac(&mod_tsx_user, request, &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; i<working_set; ++i) {
+ if (tsx[i]) {
+ pjsip_tsx_terminate(tsx[i], 601);
+ tsx[i] = NULL;
+ }
+ }
+ pjsip_tx_data_dec_ref(request);
+ flush_events(2000);
+ return status;
+}
+
+
+
+static int uas_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed)
+{
+ unsigned i;
+ pjsip_tx_data *request;
+ pjsip_via_hdr *via;
+ pjsip_rx_data rdata;
+ pj_sockaddr_in remote;
+ pjsip_transaction **tsx;
+ pj_timestamp t1, t2, elapsed;
+ char branch_buf[80] = PJSIP_RFC3261_BRANCH_ID "0000000000";
+ 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\" <sip:localuser@serviceprovider.com>");
+ pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>");
+ 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; i<working_set; ++i) {
+ via->branch_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; i<working_set; ++i) {
+ if (tsx[i]) {
+ pjsip_tsx_terminate(tsx[i], 601);
+ tsx[i] = NULL;
+ }
+ }
+ pjsip_tx_data_dec_ref(request);
+ flush_events(2000);
+ return status;
+}
+
+
+
+int tsx_bench(void)
+{
+ enum { WORKING_SET=PJSIP_MAX_TSX_COUNT, REPEAT = 4 };
+ unsigned i, speed;
+ pj_timestamp usec[REPEAT], min, freq;
+ char desc[250];
+ int status;
+
+ status = pj_get_timestamp_freq(&freq);
+ if (status != PJ_SUCCESS)
+ return status;
+
+
+ /*
+ * Benchmark UAC
+ */
+ PJ_LOG(3,(THIS_FILE, " benchmarking UAC transaction creation:"));
+ for (i=0; i<REPEAT; ++i) {
+ PJ_LOG(3,(THIS_FILE, " test %d of %d..",
+ i+1, REPEAT));
+ status = uac_tsx_bench(WORKING_SET, &usec[i]);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF);
+ for (i=0; i<REPEAT; ++i) {
+ if (usec[i].u64 < min.u64) min.u64 = usec[i].u64;
+ }
+
+
+ /* Report time */
+ pj_ansi_sprintf(desc, "Time to create %d UAC transactions, in miliseconds",
+ WORKING_SET);
+ report_ival("create-uac-time", (unsigned)(min.u64 * 1000 / freq.u64), "msec", desc);
+
+
+ /* Write speed */
+ speed = (unsigned)(freq.u64 * WORKING_SET / min.u64);
+ PJ_LOG(3,(THIS_FILE, " UAC created at %d tsx/sec", speed));
+
+ pj_ansi_sprintf(desc, "Number of UAC transactions that potentially can be created per second "
+ "with <tt>pjsip_tsx_create_uac()</tt>, 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; i<REPEAT; ++i) {
+ PJ_LOG(3,(THIS_FILE, " test %d of %d..",
+ i+1, REPEAT));
+ status = uas_tsx_bench(WORKING_SET, &usec[i]);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF);
+ for (i=0; i<REPEAT; ++i) {
+ if (usec[i].u64 < min.u64) min.u64 = usec[i].u64;
+ }
+
+
+ /* Report time */
+ pj_ansi_sprintf(desc, "Time to create %d UAS transactions, in miliseconds",
+ WORKING_SET);
+ report_ival("create-uas-time", (unsigned)(min.u64 * 1000 / freq.u64), "msec", desc);
+
+
+ /* Write speed */
+ speed = (unsigned)(freq.u64 * WORKING_SET / min.u64);
+ PJ_LOG(3,(THIS_FILE, " UAS created at %d tsx/sec", speed));
+
+ pj_ansi_sprintf(desc, "Number of UAS transactions that potentially can be created per second "
+ "with <tt>pjsip_tsx_create_uas()</tt>, 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; i<PJ_ARRAY_SIZE(delay); ++i) {
- PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay",
- ('a'+i), delay[i]));
+ if (test_param->type == 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 <pjsip.h>
#include <pjlib.h>
-#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\" <sip:localuser@serviceprovider.com>");
+ pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>");
+ pj_str_t str_contact = str_from;
+
+ elapsed.u64 = 0;
+
+ for (i=0; i<LOOP; i+=COUNT) {
+ pj_memset(tdata, 0, sizeof(tdata));
+
+ pj_get_timestamp(&t1);
+
+ for (j=0; j<COUNT; ++j) {
+ status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
+ &str_target, &str_from, &str_to,
+ &str_contact, NULL, -1, NULL,
+ &tdata[j]);
+ if (status != PJ_SUCCESS) {
+ app_perror(" error: unable to create request", status);
+ goto on_error;
+ }
+ }
+
+ pj_get_timestamp(&t2);
+ pj_sub_timestamp(&t2, &t1);
+ pj_add_timestamp(&elapsed, &t2);
+
+ for (j=0; j<COUNT; ++j)
+ pjsip_tx_data_dec_ref(tdata[j]);
+ }
+
+ p_elapsed->u64 = elapsed.u64;
+ return PJ_SUCCESS;
+
+on_error:
+ for (i=0; i<COUNT; ++i) {
+ if (tdata[i])
+ pjsip_tx_data_dec_ref(tdata[i]);
+ }
+ return -400;
+}
+
+
+
+/*
+ * create response benchmark
+ */
+static int create_response_bench(pj_timestamp *p_elapsed)
+{
+ enum { COUNT = 100 };
+ unsigned i, j;
+ pjsip_via_hdr *via;
+ pjsip_rx_data rdata;
+ pjsip_tx_data *request;
+ pjsip_tx_data *tdata[COUNT];
+ 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\" <sip:localuser@serviceprovider.com>");
+ pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>");
+ 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; i<LOOP; i+=COUNT) {
+ pj_memset(tdata, 0, sizeof(tdata));
+
+ pj_get_timestamp(&t1);
+
+ for (j=0; j<COUNT; ++j) {
+ status = pjsip_endpt_create_response(endpt, &rdata, 200, NULL, &tdata[j]);
+ if (status != PJ_SUCCESS) {
+ app_perror(" error: unable to create request", status);
+ goto on_error;
+ }
+ }
+
+ pj_get_timestamp(&t2);
+ pj_sub_timestamp(&t2, &t1);
+ pj_add_timestamp(&elapsed, &t2);
+
+ for (j=0; j<COUNT; ++j)
+ pjsip_tx_data_dec_ref(tdata[j]);
+ }
+
+ p_elapsed->u64 = elapsed.u64;
+ pjsip_tx_data_dec_ref(request);
+ return PJ_SUCCESS;
+
+on_error:
+ for (i=0; i<COUNT; ++i) {
+ if (tdata[i])
+ pjsip_tx_data_dec_ref(tdata[i]);
+ }
+ return -400;
+}
+
+
int txdata_test(void)
{
+ enum { REPEAT = 4 };
+ unsigned i, msgs;
+ pj_timestamp usec[REPEAT], min, freq;
int status;
+ status = pj_get_timestamp_freq(&freq);
+ if (status != PJ_SUCCESS)
+ return status;
+
status = core_txdata_test();
if (status != 0)
return status;
+#if INCLUDE_GCC_TEST
+ status = gcc_test();
+ if (status != 0)
+ return status;
+#endif
status = txdata_test_uri_params();
if (status != 0)
return status;
+
+ /*
+ * Benchmark create_request()
+ */
+ PJ_LOG(3,(THIS_FILE, " benchmarking request creation:"));
+ for (i=0; i<REPEAT; ++i) {
+ PJ_LOG(3,(THIS_FILE, " test %d of %d..",
+ i+1, REPEAT));
+ status = create_request_bench(&usec[i]);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF);
+ for (i=0; i<REPEAT; ++i) {
+ if (usec[i].u64 < min.u64) min.u64 = usec[i].u64;
+ }
+
+ msgs = (unsigned)(freq.u64 * LOOP / min.u64);
+
+ PJ_LOG(3,(THIS_FILE, " Requests created at %d requests/sec", msgs));
+
+ report_ival("create-request-per-sec",
+ msgs, "msg/sec",
+ "Number of typical request messages that can be created "
+ "per second with <tt>pjsip_endpt_create_request()</tt>");
+
+
+ /*
+ * Benchmark create_response()
+ */
+ PJ_LOG(3,(THIS_FILE, " benchmarking response creation:"));
+ for (i=0; i<REPEAT; ++i) {
+ PJ_LOG(3,(THIS_FILE, " test %d of %d..",
+ i+1, REPEAT));
+ status = create_response_bench(&usec[i]);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF);
+ for (i=0; i<REPEAT; ++i) {
+ if (usec[i].u64 < min.u64) min.u64 = usec[i].u64;
+ }
+
+ msgs = (unsigned)(freq.u64 * LOOP / min.u64);
+
+ PJ_LOG(3,(THIS_FILE, " Responses created at %d responses/sec", msgs));
+
+ report_ival("create-response-per-sec",
+ msgs, "msg/sec",
+ "Number of typical response messages that can be created "
+ "per second with <tt>pjsip_endpt_create_response()</tt>");
+
+
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<LOOP_COUNT; ++loop) {
pool = pjsip_endpt_create_pool(endpt, "", POOL_SIZE, POOL_SIZE);
for (i=0; i<PJ_ARRAY_SIZE(uri_test_array); ++i) {
@@ -827,55 +845,144 @@ int uri_test()
pjsip_endpt_release_pool(endpt, pool);
}
- kbytes = parse_len;
+ kbytes = var.parse_len;
pj_highprec_mod(kbytes, 1000000);
pj_highprec_div(kbytes, 100000);
- elapsed = pj_elapsed_time(&zero, &parse_time);
- avg_parse = pj_elapsed_usec(&zero, &parse_time);
+ elapsed = pj_elapsed_time(&zero, &var.parse_time);
+ avg_parse = pj_elapsed_usec(&zero, &var.parse_time);
pj_highprec_mul(avg_parse, AVERAGE_URL_LEN);
- pj_highprec_div(avg_parse, parse_len);
+ pj_highprec_div(avg_parse, var.parse_len);
avg_parse = 1000000 / avg_parse;
PJ_LOG(3,(THIS_FILE,
" %u.%u MB of urls parsed in %d.%03ds (avg=%d urls/sec)",
- (unsigned)(parse_len/1000000), (unsigned)kbytes,
+ (unsigned)(var.parse_len/1000000), (unsigned)kbytes,
elapsed.sec, elapsed.msec,
(unsigned)avg_parse));
- kbytes = print_len;
+ *p_parse = (unsigned)avg_parse;
+
+ kbytes = var.print_len;
pj_highprec_mod(kbytes, 1000000);
pj_highprec_div(kbytes, 100000);
- elapsed = pj_elapsed_time(&zero, &print_time);
- avg_print = pj_elapsed_usec(&zero, &print_time);
+ elapsed = pj_elapsed_time(&zero, &var.print_time);
+ avg_print = pj_elapsed_usec(&zero, &var.print_time);
pj_highprec_mul(avg_print, AVERAGE_URL_LEN);
- pj_highprec_div(avg_print, parse_len);
+ pj_highprec_div(avg_print, var.parse_len);
avg_print = 1000000 / avg_print;
PJ_LOG(3,(THIS_FILE,
" %u.%u MB of urls printed in %d.%03ds (avg=%d urls/sec)",
- (unsigned)(print_len/1000000), (unsigned)kbytes,
+ (unsigned)(var.print_len/1000000), (unsigned)kbytes,
elapsed.sec, elapsed.msec,
(unsigned)avg_print));
- kbytes = cmp_len;
+ *p_print = (unsigned)avg_print;
+
+ kbytes = var.cmp_len;
pj_highprec_mod(kbytes, 1000000);
pj_highprec_div(kbytes, 100000);
- elapsed = pj_elapsed_time(&zero, &cmp_time);
- avg_cmp = pj_elapsed_usec(&zero, &cmp_time);
+ elapsed = pj_elapsed_time(&zero, &var.cmp_time);
+ avg_cmp = pj_elapsed_usec(&zero, &var.cmp_time);
pj_highprec_mul(avg_cmp, AVERAGE_URL_LEN);
- pj_highprec_div(avg_cmp, cmp_len);
+ pj_highprec_div(avg_cmp, var.cmp_len);
avg_cmp = 1000000 / avg_cmp;
PJ_LOG(3,(THIS_FILE,
" %u.%u MB of urls compared in %d.%03ds (avg=%d urls/sec)",
- (unsigned)(cmp_len/1000000), (unsigned)kbytes,
+ (unsigned)(var.cmp_len/1000000), (unsigned)kbytes,
elapsed.sec, elapsed.msec,
(unsigned)avg_cmp));
- PJ_LOG(3,(THIS_FILE, " multithreaded test"));
-
+ *p_cmp = (unsigned)avg_cmp;
on_return:
return status;
}
+
+/*****************************************************************************/
+
+int uri_test(void)
+{
+ enum { COUNT = 4, DETECT=0, PARSE=1, PRINT=2 };
+ struct {
+ unsigned parse;
+ unsigned print;
+ unsigned cmp;
+ } run[COUNT];
+ unsigned i, max, avg_len;
+ char desc[200];
+ pj_status_t status;
+
+ status = simple_uri_test();
+ if (status != PJ_SUCCESS)
+ return status;
+
+ for (i=0; i<COUNT; ++i) {
+ PJ_LOG(3,(THIS_FILE, " benchmarking (%d of %d)...", i+1, COUNT));
+ status = uri_benchmark(&run[i].parse, &run[i].print, &run[i].cmp);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ /* Calculate average URI length */
+ for (i=0, avg_len=0; i<PJ_ARRAY_SIZE(uri_test_array); ++i) {
+ avg_len += uri_test_array[i].len;
+ }
+ avg_len /= PJ_ARRAY_SIZE(uri_test_array);
+
+
+ /*
+ * Print maximum parse/sec
+ */
+ for (i=0, max=0; i<COUNT; ++i)
+ if (run[i].parse > 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 <B>parsed</B> with "
+ "<tt>pjsip_parse_uri()</tt> 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<COUNT; ++i)
+ if (run[i].print > 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 <B>printed</B> with "
+ "<tt>pjsip_uri_print()</tt> 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<COUNT; ++i)
+ if (run[i].cmp > 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 <B>compared</B> with "
+ "<tt>pjsip_uri_cmp()</tt> 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;
+}
+