summaryrefslogtreecommitdiff
path: root/pjnath/src/pjnath-test
diff options
context:
space:
mode:
Diffstat (limited to 'pjnath/src/pjnath-test')
-rw-r--r--pjnath/src/pjnath-test/concur_test.c367
-rw-r--r--pjnath/src/pjnath-test/ice_test.c241
-rw-r--r--pjnath/src/pjnath-test/sess_auth.c6
-rw-r--r--pjnath/src/pjnath-test/stun_sock_test.c14
-rw-r--r--pjnath/src/pjnath-test/test.c35
-rw-r--r--pjnath/src/pjnath-test/test.h6
6 files changed, 623 insertions, 46 deletions
diff --git a/pjnath/src/pjnath-test/concur_test.c b/pjnath/src/pjnath-test/concur_test.c
new file mode 100644
index 0000000..bf54e94
--- /dev/null
+++ b/pjnath/src/pjnath-test/concur_test.c
@@ -0,0 +1,367 @@
+/* $Id: concur_test.c 4412 2013-03-05 03:12:32Z riza $ */
+/*
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 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"
+
+#if INCLUDE_CONCUR_TEST
+
+#define THIS_FILE "concur_test.c"
+
+/****************************************************************************/
+#define WORKER_THREAD_CNT 4
+#define SERVER_THREAD_CNT 4
+#define MAX_SOCK_CLIENTS 80
+
+struct stun_test_session
+{
+ pj_stun_config stun_cfg;
+
+ pj_lock_t *lock;
+
+ pj_thread_t *worker_threads[WORKER_THREAD_CNT];
+
+ pj_sock_t server_sock;
+ int server_port;
+ pj_thread_t *server_threads[SERVER_THREAD_CNT];
+ pj_event_t *server_event;
+
+ pj_bool_t thread_quit_flag;
+
+ /* Test parameters: */
+ struct {
+ int client_got_response;
+
+ pj_bool_t server_wait_for_event;
+ pj_bool_t server_drop_request;
+ int client_sleep_after_start;
+ int client_sleep_before_destroy;
+ } param;
+};
+
+static int server_thread_proc(void *p)
+{
+ struct stun_test_session *test_sess = (struct stun_test_session*)p;
+ pj_pool_t *pool;
+ pj_status_t status;
+
+ PJ_LOG(4,(THIS_FILE, "Server thread running"));
+
+ pool = pj_pool_create(test_sess->stun_cfg.pf, "server", 512, 512, NULL);
+
+ while (!test_sess->thread_quit_flag) {
+ pj_time_val timeout = {0, 10};
+ pj_fd_set_t rdset;
+ int n;
+
+ /* Serve client */
+ PJ_FD_ZERO(&rdset);
+ PJ_FD_SET(test_sess->server_sock, &rdset);
+ n = pj_sock_select(test_sess->server_sock+1, &rdset,
+ NULL, NULL, &timeout);
+ if (n==1 && PJ_FD_ISSET(test_sess->server_sock, &rdset)) {
+ pj_uint8_t pkt[512];
+ pj_ssize_t pkt_len;
+ pj_size_t res_len;
+ pj_sockaddr client_addr;
+ int addr_len;
+
+ pj_stun_msg *stun_req, *stun_res;
+
+ pj_pool_reset(pool);
+
+ /* Got query */
+ pkt_len = sizeof(pkt);
+ addr_len = sizeof(client_addr);
+ status = pj_sock_recvfrom(test_sess->server_sock, pkt, &pkt_len,
+ 0, &client_addr, &addr_len);
+ if (status != PJ_SUCCESS) {
+ continue;
+ }
+
+ status = pj_stun_msg_decode(pool, pkt, pkt_len,
+ PJ_STUN_IS_DATAGRAM,
+ &stun_req, NULL, NULL);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "STUN request decode error"));
+ continue;
+ }
+
+ status = pj_stun_msg_create_response(pool, stun_req,
+ PJ_STUN_SC_BAD_REQUEST, NULL,
+ &stun_res);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "STUN create response error"));
+ continue;
+ }
+
+ status = pj_stun_msg_encode(stun_res, pkt, sizeof(pkt), 0,
+ NULL, &res_len);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "STUN encode error"));
+ continue;
+ }
+
+ /* Ignore request */
+ if (test_sess->param.server_drop_request)
+ continue;
+
+ /* Wait for signal to continue */
+ if (test_sess->param.server_wait_for_event)
+ pj_event_wait(test_sess->server_event);
+
+ pkt_len = res_len;
+ pj_sock_sendto(test_sess->server_sock, pkt, &pkt_len, 0,
+ &client_addr, pj_sockaddr_get_len(&client_addr));
+ }
+ }
+
+ pj_pool_release(pool);
+
+ PJ_LOG(4,(THIS_FILE, "Server thread quitting"));
+ return 0;
+}
+
+static int worker_thread_proc(void *p)
+{
+ struct stun_test_session *test_sess = (struct stun_test_session*)p;
+
+ PJ_LOG(4,(THIS_FILE, "Worker thread running"));
+
+ while (!test_sess->thread_quit_flag) {
+ pj_time_val timeout = {0, 10};
+ pj_timer_heap_poll(test_sess->stun_cfg.timer_heap, NULL);
+ pj_ioqueue_poll(test_sess->stun_cfg.ioqueue, &timeout);
+ }
+
+ PJ_LOG(4,(THIS_FILE, "Worker thread quitting"));
+ return 0;
+}
+
+static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock,
+ pj_stun_sock_op op,
+ pj_status_t status)
+{
+ struct stun_test_session *test_sess = (struct stun_test_session*)pj_stun_sock_get_user_data(stun_sock);
+
+ PJ_UNUSED_ARG(op);
+ PJ_UNUSED_ARG(status);
+
+ test_sess->param.client_got_response++;
+ return PJ_TRUE;
+}
+
+static int stun_destroy_test_session(struct stun_test_session *test_sess)
+{
+
+ unsigned i;
+ pj_stun_sock_cb stun_cb;
+ pj_status_t status;
+ pj_stun_sock *stun_sock[MAX_SOCK_CLIENTS];
+
+ pj_bzero(&stun_cb, sizeof(stun_cb));
+ stun_cb.on_status = &stun_sock_on_status;
+
+ pj_event_reset(test_sess->server_event);
+
+ /* Create all clients first */
+ for (i=0; i<MAX_SOCK_CLIENTS; ++i) {
+ char name[10];
+ sprintf(name, "stun%02d", i);
+ status = pj_stun_sock_create(&test_sess->stun_cfg, name, pj_AF_INET(),
+ &stun_cb, NULL, test_sess,
+ &stun_sock[i]);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "Error creating stun socket"));
+ return -10;
+ }
+ }
+
+ /* Start resolution */
+ for (i=0; i<MAX_SOCK_CLIENTS; ++i) {
+ pj_str_t server_ip = pj_str("127.0.0.1");
+ status = pj_stun_sock_start(stun_sock[i], &server_ip,
+ (pj_uint16_t)test_sess->server_port, NULL);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "Error starting stun socket"));
+ return -20;
+ }
+ }
+
+ /* settle down */
+ pj_thread_sleep(test_sess->param.client_sleep_after_start);
+
+ /* Resume server threads */
+ pj_event_set(test_sess->server_event);
+
+ pj_thread_sleep(test_sess->param.client_sleep_before_destroy);
+
+ /* Destroy clients */
+ for (i=0; i<MAX_SOCK_CLIENTS; ++i) {
+ status = pj_stun_sock_destroy(stun_sock[i]);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "Error destroying stun socket"));
+ }
+ }
+
+ return 0;
+}
+
+static int stun_destroy_test(void)
+{
+ enum { LOOP = 500 };
+ struct stun_test_session test_sess;
+ pj_sockaddr bind_addr;
+ int addr_len;
+ pj_caching_pool cp;
+ pj_pool_t *pool;
+ unsigned i;
+ pj_status_t status;
+ int rc = 0;
+
+ PJ_LOG(3,(THIS_FILE, " STUN destroy concurrency test"));
+
+ pj_bzero(&test_sess, sizeof(test_sess));
+
+ pj_caching_pool_init(&cp, NULL, 0);
+ pool = pj_pool_create(&cp.factory, "testsess", 512, 512, NULL);
+
+ pj_stun_config_init(&test_sess.stun_cfg, &cp.factory, 0, NULL, NULL);
+
+ status = pj_timer_heap_create(pool, 1023, &test_sess.stun_cfg.timer_heap);
+ pj_assert(status == PJ_SUCCESS);
+
+ status = pj_lock_create_recursive_mutex(pool, NULL, &test_sess.lock);
+ pj_assert(status == PJ_SUCCESS);
+
+ pj_timer_heap_set_lock(test_sess.stun_cfg.timer_heap, test_sess.lock, PJ_TRUE);
+ pj_assert(status == PJ_SUCCESS);
+
+ status = pj_ioqueue_create(pool, 512, &test_sess.stun_cfg.ioqueue);
+ pj_assert(status == PJ_SUCCESS);
+
+ pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &test_sess.server_sock);
+ pj_sockaddr_init(pj_AF_INET(), &bind_addr, NULL, 0);
+ status = pj_sock_bind(test_sess.server_sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
+ pj_assert(status == PJ_SUCCESS);
+
+ addr_len = sizeof(bind_addr);
+ status = pj_sock_getsockname(test_sess.server_sock, &bind_addr, &addr_len);
+ pj_assert(status == PJ_SUCCESS);
+
+ test_sess.server_port = pj_sockaddr_get_port(&bind_addr);
+
+ status = pj_event_create(pool, NULL, PJ_TRUE, PJ_FALSE, &test_sess.server_event);
+ pj_assert(status == PJ_SUCCESS);
+
+ for (i=0; i<SERVER_THREAD_CNT; ++i) {
+ status = pj_thread_create(pool, NULL,
+ &server_thread_proc, &test_sess,
+ 0, 0, &test_sess.server_threads[i]);
+ pj_assert(status == PJ_SUCCESS);
+ }
+
+ for (i=0; i<WORKER_THREAD_CNT; ++i) {
+ status = pj_thread_create(pool, NULL,
+ &worker_thread_proc, &test_sess,
+ 0, 0, &test_sess.worker_threads[i]);
+ pj_assert(status == PJ_SUCCESS);
+ }
+
+ /* Test 1: Main thread calls destroy while callback is processing response */
+ PJ_LOG(3,(THIS_FILE, " Destroy in main thread while callback is running"));
+ for (i=0; i<LOOP; ++i) {
+ int sleep = pj_rand() % 5;
+
+ PJ_LOG(3,(THIS_FILE, " Try %-3d of %d", i+1, LOOP));
+
+ /* Test 1: destroy at the same time when receiving response */
+ pj_bzero(&test_sess.param, sizeof(test_sess.param));
+ test_sess.param.client_sleep_after_start = 20;
+ test_sess.param.client_sleep_before_destroy = sleep;
+ test_sess.param.server_wait_for_event = PJ_TRUE;
+ stun_destroy_test_session(&test_sess);
+ PJ_LOG(3,(THIS_FILE,
+ " stun test a: sleep delay:%d: clients with response: %d",
+ sleep, test_sess.param.client_got_response));
+
+ /* Test 2: destroy at the same time with STUN retransmit timer */
+ test_sess.param.server_drop_request = PJ_TRUE;
+ test_sess.param.client_sleep_after_start = 0;
+ test_sess.param.client_sleep_before_destroy = PJ_STUN_RTO_VALUE;
+ test_sess.param.server_wait_for_event = PJ_FALSE;
+ stun_destroy_test_session(&test_sess);
+ PJ_LOG(3,(THIS_FILE, " stun test b: retransmit concurrency"));
+
+ /* Test 3: destroy at the same time with receiving response
+ * AND STUN retransmit timer */
+ test_sess.param.client_got_response = 0;
+ test_sess.param.server_drop_request = PJ_FALSE;
+ test_sess.param.client_sleep_after_start = PJ_STUN_RTO_VALUE;
+ test_sess.param.client_sleep_before_destroy = 0;
+ test_sess.param.server_wait_for_event = PJ_TRUE;
+ stun_destroy_test_session(&test_sess);
+ PJ_LOG(3,(THIS_FILE,
+ " stun test c: clients with response: %d",
+ test_sess.param.client_got_response));
+
+ pj_thread_sleep(10);
+
+ ice_one_conc_test(&test_sess.stun_cfg, PJ_FALSE);
+
+ pj_thread_sleep(10);
+ }
+
+ /* Avoid compiler warning */
+ goto on_return;
+
+
+on_return:
+ test_sess.thread_quit_flag = PJ_TRUE;
+
+ for (i=0; i<SERVER_THREAD_CNT; ++i) {
+ pj_thread_join(test_sess.server_threads[i]);
+ }
+
+ for (i=0; i<WORKER_THREAD_CNT; ++i) {
+ pj_thread_join(test_sess.worker_threads[i]);
+ }
+
+ pj_event_destroy(test_sess.server_event);
+ pj_sock_close(test_sess.server_sock);
+ pj_ioqueue_destroy(test_sess.stun_cfg.ioqueue);
+ pj_timer_heap_destroy(test_sess.stun_cfg.timer_heap);
+
+ pj_pool_release(pool);
+ pj_caching_pool_destroy(&cp);
+
+ PJ_LOG(3,(THIS_FILE, " Done. rc=%d", rc));
+ return rc;
+}
+
+
+int concur_test(void)
+{
+ int rc = 0;
+
+ rc += stun_destroy_test();
+
+ return 0;
+}
+
+#endif /* INCLUDE_CONCUR_TEST */
diff --git a/pjnath/src/pjnath-test/ice_test.c b/pjnath/src/pjnath-test/ice_test.c
index fe0ee8d..2b74811 100644
--- a/pjnath/src/pjnath-test/ice_test.c
+++ b/pjnath/src/pjnath-test/ice_test.c
@@ -1,4 +1,4 @@
-/* $Id: ice_test.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: ice_test.c 4412 2013-03-05 03:12:32Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -29,7 +29,9 @@ enum
#define NODELAY 0xFFFFFFFF
#define SRV_DOMAIN "pjsip.lab.domain"
+#define MAX_THREADS 16
+#define THIS_FILE "ice_test.c"
#define INDENT " "
/* Client flags */
@@ -48,7 +50,7 @@ struct test_result
unsigned rx_cnt[4]; /* Number of data received */
};
-
+/* Role comp# host? stun? turn? flag? ans_del snd_del des_del */
/* Test session configuration */
struct test_cfg
{
@@ -60,8 +62,8 @@ struct test_cfg
unsigned client_flag; /* Client flags */
unsigned answer_delay; /* Delay before sending SDP */
- unsigned send_delay; /* Delay before sending data */
- unsigned destroy_delay; /* Delay before destroy() */
+ unsigned send_delay; /* unused */
+ unsigned destroy_delay; /* unused */
struct test_result expected;/* Expected result */
@@ -79,6 +81,17 @@ struct ice_ept
pj_str_t pass; /* password */
};
+/* Session param */
+struct sess_param
+{
+ unsigned worker_cnt;
+ unsigned worker_timeout;
+ pj_bool_t worker_quit;
+
+ pj_bool_t destroy_after_create;
+ pj_bool_t destroy_after_one_done;
+};
+
/* The test session */
struct test_sess
{
@@ -86,8 +99,12 @@ struct test_sess
pj_stun_config *stun_cfg;
pj_dns_resolver *resolver;
+ struct sess_param *param;
+
test_server *server;
+ pj_thread_t *worker_threads[MAX_THREADS];
+
unsigned server_flag;
struct ice_ept caller;
struct ice_ept callee;
@@ -190,6 +207,7 @@ static int create_sess(pj_stun_config *stun_cfg,
unsigned server_flag,
struct test_cfg *caller_cfg,
struct test_cfg *callee_cfg,
+ struct sess_param *test_param,
struct test_sess **p_sess)
{
pj_pool_t *pool;
@@ -204,6 +222,7 @@ static int create_sess(pj_stun_config *stun_cfg,
sess = PJ_POOL_ZALLOC_T(pool, struct test_sess);
sess->pool = pool;
sess->stun_cfg = stun_cfg;
+ sess->param = test_param;
pj_memcpy(&sess->caller.cfg, caller_cfg, sizeof(*caller_cfg));
sess->caller.result.init_status = sess->caller.result.nego_status = PJ_EPENDING;
@@ -261,6 +280,8 @@ static int create_sess(pj_stun_config *stun_cfg,
/* Destroy test session */
static void destroy_sess(struct test_sess *sess, unsigned wait_msec)
{
+ unsigned i;
+
if (sess->caller.ice) {
pj_ice_strans_destroy(sess->caller.ice);
sess->caller.ice = NULL;
@@ -271,6 +292,12 @@ static void destroy_sess(struct test_sess *sess, unsigned wait_msec)
sess->callee.ice = NULL;
}
+ sess->param->worker_quit = PJ_TRUE;
+ for (i=0; i<sess->param->worker_cnt; ++i) {
+ if (sess->worker_threads[i])
+ pj_thread_join(sess->worker_threads[i]);
+ }
+
poll_events(sess->stun_cfg, wait_msec, PJ_FALSE);
if (sess->resolver) {
@@ -326,6 +353,9 @@ static void ice_on_ice_complete(pj_ice_strans *ice_st,
case PJ_ICE_STRANS_OP_NEGOTIATION:
ept->result.nego_status = status;
break;
+ case PJ_ICE_STRANS_OP_KEEP_ALIVE:
+ /* keep alive failed? */
+ break;
default:
pj_assert(!"Unknown op");
}
@@ -384,20 +414,20 @@ static int check_pair(const struct ice_ept *ept1, const struct ice_ept *ept2,
c1 = pj_ice_strans_get_valid_pair(ept1->ice, i+1);
if (c1 == NULL) {
- PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice1 "
+ PJ_LOG(3,(THIS_FILE, INDENT "err: unable to get valid pair for ice1 "
"component %d", i+1));
return start_err - 2;
}
c2 = pj_ice_strans_get_valid_pair(ept2->ice, i+1);
if (c2 == NULL) {
- PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice2 "
+ PJ_LOG(3,(THIS_FILE, INDENT "err: unable to get valid pair for ice2 "
"component %d", i+1));
return start_err - 4;
}
if (pj_sockaddr_cmp(&c1->rcand->addr, &c2->lcand->addr) != 0) {
- PJ_LOG(3,("", INDENT "err: candidate pair does not match "
+ PJ_LOG(3,(THIS_FILE, INDENT "err: candidate pair does not match "
"for component %d", i+1));
return start_err - 6;
}
@@ -408,14 +438,14 @@ static int check_pair(const struct ice_ept *ept1, const struct ice_ept *ept2,
if (ept1->cfg.comp_cnt>i &&
pj_ice_strans_get_valid_pair(ept1->ice, i+1) != NULL)
{
- PJ_LOG(3,("", INDENT "err: ice1 shouldn't have valid pair "
+ PJ_LOG(3,(THIS_FILE, INDENT "err: ice1 shouldn't have valid pair "
"for component %d", i+1));
return start_err - 8;
}
if (ept2->cfg.comp_cnt>i &&
pj_ice_strans_get_valid_pair(ept2->ice, i+1) != NULL)
{
- PJ_LOG(3,("", INDENT "err: ice2 shouldn't have valid pair "
+ PJ_LOG(3,(THIS_FILE, INDENT "err: ice2 shouldn't have valid pair "
"for component %d", i+1));
return start_err - 9;
}
@@ -436,26 +466,44 @@ static int check_pair(const struct ice_ept *ept1, const struct ice_ept *ept2,
rc = PJ_SUCCESS; \
break; \
} \
- if (t.sec - t0.sec > (timeout)) break; \
+ PJ_TIME_VAL_SUB(t, t0); \
+ if ((unsigned)PJ_TIME_VAL_MSEC(t) >= (timeout)) \
+ break; \
} \
}
+int worker_thread_proc(void *data)
+{
+ pj_status_t rc;
+ struct test_sess *sess = (struct test_sess *) data;
+ pj_stun_config *stun_cfg = sess->stun_cfg;
+
+ /* Wait until negotiation is complete on both endpoints */
+#define ALL_DONE (sess->param->worker_quit || \
+ (sess->caller.result.nego_status!=PJ_EPENDING && \
+ sess->callee.result.nego_status!=PJ_EPENDING))
+ WAIT_UNTIL(sess->param->worker_timeout, ALL_DONE, rc);
+
+ return 0;
+}
-static int perform_test(const char *title,
- pj_stun_config *stun_cfg,
- unsigned server_flag,
- struct test_cfg *caller_cfg,
- struct test_cfg *callee_cfg)
+static int perform_test2(const char *title,
+ pj_stun_config *stun_cfg,
+ unsigned server_flag,
+ struct test_cfg *caller_cfg,
+ struct test_cfg *callee_cfg,
+ struct sess_param *test_param)
{
pjlib_state pjlib_state;
struct test_sess *sess;
+ unsigned i;
int rc;
- PJ_LOG(3,("", INDENT "%s", title));
+ PJ_LOG(3,(THIS_FILE, INDENT "%s", title));
capture_pjlib_state(stun_cfg, &pjlib_state);
- rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, &sess);
+ rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, test_param, &sess);
if (rc != 0)
return rc;
@@ -463,10 +511,10 @@ static int perform_test(const char *title,
sess->callee.result.init_status!=PJ_EPENDING)
/* Wait until both ICE transports are initialized */
- WAIT_UNTIL(30, ALL_READY, rc);
+ WAIT_UNTIL(30000, ALL_READY, rc);
if (!ALL_READY) {
- PJ_LOG(3,("", INDENT "err: init timed-out"));
+ PJ_LOG(3,(THIS_FILE, INDENT "err: init timed-out"));
destroy_sess(sess, 500);
return -100;
}
@@ -489,7 +537,6 @@ static int perform_test(const char *title,
rc = 0;
goto on_return;
}
-
/* Init ICE on caller */
rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role,
&sess->caller.ufrag, &sess->caller.pass);
@@ -507,17 +554,14 @@ static int perform_test(const char *title,
destroy_sess(sess, 500);
return -110;
}
-
/* Start ICE on callee */
rc = start_ice(&sess->callee, &sess->caller);
if (rc != PJ_SUCCESS) {
destroy_sess(sess, 500);
return -120;
}
-
/* Wait for callee's answer_delay */
poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE);
-
/* Start ICE on caller */
rc = start_ice(&sess->caller, &sess->callee);
if (rc != PJ_SUCCESS) {
@@ -525,13 +569,37 @@ static int perform_test(const char *title,
return -130;
}
- /* Wait until negotiation is complete on both endpoints */
-#define ALL_DONE (sess->caller.result.nego_status!=PJ_EPENDING && \
- sess->callee.result.nego_status!=PJ_EPENDING)
- WAIT_UNTIL(30, ALL_DONE, rc);
+ for (i=0; i<sess->param->worker_cnt; ++i) {
+ pj_status_t status;
+ status = pj_thread_create(sess->pool, "worker_thread",
+ worker_thread_proc, sess, 0, 0,
+ &sess->worker_threads[i]);
+ if (status != PJ_SUCCESS) {
+ PJ_LOG(3,(THIS_FILE, INDENT "err: create thread"));
+ destroy_sess(sess, 500);
+ return -135;
+ }
+ }
+
+ if (sess->param->destroy_after_create)
+ goto on_destroy;
+
+ if (sess->param->destroy_after_one_done) {
+ while (sess->caller.result.init_status==PJ_EPENDING &&
+ sess->callee.result.init_status==PJ_EPENDING)
+ {
+ if (sess->param->worker_cnt)
+ pj_thread_sleep(0);
+ else
+ poll_events(stun_cfg, 0, PJ_FALSE);
+ }
+ goto on_destroy;
+ }
+
+ WAIT_UNTIL(30000, ALL_DONE, rc);
if (!ALL_DONE) {
- PJ_LOG(3,("", INDENT "err: negotiation timed-out"));
+ PJ_LOG(3,(THIS_FILE, INDENT "err: negotiation timed-out"));
destroy_sess(sess, 500);
return -140;
}
@@ -561,6 +629,7 @@ static int perform_test(const char *title,
}
/* Looks like everything is okay */
+on_destroy:
/* Destroy ICE stream transports first to let it de-allocate
* TURN relay (otherwise there'll be timer/memory leak, unless
@@ -578,7 +647,7 @@ static int perform_test(const char *title,
on_return:
/* Wait.. */
- poll_events(stun_cfg, 500, PJ_FALSE);
+ poll_events(stun_cfg, 200, PJ_FALSE);
/* Now destroy everything */
destroy_sess(sess, 500);
@@ -591,7 +660,20 @@ on_return:
return rc;
}
- return 0;
+ return rc;
+}
+
+static int perform_test(const char *title,
+ pj_stun_config *stun_cfg,
+ unsigned server_flag,
+ struct test_cfg *caller_cfg,
+ struct test_cfg *callee_cfg)
+{
+ struct sess_param test_param;
+
+ pj_bzero(&test_param, sizeof(test_param));
+ return perform_test2(title, stun_cfg, server_flag, caller_cfg,
+ callee_cfg, &test_param);
}
#define ROLE1 PJ_ICE_SESS_ROLE_CONTROLLED
@@ -680,7 +762,7 @@ int ice_test(void)
if (rc != 0)
goto on_return;
}
-
+
/* Simple test first with srflx candidate */
if (1) {
struct sess_cfg_t cfg =
@@ -744,7 +826,7 @@ int ice_test(void)
{ROLE2, 2, NO, YES, NO, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}}
};
- rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,
+ rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,
&cfg.ua1, &cfg.ua2);
if (rc != 0)
goto on_return;
@@ -785,6 +867,7 @@ int ice_test(void)
goto on_return;
}
+
/* STUN failure, testing TURN deallocation */
if (1) {
struct sess_cfg_t cfg =
@@ -792,11 +875,11 @@ int ice_test(void)
"STUN failure, testing TURN deallocation",
0xFFFF & (~(CREATE_STUN_SERVER)),
/* Role comp# host? stun? turn? flag? ans_del snd_del des_del */
- {ROLE1, 2, YES, YES, YES, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}},
- {ROLE2, 2, YES, YES, YES, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}}
+ {ROLE1, 1, YES, YES, YES, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}},
+ {ROLE2, 1, YES, YES, YES, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}}
};
- rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,
+ rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,
&cfg.ua1, &cfg.ua2);
if (rc != 0)
goto on_return;
@@ -818,7 +901,7 @@ int ice_test(void)
unsigned delay[] = { 50, 2000 };
unsigned d;
- PJ_LOG(3,("", " %s", cfg->title));
+ PJ_LOG(3,(THIS_FILE, " %s", cfg->title));
/* For each test item, test with various answer delay */
for (d=0; d<PJ_ARRAY_SIZE(delay); ++d) {
@@ -876,3 +959,89 @@ on_return:
return rc;
}
+int ice_one_conc_test(pj_stun_config *stun_cfg, int err_quit)
+{
+ struct sess_cfg_t {
+ const char *title;
+ unsigned server_flag;
+ struct test_cfg ua1;
+ struct test_cfg ua2;
+ } cfg =
+ {
+ "Concurrency test",
+ 0xFFFF,
+ /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */
+ {ROLE1, 1, YES, YES, YES, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}},
+ {ROLE2, 1, YES, YES, YES, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}
+ };
+ struct sess_param test_param;
+ int rc;
+
+
+ /* test a: destroy as soon as nego starts */
+ cfg.title = " ice test a: immediate destroy";
+ pj_bzero(&test_param, sizeof(test_param));
+ test_param.worker_cnt = 4;
+ test_param.worker_timeout = 1000;
+ test_param.destroy_after_create = PJ_TRUE;
+
+ rc = perform_test2(cfg.title, stun_cfg, cfg.server_flag,
+ &cfg.ua1, &cfg.ua2, &test_param);
+ if (rc != 0 && err_quit)
+ return rc;
+
+ /* test b: destroy as soon as one is done */
+ cfg.title = " ice test b: destroy after 1 success";
+ test_param.destroy_after_create = PJ_FALSE;
+ test_param.destroy_after_one_done = PJ_TRUE;
+
+ rc = perform_test2(cfg.title, stun_cfg, cfg.server_flag,
+ &cfg.ua1, &cfg.ua2, &test_param);
+ if (rc != 0 && err_quit)
+ return rc;
+
+ /* test c: normal */
+ cfg.title = " ice test c: normal flow";
+ pj_bzero(&test_param, sizeof(test_param));
+ test_param.worker_cnt = 4;
+ test_param.worker_timeout = 1000;
+
+ rc = perform_test2(cfg.title, stun_cfg, cfg.server_flag,
+ &cfg.ua1, &cfg.ua2, &test_param);
+ if (rc != 0 && err_quit)
+ return rc;
+
+ return 0;
+}
+
+int ice_conc_test(void)
+{
+ const unsigned LOOP = 100;
+ pj_pool_t *pool;
+ pj_stun_config stun_cfg;
+ unsigned i;
+ int rc;
+
+ pool = pj_pool_create(mem, NULL, 512, 512, NULL);
+ rc = create_stun_config(pool, &stun_cfg);
+ if (rc != PJ_SUCCESS) {
+ pj_pool_release(pool);
+ return -7;
+ }
+
+ for (i = 0; i < LOOP; i++) {
+ PJ_LOG(3,(THIS_FILE, INDENT "Test %d of %d", i+1, LOOP));
+ rc = ice_one_conc_test(&stun_cfg, PJ_TRUE);
+ if (rc)
+ break;
+ }
+
+ /* Avoid compiler warning */
+ goto on_return;
+
+on_return:
+ destroy_stun_config(&stun_cfg);
+ pj_pool_release(pool);
+
+ return rc;
+}
diff --git a/pjnath/src/pjnath-test/sess_auth.c b/pjnath/src/pjnath-test/sess_auth.c
index 05a6209..2364260 100644
--- a/pjnath/src/pjnath-test/sess_auth.c
+++ b/pjnath/src/pjnath-test/sess_auth.c
@@ -1,4 +1,4 @@
-/* $Id: sess_auth.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sess_auth.c 4360 2013-02-21 11:26:35Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -247,7 +247,7 @@ static int create_std_server(pj_stun_auth_type auth_type,
pj_bzero(&sess_cb, sizeof(sess_cb));
sess_cb.on_rx_request = &server_on_rx_request;
sess_cb.on_send_msg = &server_send_msg;
- status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, &server->sess);
+ status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, NULL, &server->sess);
if (status != PJ_SUCCESS) {
destroy_server();
return -10;
@@ -479,7 +479,7 @@ static int run_client_test(const char *title,
pj_bzero(&sess_cb, sizeof(sess_cb));
sess_cb.on_request_complete = &client_on_request_complete;
sess_cb.on_send_msg = &client_send_msg;
- status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, &client->sess);
+ status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, NULL, &client->sess);
if (status != PJ_SUCCESS) {
destroy_client_server();
return -200;
diff --git a/pjnath/src/pjnath-test/stun_sock_test.c b/pjnath/src/pjnath-test/stun_sock_test.c
index 7a309ea..3c3cecc 100644
--- a/pjnath/src/pjnath-test/stun_sock_test.c
+++ b/pjnath/src/pjnath-test/stun_sock_test.c
@@ -1,4 +1,4 @@
-/* $Id: stun_sock_test.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: stun_sock_test.c 4360 2013-02-21 11:26:35Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -298,7 +298,7 @@ static int timeout_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
struct stun_client *client;
pj_str_t srv_addr;
pj_time_val timeout, t;
- int ret = 0;
+ int i, ret = 0;
pj_status_t status;
PJ_LOG(3,(THIS_FILE, " timeout test [%d]", destroy_on_err));
@@ -359,6 +359,8 @@ static int timeout_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
on_return:
destroy_server(srv);
destroy_client(client);
+ for (i=0; i<7; ++i)
+ handle_events(cfg, 50);
return ret;
}
@@ -373,7 +375,7 @@ static int missing_attr_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
struct stun_client *client;
pj_str_t srv_addr;
pj_time_val timeout, t;
- int ret = 0;
+ int i, ret = 0;
pj_status_t status;
PJ_LOG(3,(THIS_FILE, " missing attribute test [%d]", destroy_on_err));
@@ -426,6 +428,8 @@ static int missing_attr_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
on_return:
destroy_server(srv);
destroy_client(client);
+ for (i=0; i<7; ++i)
+ handle_events(cfg, 50);
return ret;
}
@@ -440,7 +444,7 @@ static int keep_alive_test(pj_stun_config *cfg)
pj_stun_sock_info info;
pj_str_t srv_addr;
pj_time_val timeout, t;
- int ret = 0;
+ int i, ret = 0;
pj_status_t status;
PJ_LOG(3,(THIS_FILE, " normal operation"));
@@ -791,6 +795,8 @@ static int keep_alive_test(pj_stun_config *cfg)
on_return:
destroy_server(srv);
destroy_client(client);
+ for (i=0; i<7; ++i)
+ handle_events(cfg, 50);
return ret;
}
diff --git a/pjnath/src/pjnath-test/test.c b/pjnath/src/pjnath-test/test.c
index 081df25..5277585 100644
--- a/pjnath/src/pjnath-test/test.c
+++ b/pjnath/src/pjnath-test/test.c
@@ -1,4 +1,4 @@
-/* $Id: test.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: test.c 4360 2013-02-21 11:26:35Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -34,6 +34,7 @@ pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg)
{
pj_ioqueue_t *ioqueue;
pj_timer_heap_t *timer_heap;
+ pj_lock_t *lock;
pj_status_t status;
status = pj_ioqueue_create(pool, 64, &ioqueue);
@@ -49,6 +50,9 @@ pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg)
return status;
}
+ pj_lock_create_recursive_mutex(pool, NULL, &lock);
+ pj_timer_heap_set_lock(timer_heap, lock, PJ_TRUE);
+
pj_stun_config_init(stun_cfg, mem, 0, ioqueue, timer_heap);
return PJ_SUCCESS;
@@ -105,7 +109,7 @@ void capture_pjlib_state(pj_stun_config *cfg, struct pjlib_state *st)
st->timer_cnt = pj_timer_heap_count(cfg->timer_heap);
- cp = (pj_caching_pool*)mem;
+ cp = (pj_caching_pool*)cfg->pf;
st->pool_used_cnt = cp->used_count;
}
@@ -120,6 +124,10 @@ int check_pjlib_state(pj_stun_config *cfg,
if (current_state.timer_cnt > initial_st->timer_cnt) {
PJ_LOG(3,("", " error: possibly leaking timer"));
rc |= ERR_TIMER_LEAK;
+
+#if PJ_TIMER_DEBUG
+ pj_timer_heap_dump(cfg->timer_heap);
+#endif
}
if (current_state.pool_used_cnt > initial_st->pool_used_cnt) {
@@ -148,6 +156,18 @@ pj_pool_factory *mem;
int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME |
PJ_LOG_HAS_MICRO_SEC;
+pj_log_func *orig_log_func;
+FILE *log_file;
+
+static void test_log_func(int level, const char *data, int len)
+{
+ if (log_file) {
+ fwrite(data, len, 1, log_file);
+ }
+ if (level <= 3)
+ orig_log_func(level, data, len);
+}
+
static int test_inner(void)
{
pj_caching_pool caching_pool;
@@ -158,6 +178,11 @@ static int test_inner(void)
#if 1
pj_log_set_level(3);
pj_log_set_decor(param_log_decor);
+#elif 1
+ log_file = fopen("pjnath-test.log", "wt");
+ pj_log_set_level(5);
+ orig_log_func = pj_log_get_log_func();
+ pj_log_set_log_func(&test_log_func);
#endif
rc = pj_init();
@@ -189,7 +214,13 @@ static int test_inner(void)
DO_TEST(turn_sock_test());
#endif
+#if INCLUDE_CONCUR_TEST
+ DO_TEST(concur_test());
+#endif
+
on_return:
+ if (log_file)
+ fclose(log_file);
return rc;
}
diff --git a/pjnath/src/pjnath-test/test.h b/pjnath/src/pjnath-test/test.h
index bbba992..504f2f7 100644
--- a/pjnath/src/pjnath-test/test.h
+++ b/pjnath/src/pjnath-test/test.h
@@ -1,4 +1,4 @@
-/* $Id: test.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: test.h 4360 2013-02-21 11:26:35Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -25,17 +25,21 @@
#define INCLUDE_ICE_TEST 1
#define INCLUDE_STUN_SOCK_TEST 1
#define INCLUDE_TURN_SOCK_TEST 1
+#define INCLUDE_CONCUR_TEST 1
int stun_test(void);
int sess_auth_test(void);
int stun_sock_test(void);
int turn_sock_test(void);
int ice_test(void);
+int concur_test(void);
int test_main(void);
extern void app_perror(const char *title, pj_status_t rc);
extern pj_pool_factory *mem;
+int ice_one_conc_test(pj_stun_config *stun_cfg, int err_quit);
+
////////////////////////////////////
/*
* Utilities