~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjnath/src/pjnath-test/turn_sock_test.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: turn_sock_test.c 3553 2011-05-05 06:14:19Z nanang $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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 
 
19
 */
 
20
#include "test.h"
 
21
#include "server.h"
 
22
 
 
23
#define SRV_DOMAIN      "pjsip.lab.domain"
 
24
#define KA_INTERVAL     50
 
25
 
 
26
struct test_result
 
27
{
 
28
    unsigned    state_called;
 
29
    unsigned    rx_data_cnt;
 
30
};
 
31
 
 
32
struct test_session
 
33
{
 
34
    pj_pool_t           *pool;
 
35
    pj_stun_config      *stun_cfg;
 
36
    pj_turn_sock        *turn_sock;
 
37
    pj_dns_resolver     *resolver;
 
38
    test_server         *test_srv;
 
39
 
 
40
    pj_bool_t            destroy_called;
 
41
    int                  destroy_on_state;
 
42
    struct test_result   result;
 
43
};
 
44
 
 
45
struct test_session_cfg
 
46
{
 
47
    struct {
 
48
        pj_bool_t       enable_dns_srv;
 
49
        int             destroy_on_state;
 
50
    } client;
 
51
 
 
52
    struct {
 
53
        pj_uint32_t     flags;
 
54
        pj_bool_t       respond_allocate;
 
55
        pj_bool_t       respond_refresh;
 
56
    } srv;
 
57
};
 
58
 
 
59
static void turn_on_rx_data(pj_turn_sock *turn_sock,
 
60
                            void *pkt,
 
61
                            unsigned pkt_len,
 
62
                            const pj_sockaddr_t *peer_addr,
 
63
                            unsigned addr_len);
 
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);
 
67
 
 
68
static void destroy_session(struct test_session *sess)
 
69
{
 
70
    if (sess->resolver) {
 
71
        pj_dns_resolver_destroy(sess->resolver, PJ_TRUE);
 
72
        sess->resolver = NULL;
 
73
    }
 
74
 
 
75
    if (sess->turn_sock) {
 
76
        if (!sess->destroy_called) {
 
77
            sess->destroy_called = PJ_TRUE;
 
78
            pj_turn_sock_destroy(sess->turn_sock);
 
79
        }
 
80
        sess->turn_sock = NULL;
 
81
    }
 
82
 
 
83
    if (sess->test_srv) {
 
84
        destroy_test_server(sess->test_srv);
 
85
        sess->test_srv = NULL;
 
86
    }
 
87
 
 
88
    if (sess->pool) {
 
89
        pj_pool_release(sess->pool);
 
90
    }
 
91
}
 
92
 
 
93
 
 
94
 
 
95
static int create_test_session(pj_stun_config  *stun_cfg,
 
96
                               const struct test_session_cfg *cfg,
 
97
                               struct test_session **p_sess)
 
98
{
 
99
    struct test_session *sess;
 
100
    pj_pool_t *pool;
 
101
    pj_turn_sock_cb turn_sock_cb;
 
102
    pj_turn_alloc_param alloc_param;
 
103
    pj_stun_auth_cred cred;
 
104
    pj_status_t status;
 
105
 
 
106
    /* Create client */
 
107
    pool = pj_pool_create(mem, "turnclient", 512, 512, NULL);
 
108
    sess = PJ_POOL_ZALLOC_T(pool, struct test_session);
 
109
    sess->pool = pool;
 
110
    sess->stun_cfg = stun_cfg;
 
111
    sess->destroy_on_state = cfg->client.destroy_on_state;
 
112
 
 
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);
 
120
        return -20;
 
121
    }
 
122
 
 
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);
 
128
        return -30;
 
129
    }
 
130
 
 
131
    sess->test_srv->turn_respond_allocate = cfg->srv.respond_allocate;
 
132
    sess->test_srv->turn_respond_refresh = cfg->srv.respond_refresh;
 
133
 
 
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);
 
139
        return -40;
 
140
 
 
141
    } else {
 
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);
 
145
 
 
146
        if (status != PJ_SUCCESS) {
 
147
            destroy_session(sess);
 
148
            return -50;
 
149
        }
 
150
    }
 
151
 
 
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);
 
