1
/* $Id: turn_sock_test.c 3553 2011-05-05 06:14:19Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
#define SRV_DOMAIN "pjsip.lab.domain"
24
#define KA_INTERVAL 50
28
unsigned state_called;
35
pj_stun_config *stun_cfg;
36
pj_turn_sock *turn_sock;
37
pj_dns_resolver *resolver;
38
test_server *test_srv;
40
pj_bool_t destroy_called;
42
struct test_result result;
45
struct test_session_cfg
48
pj_bool_t enable_dns_srv;
54
pj_bool_t respond_allocate;
55
pj_bool_t respond_refresh;
59
static void turn_on_rx_data(pj_turn_sock *turn_sock,
62
const pj_sockaddr_t *peer_addr,
64
static void turn_on_state(pj_turn_sock *turn_sock,
65
pj_turn_state_t old_state,
66
pj_turn_state_t new_state);
68
static void destroy_session(struct test_session *sess)
71
pj_dns_resolver_destroy(sess->resolver, PJ_TRUE);
72
sess->resolver = NULL;
75
if (sess->turn_sock) {
76
if (!sess->destroy_called) {
77
sess->destroy_called = PJ_TRUE;
78
pj_turn_sock_destroy(sess->turn_sock);
80
sess->turn_sock = NULL;
84
destroy_test_server(sess->test_srv);
85
sess->test_srv = NULL;
89
pj_pool_release(sess->pool);
95
static int create_test_session(pj_stun_config *stun_cfg,
96
const struct test_session_cfg *cfg,
97
struct test_session **p_sess)
99
struct test_session *sess;
101
pj_turn_sock_cb turn_sock_cb;
102
pj_turn_alloc_param alloc_param;
103
pj_stun_auth_cred cred;
107
pool = pj_pool_create(mem, "turnclient", 512, 512, NULL);
108
sess = PJ_POOL_ZALLOC_T(pool, struct test_session);
110
sess->stun_cfg = stun_cfg;
111
sess->destroy_on_state = cfg->client.destroy_on_state;
113
pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
114
turn_sock_cb.on_rx_data = &turn_on_rx_data;
115
turn_sock_cb.on_state = &turn_on_state;
116
status = pj_turn_sock_create(sess->stun_cfg, pj_AF_INET(), PJ_TURN_TP_UDP,
117
&turn_sock_cb, 0, sess, &sess->turn_sock);
118
if (status != PJ_SUCCESS) {
119
destroy_session(sess);
123
/* Create test server */
124
status = create_test_server(sess->stun_cfg, cfg->srv.flags,
125
SRV_DOMAIN, &sess->test_srv);
126
if (status != PJ_SUCCESS) {
127
destroy_session(sess);
131
sess->test_srv->turn_respond_allocate = cfg->srv.respond_allocate;
132
sess->test_srv->turn_respond_refresh = cfg->srv.respond_refresh;
134
/* Create client resolver */
135
status = pj_dns_resolver_create(mem, "resolver", 0, sess->stun_cfg->timer_heap,
136
sess->stun_cfg->ioqueue, &sess->resolver);
137
if (status != PJ_SUCCESS) {
138
destroy_session(sess);
142
pj_str_t dns_srv = pj_str("127.0.0.1");
143
pj_uint16_t dns_srv_port = (pj_uint16_t) DNS_SERVER_PORT;
144
status = pj_dns_resolver_set_ns(sess->resolver, 1, &dns_srv, &dns_srv_port);
146
if (status != PJ_SUCCESS) {
147
destroy_session(sess);
152
/* Init TURN credential */
153
pj_bzero(&cred, sizeof(cred));
154
cred.type = PJ_STUN_AUTH_CRED_STATIC;
155
cred.data.static_cred.realm = pj_str(SRV_DOMAIN);
156
cred.data.static_cred.username = pj_str(TURN_USERNAME);
157
cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
158
cred.data.static_cred.data = pj_str(TURN_PASSWD);
160
/* Init TURN allocate parameter */
161
pj_turn_alloc_param_default(&alloc_param);
162
alloc_param.ka_interval = KA_INTERVAL;
164
/* Start the client */
165
if (cfg->client.enable_dns_srv) {
166
/* Use DNS SRV to resolve server, may fallback to DNS A */
167
pj_str_t domain = pj_str(SRV_DOMAIN);
168
status = pj_turn_sock_alloc(sess->turn_sock, &domain, TURN_SERVER_PORT,
169
sess->resolver, &cred, &alloc_param);
172
/* Explicitly specify server address */
173
pj_str_t host = pj_str("127.0.0.1");
174
status = pj_turn_sock_alloc(sess->turn_sock, &host, TURN_SERVER_PORT,
175
NULL, &cred, &alloc_param);
179
if (status != PJ_SUCCESS) {
180
if (cfg->client.destroy_on_state >= PJ_TURN_STATE_READY) {
181
destroy_session(sess);
191
static void turn_on_rx_data(pj_turn_sock *turn_sock,
194
const pj_sockaddr_t *peer_addr,
197
struct test_session *sess;
200
PJ_UNUSED_ARG(pkt_len);
201
PJ_UNUSED_ARG(peer_addr);
202
PJ_UNUSED_ARG(addr_len);
204
sess = (struct test_session*) pj_turn_sock_get_user_data(turn_sock);
208
sess->result.rx_data_cnt++;
212
static void turn_on_state(pj_turn_sock *turn_sock,
213
pj_turn_state_t old_state,
214
pj_turn_state_t new_state)
216
struct test_session *sess;
219
PJ_UNUSED_ARG(old_state);
221
sess = (struct test_session*) pj_turn_sock_get_user_data(turn_sock);
225
/* This state must not be called before */
226
pj_assert((sess->result.state_called & (1<<new_state)) == 0);
228
/* new_state must be greater than old_state */
229
pj_assert(new_state > old_state);
231
/* must not call any greater state before */
233
for (i=new_state+1; i<31; ++i) mask |= (1 << i);
235
pj_assert((sess->result.state_called & mask) == 0);
237
sess->result.state_called |= (1 << new_state);
239
if (new_state >= sess->destroy_on_state && !sess->destroy_called) {
240
sess->destroy_called = PJ_TRUE;
241
pj_turn_sock_destroy(turn_sock);
244
if (new_state >= PJ_TURN_STATE_DESTROYING) {
245
pj_turn_sock_set_user_data(sess->turn_sock, NULL);
246
sess->turn_sock = NULL;
251
/////////////////////////////////////////////////////////////////////
253
static int state_progression_test(pj_stun_config *stun_cfg)
255
struct test_session_cfg test_cfg =
258
/* DNS SRV */ /* Destroy on state */
262
0xFFFFFFFF, /* flags */
263
PJ_TRUE, /* respond to allocate */
264
PJ_TRUE /* respond to refresh */
267
struct test_session *sess;
271
PJ_LOG(3,("", " state progression tests"));
273
for (i=0; i<=1; ++i) {
274
enum { TIMEOUT = 60 };
275
pjlib_state pjlib_state;
276
pj_turn_session_info info;
277
struct test_result result;
280
PJ_LOG(3,("", " %s DNS SRV resolution",
281
(i==0? "without" : "with")));
283
capture_pjlib_state(stun_cfg, &pjlib_state);
285
test_cfg.client.enable_dns_srv = i;
287
rc = create_test_session(stun_cfg, &test_cfg, &sess);
291
pj_bzero(&info, sizeof(info));
293
/* Wait until state is READY */
294
pj_gettimeofday(&tstart);
295
while (sess->turn_sock) {
298
poll_events(stun_cfg, 10, PJ_FALSE);
299
rc = pj_turn_sock_get_info(sess->turn_sock, &info);
303
if (info.state >= PJ_TURN_STATE_READY)
306
pj_gettimeofday(&now);
307
if (now.sec - tstart.sec > TIMEOUT) {
308
PJ_LOG(3,("", " timed-out"));
313
if (info.state != PJ_TURN_STATE_READY) {
314
PJ_LOG(3,("", " error: state is not READY"));
315
destroy_session(sess);
320
pj_turn_sock_destroy(sess->turn_sock);
322
/* Wait for couple of seconds.
323
* We can't poll the session info since the session may have
326
poll_events(stun_cfg, 2000, PJ_FALSE);
327
sess->turn_sock = NULL;
328
pj_memcpy(&result, &sess->result, sizeof(result));
329
destroy_session(sess);
331
/* Check the result */
332
if ((result.state_called & (1<<PJ_TURN_STATE_RESOLVING)) == 0) {
333
PJ_LOG(3,("", " error: PJ_TURN_STATE_RESOLVING is not called"));
337
if ((result.state_called & (1<<PJ_TURN_STATE_RESOLVED)) == 0) {
338
PJ_LOG(3,("", " error: PJ_TURN_STATE_RESOLVED is not called"));
342
if ((result.state_called & (1<<PJ_TURN_STATE_ALLOCATING)) == 0) {
343
PJ_LOG(3,("", " error: PJ_TURN_STATE_ALLOCATING is not called"));
347
if ((result.state_called & (1<<PJ_TURN_STATE_READY)) == 0) {
348
PJ_LOG(3,("", " error: PJ_TURN_STATE_READY is not called"));
352
if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATING)) == 0) {
353
PJ_LOG(3,("", " error: PJ_TURN_STATE_DEALLOCATING is not called"));
357
if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATED)) == 0) {
358
PJ_LOG(3,("", " error: PJ_TURN_STATE_DEALLOCATED is not called"));
362
if ((result.state_called & (1<<PJ_TURN_STATE_DESTROYING)) == 0) {
363
PJ_LOG(3,("", " error: PJ_TURN_STATE_DESTROYING is not called"));
367
poll_events(stun_cfg, 500, PJ_FALSE);
368
rc = check_pjlib_state(stun_cfg, &pjlib_state);
370
PJ_LOG(3,("", " error: memory/timer-heap leak detected"));
379
/////////////////////////////////////////////////////////////////////
381
static int destroy_test(pj_stun_config *stun_cfg,
382
pj_bool_t with_dns_srv,
383
pj_bool_t in_callback)
385
struct test_session_cfg test_cfg =
388
/* DNS SRV */ /* Destroy on state */
392
0xFFFFFFFF, /* flags */
393
PJ_TRUE, /* respond to allocate */
394
PJ_TRUE /* respond to refresh */
397
struct test_session *sess;
401
PJ_LOG(3,("", " destroy test %s %s",
402
(in_callback? "in callback" : ""),
403
(with_dns_srv? "with DNS srv" : "")
406
test_cfg.client.enable_dns_srv = with_dns_srv;
408
for (target_state=PJ_TURN_STATE_RESOLVING; target_state<=PJ_TURN_STATE_READY; ++target_state) {
409
enum { TIMEOUT = 60 };
410
pjlib_state pjlib_state;
411
pj_turn_session_info info;
414
capture_pjlib_state(stun_cfg, &pjlib_state);
416
PJ_LOG(3,("", " %s", pj_turn_state_name((pj_turn_state_t)target_state)));
419
test_cfg.client.destroy_on_state = target_state;
421
rc = create_test_session(stun_cfg, &test_cfg, &sess);
426
pj_gettimeofday(&tstart);
428
while (sess->turn_sock) {
431
poll_events(stun_cfg, 100, PJ_FALSE);
433
pj_gettimeofday(&now);
434
if (now.sec - tstart.sec > TIMEOUT) {
441
pj_gettimeofday(&tstart);
443
while (sess->turn_sock) {
446
poll_events(stun_cfg, 1, PJ_FALSE);
448
pj_turn_sock_get_info(sess->turn_sock, &info);
450
if (info.state >= target_state) {
451
pj_turn_sock_destroy(sess->turn_sock);
455
pj_gettimeofday(&now);
456
if (now.sec - tstart.sec > TIMEOUT) {
465
PJ_LOG(3,("", " error: timeout"));
469
poll_events(stun_cfg, 1000, PJ_FALSE);
470
destroy_session(sess);
472
rc = check_pjlib_state(stun_cfg, &pjlib_state);
474
PJ_LOG(3,("", " error: memory/timer-heap leak detected"));
483
/////////////////////////////////////////////////////////////////////
485
int turn_sock_test(void)
488
pj_stun_config stun_cfg;
491
pool = pj_pool_create(mem, "turntest", 512, 512, NULL);
492
rc = create_stun_config(pool, &stun_cfg);
493
if (rc != PJ_SUCCESS) {
494
pj_pool_release(pool);
498
rc = state_progression_test(&stun_cfg);
502
for (i=0; i<=1; ++i) {
504
for (j=0; j<=1; ++j) {
505
rc = destroy_test(&stun_cfg, i, j);
512
destroy_stun_config(&stun_cfg);
513
pj_pool_release(pool);