diff options
Diffstat (limited to 'pjnath/src/pjnath-test')
-rw-r--r-- | pjnath/src/pjnath-test/concur_test.c | 360 | ||||
-rw-r--r-- | pjnath/src/pjnath-test/ice_test.c | 235 | ||||
-rw-r--r-- | pjnath/src/pjnath-test/sess_auth.c | 4 | ||||
-rw-r--r-- | pjnath/src/pjnath-test/stun_sock_test.c | 12 | ||||
-rw-r--r-- | pjnath/src/pjnath-test/test.c | 33 | ||||
-rw-r--r-- | pjnath/src/pjnath-test/test.h | 4 |
6 files changed, 607 insertions, 41 deletions
diff --git a/pjnath/src/pjnath-test/concur_test.c b/pjnath/src/pjnath-test/concur_test.c new file mode 100644 index 00000000..92c2d394 --- /dev/null +++ b/pjnath/src/pjnath-test/concur_test.c @@ -0,0 +1,360 @@ +/* $Id$ */ +/* + * 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); + 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, + 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); + } + + +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 fce2cbd0..0a4c8a3e 100644 --- a/pjnath/src/pjnath-test/ice_test.c +++ b/pjnath/src/pjnath-test/ice_test.c @@ -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,43 @@ 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 (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 +510,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 +536,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 +553,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 +568,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 +628,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 +646,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 +659,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 +761,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 +825,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 +866,7 @@ int ice_test(void) goto on_return; } + /* STUN failure, testing TURN deallocation */ if (1) { struct sess_cfg_t cfg = @@ -792,11 +874,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 +900,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 +958,86 @@ 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 int 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; + } + +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 9780d2b4..6db3f333 100644 --- a/pjnath/src/pjnath-test/sess_auth.c +++ b/pjnath/src/pjnath-test/sess_auth.c @@ -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 93e510eb..ebf5a2bd 100644 --- a/pjnath/src/pjnath-test/stun_sock_test.c +++ b/pjnath/src/pjnath-test/stun_sock_test.c @@ -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 12ee0ac3..b100af3d 100644 --- a/pjnath/src/pjnath-test/test.c +++ b/pjnath/src/pjnath-test/test.c @@ -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 28b0cd9c..6a57bc0c 100644 --- a/pjnath/src/pjnath-test/test.h +++ b/pjnath/src/pjnath-test/test.h @@ -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 |