159
 
 
160
    /* Init TURN allocate parameter */
 
161
    pj_turn_alloc_param_default(&alloc_param);
 
162
    alloc_param.ka_interval = KA_INTERVAL;
 
163
 
 
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);
 
170
 
 
171
    } else {
 
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);
 
176
 
 
177
    }
 
178
 
 
179
    if (status != PJ_SUCCESS) {
 
180
        if (cfg->client.destroy_on_state >= PJ_TURN_STATE_READY) {
 
181
            destroy_session(sess);
 
182
            return -70;
 
183
        }
 
184
    }
 
185
 
 
186
    *p_sess = sess;
 
187
    return 0;
 
188
}
 
189
 
 
190
 
 
191
static void turn_on_rx_data(pj_turn_sock *turn_sock,
 
192
                            void *pkt,
 
193
                            unsigned pkt_len,
 
194
                            const pj_sockaddr_t *peer_addr,
 
195
                            unsigned addr_len)
 
196
{
 
197
    struct test_session *sess;
 
198
 
 
199
    PJ_UNUSED_ARG(pkt);
 
200
    PJ_UNUSED_ARG(pkt_len);
 
201
    PJ_UNUSED_ARG(peer_addr);
 
202
    PJ_UNUSED_ARG(addr_len);
 
203
 
 
204
    sess = (struct test_session*) pj_turn_sock_get_user_data(turn_sock);
 
205
    if (sess == NULL)
 
206
        return;
 
207
 
 
208
    sess->result.rx_data_cnt++;
 
209
}
 
210
 
 
211
 
 
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)
 
215
{
 
216
    struct test_session *sess;
 
217
    unsigned i, mask;
 
218
 
 
219
    PJ_UNUSED_ARG(old_state);
 
220
 
 
221
    sess = (struct test_session*) pj_turn_sock_get_user_data(turn_sock);
 
222
    if (sess == NULL)
 
223
        return;
 
224
 
 
225
    /* This state must not be called before */
 
226
    pj_assert((sess->result.state_called & (1<<new_state)) == 0);
 
227
 
 
228
    /* new_state must be greater than old_state */
 
229
    pj_assert(new_state > old_state);
 
230
 
 
231
    /* must not call any greater state before */
 
232
    mask = 0;
 
233
    for (i=new_state+1; i<31; ++i) mask |= (1 << i);
 
234
 
 
235
    pj_assert((sess->result.state_called & mask) == 0);
 
236
 
 
237
    sess->result.state_called |= (1 << new_state);
 
238
 
 
239
    if (new_state >= sess->destroy_on_state && !sess->destroy_called) {
 
240
        sess->destroy_called = PJ_TRUE;
 
241
        pj_turn_sock_destroy(turn_sock);
 
242
    }
 
243
 
 
244
    if (new_state >= PJ_TURN_STATE_DESTROYING) {
 
245
        pj_turn_sock_set_user_data(sess->turn_sock, NULL);
 
246
        sess->turn_sock = NULL;
 
247
    }
 
248
}
 
249
 
 
250
 
 
251
/////////////////////////////////////////////////////////////////////
 
252
 
 
253
static int state_progression_test(pj_stun_config  *stun_cfg)
 
