/* Utility: display error message and exit application (usually * because of fatal error. */ static void err_exit(const char *title, pj_status_t status) { if (status != PJ_SUCCESS) { icedemo_perror(title, status); } PJ_LOG(3,(THIS_FILE, "Shutting down..")); if (icedemo.icest) pj_ice_strans_destroy(icedemo.icest); pj_thread_sleep(500); icedemo.thread_quit_flag = PJ_TRUE; if (icedemo.thread) { pj_thread_join(icedemo.thread); pj_thread_destroy(icedemo.thread); } if (icedemo.ice_cfg.stun_cfg.ioqueue) pj_ioqueue_destroy(icedemo.ice_cfg.stun_cfg.ioqueue); if (icedemo.ice_cfg.stun_cfg.timer_heap) pj_timer_heap_destroy(icedemo.ice_cfg.stun_cfg.timer_heap); pj_caching_pool_destroy(&icedemo.cp); pj_shutdown(); if (icedemo.log_fhnd) { fclose(icedemo.log_fhnd); icedemo.log_fhnd = NULL; } exit(status != PJ_SUCCESS); }
static int timer_thread_run(void* p) { pj_time_val tick = {0, 10}; timer_running = 1; while (timer_running) { if (pj_timer_heap_count(timer) == 0) { pj_sem_wait(timer_sem); } else { pj_thread_sleep(PJ_TIME_VAL_MSEC(tick)); pj_timer_heap_poll(timer, NULL); } } pj_timer_heap_destroy(timer); timer = NULL; pj_sem_destroy(timer_sem); timer_sem = NULL; pj_pool_release(timer_pool); timer_pool = NULL; timer_initialized = 0; return 0; }
// // Destroy // void destroy() { if (ht_) { pj_timer_heap_destroy(ht_); ht_ = NULL; } }
PJStunTurn::~PJStunTurn() { worker_quit_ = true; if (nullptr != thread_) { pj_thread_join(thread_); pj_thread_destroy(thread_); } if (ice_cfg_.stun_cfg.ioqueue) pj_ioqueue_destroy(ice_cfg_.stun_cfg.ioqueue); if (ice_cfg_.stun_cfg.timer_heap) pj_timer_heap_destroy(ice_cfg_.stun_cfg.timer_heap); }
void destroy_stun_config(pj_stun_config *stun_cfg) { if (stun_cfg->timer_heap) { pj_timer_heap_destroy(stun_cfg->timer_heap); stun_cfg->timer_heap = NULL; } if (stun_cfg->ioqueue) { pj_ioqueue_destroy(stun_cfg->ioqueue); stun_cfg->ioqueue = NULL; } }
// // Destroy proactor. // void destroy() { if (ioq_) { pj_ioqueue_destroy(ioq_); ioq_ = NULL; } if (th_) { pj_timer_heap_destroy(th_); th_ = NULL; } }
int stun_sock_test(void) { struct pjlib_state pjlib_state; pj_stun_config stun_cfg; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer_heap = NULL; pj_pool_t *pool = NULL; pj_status_t status; int ret = 0; pool = pj_pool_create(mem, NULL, 512, 512, NULL); status = pj_ioqueue_create(pool, 12, &ioqueue); if (status != PJ_SUCCESS) { app_perror(" pj_ioqueue_create()", status); ret = -4; goto on_return; } status = pj_timer_heap_create(pool, 100, &timer_heap); if (status != PJ_SUCCESS) { app_perror(" pj_timer_heap_create()", status); ret = -8; goto on_return; } pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap); DO_TEST(timeout_test(&stun_cfg, PJ_FALSE)); DO_TEST(timeout_test(&stun_cfg, PJ_TRUE)); DO_TEST(missing_attr_test(&stun_cfg, PJ_FALSE)); DO_TEST(missing_attr_test(&stun_cfg, PJ_TRUE)); DO_TEST(keep_alive_test(&stun_cfg)); on_return: if (timer_heap) pj_timer_heap_destroy(timer_heap); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return ret; }
pj_status_t getURL(const char *curl) { pj_str_t url; pj_http_req_callback hcb; pj_status_t status; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_data_read = &on_data_read; hcb.on_send_data = &on_send_data; hcb.on_response = &on_response; /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -31; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -32; pj_strdup2(pool, &url, curl); if ((status = pj_http_req_create(pool, &url, timer_heap, ioqueue, NULL, &hcb, &http_req)) != PJ_SUCCESS) return status; if ((status = pj_http_req_start(http_req)) != PJ_SUCCESS) return status; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
static int client_shutdown() { unsigned i; if (g.thread) { g.quit = 1; pj_thread_join(g.thread); pj_thread_destroy(g.thread); g.thread = NULL; } if (g.relay) { pj_turn_sock_destroy(g.relay); g.relay = NULL; } for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) { if (g.peer[i].stun_sock) { pj_stun_sock_destroy(g.peer[i].stun_sock); g.peer[i].stun_sock = NULL; } } if (g.stun_config.timer_heap) { pj_timer_heap_destroy(g.stun_config.timer_heap); g.stun_config.timer_heap = NULL; } if (g.stun_config.ioqueue) { pj_ioqueue_destroy(g.stun_config.ioqueue); g.stun_config.ioqueue = NULL; } if (g.pool) { pj_pool_release(g.pool); g.pool = NULL; } pj_pool_factory_dump(&g.cp.factory, PJ_TRUE); pj_caching_pool_destroy(&g.cp); return PJ_SUCCESS; }
static int https_client_test(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_ssl_sock_t *ssock = NULL; pj_ssl_sock_param param; pj_status_t status; struct test_state state = {0}; pj_sockaddr local_addr, rem_addr; pj_str_t tmp_st; pool = pj_pool_create(mem, "https_get", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } state.pool = pool; state.send_str = HTTP_REQ; state.send_str_len = pj_ansi_strlen(state.send_str); state.is_verbose = PJ_TRUE; pj_ssl_sock_param_default(¶m); param.cb.on_connect_complete = &ssl_on_connect_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.user_data = &state; param.server_name = pj_str((char*)HTTP_SERVER_ADDR); param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; param.proto = PJ_SSL_SOCK_PROTO_SSL23; pj_time_val_normalize(¶m.timeout); status = pj_ssl_sock_create(pool, ¶m, &ssock); if (status != PJ_SUCCESS) { goto on_return; } pj_sockaddr_init(PJ_AF_INET, &local_addr, pj_strset2(&tmp_st, "0.0.0.0"), 0); pj_sockaddr_init(PJ_AF_INET, &rem_addr, pj_strset2(&tmp_st, HTTP_SERVER_ADDR), HTTP_SERVER_PORT); status = pj_ssl_sock_start_connect(ssock, pool, &local_addr, &rem_addr, sizeof(rem_addr)); if (status == PJ_SUCCESS) { ssl_on_connect_complete(ssock, PJ_SUCCESS); } else if (status == PJ_EPENDING) { status = PJ_SUCCESS; } else { goto on_return; } /* Wait until everything has been sent/received */ while (state.err == PJ_SUCCESS && !state.done) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state.err) { status = state.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); PJ_LOG(3, ("", ".....Sent/recv: %d/%d bytes", state.sent, state.recv)); on_return: if (ssock && !state.err && !state.done) pj_ssl_sock_close(ssock); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (timer) pj_timer_heap_destroy(timer); if (pool) pj_pool_release(pool); return status; }
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 http_client_test_delete() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -61; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -62; #ifdef USE_LOCAL_SERVER thread_quit = PJ_FALSE; g_server.action = ACTION_REPLY; g_server.send_content_length = PJ_TRUE; g_server.data_size = 0; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d/test/test2.txt", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt"); #endif pj_http_req_param_default(¶m); pj_strset2(¶m.method, (char*)"DELETE"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -63; if (pj_http_req_start(http_req)) return -65; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
/* * GET request scenario 2: using on_complete() to get the * complete data. Server does not reply with content-length. * Request timed out, application sets a longer timeout, then * then restart the request. */ int http_client_test2() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; pj_time_val timeout; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; pj_http_req_param_default(¶m); /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -41; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -42; #ifdef USE_LOCAL_SERVER pj_cstr(&url, "http://127.0.0.1:380"); param.timeout.sec = 0; param.timeout.msec = 2000; thread_quit = PJ_FALSE; g_server.action = ACTION_IGNORE; g_server.send_content_length = PJ_FALSE; g_server.data_size = 4173; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://www.google.com.sg"); param.timeout.sec = 0; param.timeout.msec = 50; #endif pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept", (char*)"image/gif, image/x-xbitmap, image/jpeg, " "image/pjpeg, application/x-ms-application," " application/vnd.ms-xpsdocument, " "application/xaml+xml, " "application/x-ms-xbap, " "application/x-shockwave-flash, " "application/vnd.ms-excel, " "application/vnd.ms-powerpoint, " "application/msword, */*"); pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept-Language", (char*)"en-sg"); pj_http_headers_add_elmt2(¶m.headers, (char*)"User-Agent", (char*)"Mozilla/4.0 (compatible; MSIE 7.0; " "Windows NT 6.0; SLCC1; " ".NET CLR 2.0.50727; " ".NET CLR 3.0.04506)"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -43; if (pj_http_req_start(http_req)) return -45; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER g_server.action = ACTION_REPLY; #endif timeout.sec = 0; timeout.msec = 10000; pj_http_req_set_timeout(http_req, &timeout); if (pj_http_req_start(http_req)) return -47; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
static int timer_initialize() { pj_status_t rc; pj_mutex_t* temp_mutex; rc = pj_mutex_create_simple(timer_pool, "zrtp_timer", &temp_mutex); if (rc != PJ_SUCCESS) { return rc; } pj_enter_critical_section(); if (timer_mutex == NULL) timer_mutex = temp_mutex; else pj_mutex_destroy(temp_mutex); pj_leave_critical_section(); pj_mutex_lock(timer_mutex); if (timer_initialized) { pj_mutex_unlock(timer_mutex); return PJ_SUCCESS; } rc = pj_timer_heap_create(timer_pool, 4, &timer); if (rc != PJ_SUCCESS) { goto ERROR; } rc = pj_sem_create(timer_pool, "zrtp_timer", 0, 1, &timer_sem); if (rc != PJ_SUCCESS) { goto ERROR; } rc = pj_thread_create(timer_pool, "zrtp_timer", &timer_thread_run, NULL, PJ_THREAD_DEFAULT_STACK_SIZE, 0, &thread_run); if (rc != PJ_SUCCESS) { goto ERROR; } timer_initialized = 1; pj_mutex_unlock(timer_mutex); return PJ_SUCCESS; ERROR: if (timer != NULL) { pj_timer_heap_destroy(timer); timer = NULL; } if (timer_sem != NULL) { pj_sem_destroy(timer_sem); timer_sem = NULL; } if (timer_mutex != NULL) { pj_mutex_unlock(timer_mutex); pj_mutex_destroy(timer_mutex); timer_mutex = NULL; } return rc; }
/* Raw TCP socket try to connect to SSL socket server, once * connection established, it will just do nothing, SSL socket * server should be able to close the connection after specified * timeout period (set ms_timeout to 0 to disable timer). */ static int client_non_ssl(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_ssl_sock_t *ssock_serv = NULL; pj_activesock_t *asock_cli = NULL; pj_activesock_cb asock_cb = { 0 }; pj_sock_t sock = PJ_INVALID_SOCKET; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state state_cli = { 0 }; pj_sockaddr listen_addr; pj_ssl_cert_t *cert = NULL; pj_status_t status; pool = pj_pool_create(mem, "ssl_accept_raw_tcp", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } /* Set cert */ { pj_str_t tmp1, tmp2, tmp3, tmp4; status = pj_ssl_cert_load_from_files(pool, pj_strset2(&tmp1, (char*)CERT_CA_FILE), pj_strset2(&tmp2, (char*)CERT_FILE), pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), &cert); if (status != PJ_SUCCESS) { goto on_return; } } pj_ssl_sock_param_default(¶m); param.cb.on_accept_complete = &ssl_on_accept_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; pj_time_val_normalize(¶m.timeout); /* SERVER */ param.user_data = &state_serv; state_serv.pool = pool; state_serv.is_server = PJ_TRUE; state_serv.is_verbose = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_serv); if (status != PJ_SUCCESS) { goto on_return; } status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert); if (status != PJ_SUCCESS) { goto on_return; } /* Init bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_ssl_sock_start_accept(ssock_serv, pool, &listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status != PJ_SUCCESS) { goto on_return; } /* Update listener address */ { pj_ssl_sock_info info; pj_ssl_sock_get_info(ssock_serv, &info); pj_sockaddr_cp(&listen_addr, &info.local_addr); } /* CLIENT */ state_cli.pool = pool; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) { goto on_return; } asock_cb.on_connect_complete = &asock_on_connect_complete; asock_cb.on_data_read = &asock_on_data_read; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, ioqueue, &asock_cb, &state_cli, &asock_cli); if (status != PJ_SUCCESS) { goto on_return; } status = pj_activesock_start_connect(asock_cli, pool, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status == PJ_SUCCESS) { asock_on_connect_complete(asock_cli, PJ_SUCCESS); } else if (status == PJ_EPENDING) { status = PJ_SUCCESS; } else { goto on_return; } /* Wait until everything has been sent/received or error */ while (!state_serv.err && !state_cli.err && !state_serv.done && !state_cli.done) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state_serv.err || state_cli.err) { if (state_serv.err != PJ_SUCCESS) status = state_serv.err; else status = state_cli.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); on_return: if (ssock_serv) pj_ssl_sock_close(ssock_serv); if (asock_cli && !state_cli.err && !state_cli.done) pj_activesock_close(asock_cli); if (timer) pj_timer_heap_destroy(timer); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
/* SSL socket try to connect to raw TCP socket server, once * connection established, SSL socket will try to perform SSL * handshake. SSL client socket should be able to close the * connection after specified timeout period (set ms_timeout to * 0 to disable timer). */ static int server_non_ssl(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_activesock_t *asock_serv = NULL; pj_ssl_sock_t *ssock_cli = NULL; pj_activesock_cb asock_cb = { 0 }; pj_sock_t sock = PJ_INVALID_SOCKET; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state state_cli = { 0 }; pj_sockaddr addr, listen_addr; pj_status_t status; pool = pj_pool_create(mem, "ssl_connect_raw_tcp", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } /* SERVER */ state_serv.pool = pool; state_serv.ioqueue = ioqueue; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) { goto on_return; } /* Init bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_sock_bind(sock, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len((pj_sockaddr_t*)&listen_addr)); if (status != PJ_SUCCESS) { goto on_return; } status = pj_sock_listen(sock, PJ_SOMAXCONN); if (status != PJ_SUCCESS) { goto on_return; } asock_cb.on_accept_complete = &asock_on_accept_complete; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, ioqueue, &asock_cb, &state_serv, &asock_serv); if (status != PJ_SUCCESS) { goto on_return; } status = pj_activesock_start_accept(asock_serv, pool); if (status != PJ_SUCCESS) goto on_return; /* Update listener address */ { int addr_len; addr_len = sizeof(listen_addr); pj_sock_getsockname(sock, (pj_sockaddr_t*)&listen_addr, &addr_len); } /* CLIENT */ pj_ssl_sock_param_default(¶m); param.cb.on_connect_complete = &ssl_on_connect_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; pj_time_val_normalize(¶m.timeout); param.user_data = &state_cli; state_cli.pool = pool; state_cli.is_server = PJ_FALSE; state_cli.is_verbose = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_cli); if (status != PJ_SUCCESS) { goto on_return; } /* Init default bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_ssl_sock_start_connect(ssock_cli, pool, (pj_sockaddr_t*)&addr, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status != PJ_EPENDING) { goto on_return; } /* Wait until everything has been sent/received or error */ while ((!state_serv.err && !state_serv.done) || (!state_cli.err && !state_cli.done)) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state_serv.err || state_cli.err) { if (state_cli.err != PJ_SUCCESS) status = state_cli.err; else status = state_serv.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); on_return: if (asock_serv) pj_activesock_close(asock_serv); if (ssock_cli && !state_cli.err && !state_cli.done) pj_ssl_sock_close(ssock_cli); if (timer) pj_timer_heap_destroy(timer); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
/* * Destroy DNS resolver instance. */ PJ_DEF(pj_status_t) pj_dns_resolver_destroy( pj_dns_resolver *resolver, pj_bool_t notify) { pj_hash_iterator_t it_buf, *it; PJ_ASSERT_RETURN(resolver, PJ_EINVAL); if (notify) { /* * Notify pending queries if requested. */ it = pj_hash_first(resolver->hquerybyid, &it_buf); while (it) { pj_dns_async_query *q = (pj_dns_async_query *) pj_hash_this(resolver->hquerybyid, it); pj_dns_async_query *cq; if (q->cb) (*q->cb)(q->user_data, PJ_ECANCELLED, NULL); cq = q->child_head.next; while (cq != (pj_dns_async_query*)&q->child_head) { if (cq->cb) (*cq->cb)(cq->user_data, PJ_ECANCELLED, NULL); cq = cq->next; } it = pj_hash_next(resolver->hquerybyid, it); } } /* Destroy cached entries */ it = pj_hash_first(resolver->hrescache, &it_buf); while (it) { struct cached_res *cache; cache = (struct cached_res*) pj_hash_this(resolver->hrescache, it); pj_hash_set(NULL, resolver->hrescache, &cache->key, sizeof(cache->key), 0, NULL); pj_pool_release(cache->pool); it = pj_hash_first(resolver->hrescache, &it_buf); } if (resolver->own_timer && resolver->timer) { pj_timer_heap_destroy(resolver->timer); resolver->timer = NULL; } if (resolver->udp_key != NULL) { pj_ioqueue_unregister(resolver->udp_key); resolver->udp_key = NULL; resolver->udp_sock = PJ_INVALID_SOCKET; } else if (resolver->udp_sock != PJ_INVALID_SOCKET) { pj_sock_close(resolver->udp_sock); resolver->udp_sock = PJ_INVALID_SOCKET; } if (resolver->own_ioqueue && resolver->ioqueue) { pj_ioqueue_destroy(resolver->ioqueue); resolver->ioqueue = NULL; } if (resolver->mutex) { pj_mutex_destroy(resolver->mutex); resolver->mutex = NULL; } if (resolver->pool) { pj_pool_t *pool = resolver->pool; resolver->pool = NULL; pj_pool_release(pool); } return PJ_SUCCESS; }
int sess_auth_test(void) { pj_pool_t *pool; int rc; PJ_LOG(3,(THIS_FILE, " STUN session authentication test")); /* Init STUN config */ pj_stun_config_init(0, &stun_cfg, mem, 0, NULL, NULL); /* Create pool and timer heap */ pool = pj_pool_create(mem, "authtest", 200, 200, NULL); if (pj_timer_heap_create(pool, 20, &stun_cfg.timer_heap)) { pj_pool_release(pool); return -5; } /* Basic retransmission test */ rc = run_client_test("Retransmission", // title PJ_FALSE, // server responding PJ_STUN_AUTH_NONE, // server auth PJ_STUN_AUTH_NONE, // client auth NULL, // realm NULL, // username NULL, // nonce NULL, // password PJ_FALSE, // dummy MI PJ_TRUE, // expected error PJNATH_ESTUNTIMEDOUT,// expected code NULL, // expected realm NULL, // expected nonce &retransmit_check // more check ); if (rc != 0) { goto done; } /* * Short term credential. * draft-ietf-behave-rfc3489bis-15#section-10.1.2 */ /* * If the message does not contain both a MESSAGE-INTEGRITY and a * USERNAME attribute, If the message is a request, the server MUST * reject the request with an error response. This response MUST * use an error code of 400 (Bad Request). */ rc = run_client_test("Missing MESSAGE-INTEGRITY (short term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_SHORT_TERM, // server auth PJ_STUN_AUTH_NONE, // client auth NULL, // realm NULL, // username NULL, // nonce NULL, // password PJ_FALSE, // dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(400),// expected code NULL, // expected realm NULL, // expected nonce NULL // more check ); if (rc != 0) { goto done; } /* If the USERNAME does not contain a username value currently valid * within the server: If the message is a request, the server MUST * reject the request with an error response. This response MUST use * an error code of 401 (Unauthorized). */ rc = run_client_test("USERNAME mismatch (short term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_SHORT_TERM, // server auth PJ_STUN_AUTH_SHORT_TERM, // client auth NULL, // realm "anotheruser", // username NULL, // nonce "anotherpass", // password PJ_FALSE, // dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(401),// expected code NULL, // expected realm NULL, // expected nonce NULL // more check ); if (rc != 0) { goto done; } /* Using the password associated with the username, compute the value * for the message-integrity as described in Section 15.4. If the * resulting value does not match the contents of the MESSAGE- * INTEGRITY attribute: * * - If the message is a request, the server MUST reject the request * with an error response. This response MUST use an error code * of 401 (Unauthorized). */ rc = run_client_test("MESSAGE-INTEGRITY mismatch (short term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_SHORT_TERM, // server auth PJ_STUN_AUTH_SHORT_TERM, // client auth NULL, // realm USERNAME, // username NULL, // nonce "anotherpass", // password PJ_FALSE, // dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(401),// expected code NULL, // expected realm NULL, // expected nonce NULL // more check ); if (rc != 0) { goto done; } /* USERNAME is not present, server must respond with 400 (Bad * Request). */ rc = run_client_test("Missing USERNAME (short term)",// title PJ_TRUE, // server responding PJ_STUN_AUTH_SHORT_TERM, // server auth PJ_STUN_AUTH_NONE, // client auth NULL, // realm NULL, // username NULL, // nonce NULL, // password PJ_TRUE, // dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(400), // expected code NULL, // expected realm NULL, // expected nonce NULL // more check ); if (rc != 0) { goto done; } /* Successful short term authentication */ rc = run_client_test("Successful scenario (short term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_SHORT_TERM, // server auth PJ_STUN_AUTH_SHORT_TERM, // client auth NULL, // realm USERNAME, // username NULL, // nonce PASSWORD, // password PJ_FALSE, // dummy MI PJ_FALSE, // expected error PJ_SUCCESS, // expected code NULL, // expected realm NULL, // expected nonce NULL // more check ); if (rc != 0) { goto done; } /* * (our own) Extended tests for long term credential */ /* When server wants to use short term credential, but request has * REALM, reject with .... 401 ??? */ rc = run_client_test("Unwanted REALM (short term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_SHORT_TERM, // server auth PJ_STUN_AUTH_NONE, // client auth REALM, // realm USERNAME, // username NULL, // nonce PASSWORD, // password PJ_TRUE, // dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(401), // expected code NULL, // expected realm NULL, // expected nonce &long_term_check2 // more check ); if (rc != 0) { goto done; } /* * Long term credential. * draft-ietf-behave-rfc3489bis-15#section-10.2.2 */ /* If the message does not contain a MESSAGE-INTEGRITY attribute, the * server MUST generate an error response with an error code of 401 * (Unauthorized). This response MUST include a REALM value. It is * RECOMMENDED that the REALM value be the domain name of the * provider of the STUN server. The response MUST include a NONCE, * selected by the server. The response SHOULD NOT contain a * USERNAME or MESSAGE-INTEGRITY attribute. */ rc = run_client_test("Missing M-I (long term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_LONG_TERM, // server auth PJ_STUN_AUTH_NONE, // client auth NULL, // client realm NULL, // client username NULL, // client nonce NULL, // client password PJ_FALSE, // client dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(401), // expected code REALM, // expected realm NONCE, // expected nonce &long_term_check1 // more check ); if (rc != 0) { goto done; } /* If the message contains a MESSAGE-INTEGRITY attribute, but is * missing the USERNAME, REALM or NONCE attributes, the server MUST * generate an error response with an error code of 400 (Bad * Request). This response SHOULD NOT include a USERNAME, NONCE, * REALM or MESSAGE-INTEGRITY attribute. */ /* Missing USERNAME */ rc = run_client_test("Missing USERNAME (long term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_LONG_TERM, // server auth PJ_STUN_AUTH_NONE, // client auth REALM, // client realm NULL, // client username NONCE, // client nonce PASSWORD, // client password PJ_TRUE, // client dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(400), // expected code NULL, // expected realm NULL, // expected nonce &long_term_check2 // more check ); if (rc != 0) { goto done; } /* Missing REALM */ rc = run_client_test("Missing REALM (long term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_LONG_TERM, // server auth PJ_STUN_AUTH_NONE, // client auth NULL, // client realm USERNAME, // client username NONCE, // client nonce PASSWORD, // client password PJ_TRUE, // client dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(400), // expected code NULL, // expected realm NULL, // expected nonce &long_term_check2 // more check ); if (rc != 0) { goto done; } /* Missing NONCE */ rc = run_client_test("Missing NONCE (long term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_LONG_TERM, // server auth PJ_STUN_AUTH_NONE, // client auth REALM, // client realm USERNAME, // client username NULL, // client nonce PASSWORD, // client password PJ_TRUE, // client dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(400), // expected code NULL, // expected realm NULL, // expected nonce &long_term_check2 // more check ); if (rc != 0) { goto done; } /* If the NONCE is no longer valid, the server MUST generate an error * response with an error code of 438 (Stale Nonce). This response * MUST include a NONCE and REALM attribute and SHOULD NOT incude the * USERNAME or MESSAGE-INTEGRITY attribute. Servers can invalidate * nonces in order to provide additional security. See Section 4.3 * of [RFC2617] for guidelines. */ // how?? /* If the username in the USERNAME attribute is not valid, the server * MUST generate an error response with an error code of 401 * (Unauthorized). This response MUST include a REALM value. It is * RECOMMENDED that the REALM value be the domain name of the * provider of the STUN server. The response MUST include a NONCE, * selected by the server. The response SHOULD NOT contain a * USERNAME or MESSAGE-INTEGRITY attribute. */ rc = run_client_test("Invalid username (long term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_LONG_TERM, // server auth PJ_STUN_AUTH_LONG_TERM, // client auth REALM, // client realm "anotheruser", // client username "a nonce", // client nonce "somepassword", // client password PJ_FALSE, // client dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(401), // expected code REALM, // expected realm NONCE, // expected nonce &long_term_check1 // more check ); if (rc != 0) { goto done; } /* Successful long term authentication */ rc = run_client_test("Successful scenario (long term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_LONG_TERM, // server auth PJ_STUN_AUTH_LONG_TERM, // client auth REALM, // client realm USERNAME, // client username "anothernonce", // client nonce PASSWORD, // client password PJ_FALSE, // client dummy MI PJ_FALSE, // expected error 0, // expected code NULL, // expected realm NULL, // expected nonce &long_term_check3 // more check ); if (rc != 0) { goto done; } /* * (our own) Extended tests for long term credential */ /* If REALM doesn't match, server must respond with 401 */ #if 0 // STUN session now will just use the realm sent in the // response, so this test will fail because it will // authenticate successfully. rc = run_client_test("Invalid REALM (long term)", // title PJ_TRUE, // server responding PJ_STUN_AUTH_LONG_TERM, // server auth PJ_STUN_AUTH_LONG_TERM, // client auth "anotherrealm", // client realm USERNAME, // client username NONCE, // client nonce PASSWORD, // client password PJ_FALSE, // client dummy MI PJ_TRUE, // expected error PJ_STATUS_FROM_STUN_CODE(401), // expected code REALM, // expected realm NONCE, // expected nonce &long_term_check1 // more check ); if (rc != 0) { goto done; } #endif /* Invalid HMAC */ /* Valid static short term, without NONCE */ /* Valid static short term, WITH NONCE */ /* Valid static long term (with NONCE */ /* Valid dynamic short term (without NONCE) */ /* Valid dynamic short term (with NONCE) */ /* Valid dynamic long term (with NONCE) */ done: pj_timer_heap_destroy(stun_cfg.timer_heap); pj_pool_release(pool); return rc; }
/* * Destroy the server. */ PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv) { pj_hash_iterator_t itbuf, *it; unsigned i; /* Stop all worker threads */ srv->core.quit = PJ_TRUE; for (i=0; i<srv->core.thread_cnt; ++i) { if (srv->core.thread[i]) { pj_thread_join(srv->core.thread[i]); pj_thread_destroy(srv->core.thread[i]); srv->core.thread[i] = NULL; } } /* Destroy all allocations FIRST */ if (srv->tables.alloc) { it = pj_hash_first(srv->tables.alloc, &itbuf); while (it != NULL) { pj_turn_allocation *alloc = (pj_turn_allocation*) pj_hash_this(srv->tables.alloc, it); pj_hash_iterator_t *next = pj_hash_next(srv->tables.alloc, it); pj_turn_allocation_destroy(alloc); it = next; } } /* Destroy all listeners. */ for (i=0; i<srv->core.lis_cnt; ++i) { if (srv->core.listener[i]) { pj_turn_listener_destroy(srv->core.listener[i]); srv->core.listener[i] = NULL; } } /* Destroy STUN session */ if (srv->core.stun_sess) { pj_stun_session_destroy(srv->core.stun_sess); srv->core.stun_sess = NULL; } /* Destroy hash tables (well, sort of) */ if (srv->tables.alloc) { srv->tables.alloc = NULL; srv->tables.res = NULL; } /* Destroy timer heap */ if (srv->core.timer_heap) { pj_timer_heap_destroy(srv->core.timer_heap); srv->core.timer_heap = NULL; } /* Destroy ioqueue */ if (srv->core.ioqueue) { pj_ioqueue_destroy(srv->core.ioqueue); srv->core.ioqueue = NULL; } /* Destroy thread local IDs */ if (srv->core.tls_key != -1) { pj_thread_local_free(srv->core.tls_key); srv->core.tls_key = -1; } if (srv->core.tls_data != -1) { pj_thread_local_free(srv->core.tls_data); srv->core.tls_data = -1; } /* Destroy server lock */ if (srv->core.lock) { pj_lock_destroy(srv->core.lock); srv->core.lock = NULL; } /* Release pool */ if (srv->core.pool) { pj_pool_t *pool = srv->core.pool; srv->core.pool = NULL; pj_pool_release(pool); } /* Done */ return PJ_SUCCESS; }