254
{
 
255
    struct test_session_cfg test_cfg = 
 
256
    {
 
257
        {   /* Client cfg */
 
258
            /* DNS SRV */   /* Destroy on state */
 
259
            PJ_TRUE,        0xFFFF
 
260
        },
 
261
        {   /* Server cfg */
 
262
            0xFFFFFFFF,     /* flags */
 
263
            PJ_TRUE,        /* respond to allocate  */
 
264
            PJ_TRUE         /* respond to refresh   */
 
265
        }
 
266
    };
 
267
    struct test_session *sess;
 
268
    unsigned i;
 
269
    int rc;
 
270
 
 
271
    PJ_LOG(3,("", "  state progression tests"));
 
272
 
 
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;
 
278
        pj_time_val tstart;
 
279
 
 
280
        PJ_LOG(3,("", "   %s DNS SRV resolution",
 
281
                      (i==0? "without" : "with")));
 
282
 
 
283
        capture_pjlib_state(stun_cfg, &pjlib_state);
 
284
 
 
285
        test_cfg.client.enable_dns_srv = i;
 
286
 
 
287
        rc = create_test_session(stun_cfg, &test_cfg, &sess);
 
288
        if (rc != 0)
 
289
            return rc;
 
290
 
 
291
        pj_bzero(&info, sizeof(info));
 
292
 
 
293
        /* Wait until state is READY */
 
294
        pj_gettimeofday(&tstart);
 
295
        while (sess->turn_sock) {
 
296
            pj_time_val now;
 
297
 
 
298
            poll_events(stun_cfg, 10, PJ_FALSE);
 
299
            rc = pj_turn_sock_get_info(sess->turn_sock, &info);
 
300
            if (rc!=PJ_SUCCESS)
 
301
                break;
 
302
 
 
303
            if (info.state >= PJ_TURN_STATE_READY)
 
304
                break;
 
305
 
 
306
            pj_gettimeofday(&now);
 
307
            if (now.sec - tstart.sec > TIMEOUT) {
 
308
                PJ_LOG(3,("", "    timed-out"));
 
309
                break;
 
310
            }
 
311
        }
 
312
 
 
313
        if (info.state != PJ_TURN_STATE_READY) {
 
314
            PJ_LOG(3,("", "    error: state is not READY"));
 
315
            destroy_session(sess);
 
316
            return -130;
 
317
        }
 
318
 
 
319
        /* Deallocate */
 
320
        pj_turn_sock_destroy(sess->turn_sock);
 
321
 
 
322
        /* Wait for couple of seconds.
 
323
         * We can't poll the session info since the session may have
 
324
         * been destroyed
 
325
         */
 
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);
 
330
 
 
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"));
 
334
            return -140;
 
335
        }
 
336
 
 
337
        if ((result.state_called & (1<<PJ_TURN_STATE_RESOLVED)) == 0) {
 
338
            PJ_LOG(3,("", "    error: PJ_TURN_STATE_RESOLVED is not called"));
 
339
            return -150;
 
340
        }
 
341
 
 
342
        if ((result.state_called & (1<<PJ_TURN_STATE_ALLOCATING)) == 0) {
 
343
            PJ_LOG(3,("", "    error: PJ_TURN_STATE_ALLOCATING is not called"));
 
344
            return -155;
 
345
        }
 
346
 
 
347
        if ((result.state_called & (1<<PJ_TURN_STATE_READY)) == 0) {
 
348
            PJ_LOG(3,("", "    error: PJ_TURN_STATE_READY is not called"));
 
349
            return -160;
 
350
        }
 
351
 
 
352
        if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATING)) == 0) {
 
353
            PJ_LOG(3,("", "    error: PJ_TURN_STATE_DEALLOCATING is not called"));
 
354
            return -170;
 
355
        }
 
356
 
 
357
        if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATED)) == 0) {
 
358
            PJ_LOG(3,("", "    error: PJ_TURN_STATE_DEALLOCATED is not called"));
 
359
            return -180;
 
360
        }
 
361
 
 
362
        if ((result.state_called & (1<<PJ_TURN_STATE_DESTROYING)) == 0) {
 
363
            PJ_LOG(3,("", "    error: PJ_TURN_STATE_DESTROYING is not called"));
 
364
            return -190;
 
365
        }
 
366
 
 
367
        poll_events(stun_cfg, 500, PJ_FALSE);
 
368
        rc = check_pjlib_state(stun_cfg, &pjlib_state);
 
369
        if (rc != 0) {
 
370
            PJ_LOG(3,("", "    error: memory/timer-heap leak detected"));
 
371
            return rc;
 
372
        }
 
373
    }
 
374
 
 
375
    return 0;
 
376
}
 
377
 
 
378
 
 
379
/////////////////////////////////////////////////////////////////////
 
380
 
 
381
static int destroy_test(pj_stun_config  *stun_cfg,
 
382
                        pj_bool_t with_dns_srv,
 
383
                        pj_bool_t in_callback)
 
384
{
 
385
    struct test_session_cfg test_cfg = 
 
386
    {
 
387
        {   /* Client cfg */
 
388
            /* DNS SRV */   /* Destroy on state */
 
389
            PJ_TRUE,        0xFFFF
 
390
        },
 
391
        {   /* Server cfg */
 
392
            0xFFFFFFFF,     /* flags */
 
393
            PJ_TRUE,        /* respond to allocate  */
 
394
            PJ_TRUE         /* respond to refresh   */
 
395
        }
 
396
    };
 
397
    struct test_session *sess;
 
398
    int target_state;
 
399
    int rc;
 
400
 
 
401
    PJ_LOG(3,("", "  destroy test %s %s",
 
402
                  (in_callback? "in callback" : ""),
 
403
                  (with_dns_srv? "with DNS srv" : "")
 
404
                  ));
 
405
 
 
406
    test_cfg.client.enable_dns_srv = with_dns_srv;
 
407
 
 
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;
 
412
        pj_time_val tstart;
 
413
 
 
414
        capture_pjlib_state(stun_cfg, &pjlib_state);
 
415
 
 
416
        PJ_LOG(3,("", "   %s", pj_turn_state_name((pj_turn_state_t)target_state)));
 
417
 
 
418
        if (in_callback)
 
419
            test_cfg.client.destroy_on_state = target_state;
 
420
 
 
421
        rc = create_test_session(stun_cfg, &test_cfg, &sess);
 
422
        if (rc != 0)
 
423
            return rc;
 
424
 
 
425
        if (in_callback) {
 
426
            pj_gettimeofday(&tstart);
 
427
            rc = 0;
 
428
            while (sess->turn_sock) {
 
429
                pj_time_val now;
 
430
 
 
431
                poll_events(stun_cfg, 100, PJ_FALSE);
 
432
 
 
433
                pj_gettimeofday(&now);
 
434
                if (now.sec - tstart.sec > TIMEOUT) {
 
435
                    rc = -7;
 
436
                    break;
 
437
                }
 
438
            }
 
439
 
 
440
        } else {
 
441
            pj_gettimeofday(&tstart);
 
442
            rc = 0;
 
443
            while (sess->turn_sock) {
 
444
                pj_time_val now;
 
445
 
 
446
                poll_events(stun_cfg, 1, PJ_FALSE);
 
447
 
 
448
                pj_turn_sock_get_info(sess->turn_sock, &info);
 
449
                
 
450
                if (info.state >= target_state) {
 
451
                    pj_turn_sock_destroy(sess->turn_sock);
 
452
                    break;
 
453
                }
 
454
 
 
455
                pj_gettimeofday(&now);
 
456
                if (now.sec - tstart.sec > TIMEOUT) {
 
457
                    rc = -8;
 
458
                    break;
 
459
                }
 
460
            }
 
461
        }
 
462
 
 
463
 
 
464
        if (rc != 0) {
 
465
            PJ_LOG(3,("", "    error: timeout"));
 
466
            return rc;
 
467
        }
 
468
 
 
469
        poll_events(stun_cfg, 1000, PJ_FALSE);
 
470
        destroy_session(sess);
 
471
 
 
472
        rc = check_pjlib_state(stun_cfg, &pjlib_state);
 
473
        if (rc != 0) {
 
474
            PJ_LOG(3,("", "    error: memory/timer-heap leak detected"));
 
475
            return rc;
 
476
        }
 
477
    }
 
478
 
 
479
    return 0;
 
480
}
 
481
 
 
482
 
 
483
/////////////////////////////////////////////////////////////////////
 
484
 
 
485
int turn_sock_test(void)
 
486
{
 
487
    pj_pool_t *pool;
 
488
    pj_stun_config stun_cfg;
 
489
    int i, rc = 0;
 
490
 
 
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);
 
495
        return -2;
 
496
    }
 
497
 
 
498
    rc = state_progression_test(&stun_cfg);
 
499
    if (rc != 0) 
 
500
        goto on_return;
 
501
 
 
502
    for (i=0; i<=1; ++i) {
 
503
        int j;
 
504
        for (j=0; j<=1; ++j) {
 
505
            rc = destroy_test(&stun_cfg, i, j);
 
506
            if (rc != 0)
 
507
                goto on_return;
 
508
        }
 
509
    }
 
510
 
 
511
on_return:
 
512
    destroy_stun_config(&stun_cfg);
 
513
    pj_pool_release(pool);
 
514
    return rc;
 
515
}
 
516