~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* 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: stun_sock_test.c 4360 2013-02-21 11:26:35Z bennylp $ */
 
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
 
 
22
#define THIS_FILE   "stun_sock_test.c"
 
23
 
 
24
enum {
 
25
    RESPOND_STUN    = 1,
 
26
    WITH_MAPPED     = 2,
 
27
    WITH_XOR_MAPPED = 4,
 
28
 
 
29
    ECHO            = 8
 
30
};
 
31
 
 
32
/*
 
33
 * Simple STUN server
 
34
 */
 
35
struct stun_srv
 
36
{
 
37
    pj_activesock_t     *asock;
 
38
    unsigned             flag;
 
39
    pj_sockaddr          addr;
 
40
    unsigned             rx_cnt;
 
41
    pj_ioqueue_op_key_t  send_key;
 
42
    pj_str_t             ip_to_send;
 
43
    pj_uint16_t          port_to_send;
 
44
};
 
45
 
 
46
static pj_bool_t srv_on_data_recvfrom(pj_activesock_t *asock,
 
47
                                      void *data,
 
48
                                      pj_size_t size,
 
49
                                      const pj_sockaddr_t *src_addr,
 
50
                                      int addr_len,
 
51
                                      pj_status_t status)
 
52
{
 
53
    struct stun_srv *srv;
 
54
    pj_ssize_t sent;
 
55
 
 
56
    srv = (struct stun_srv*) pj_activesock_get_user_data(asock);
 
57
 
 
58
    /* Ignore error */
 
59
    if (status != PJ_SUCCESS)
 
60
        return PJ_TRUE;
 
61
 
 
62
    ++srv->rx_cnt;
 
63
 
 
64
    /* Ignore if we're not responding */
 
65
    if (srv->flag & RESPOND_STUN) {
 
66
        pj_pool_t *pool;
 
67
        pj_stun_msg *req_msg, *res_msg;
 
68
 
 
69
        pool = pj_pool_create(mem, "stunsrv", 512, 512, NULL);
 
70
    
 
71
        /* Parse request */
 
72
        status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size, 
 
73
                                    PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
 
74
                                    &req_msg, NULL, NULL);
 
75
        if (status != PJ_SUCCESS) {
 
76
            app_perror("   pj_stun_msg_decode()", status);
 
77
            pj_pool_release(pool);
 
78
            return PJ_TRUE;
 
79
        }
 
80
 
 
81
        /* Create response */
 
82
        status = pj_stun_msg_create(pool, PJ_STUN_BINDING_RESPONSE, PJ_STUN_MAGIC,
 
83
                                    req_msg->hdr.tsx_id, &res_msg);
 
84
        if (status != PJ_SUCCESS) {
 
85
            app_perror("   pj_stun_msg_create()", status);
 
86
            pj_pool_release(pool);
 
87
            return PJ_TRUE;
 
88
        }
 
89
 
 
90
        /* Add MAPPED-ADDRESS or XOR-MAPPED-ADDRESS (or don't add) */
 
91
        if (srv->flag & WITH_MAPPED) {
 
92
            pj_sockaddr_in addr;
 
93
 
 
94
            pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
 
95
            pj_stun_msg_add_sockaddr_attr(pool, res_msg, PJ_STUN_ATTR_MAPPED_ADDR,
 
96
                                          PJ_FALSE, &addr, sizeof(addr));
 
97
        } else if (srv->flag & WITH_XOR_MAPPED) {
 
98
            pj_sockaddr_in addr;
 
99
 
 
100
            pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
 
101
            pj_stun_msg_add_sockaddr_attr(pool, res_msg, 
 
102
                                          PJ_STUN_ATTR_XOR_MAPPED_ADDR,
 
103
                                          PJ_TRUE, &addr, sizeof(addr));
 
104
        }
 
105
 
 
106
        /* Encode */
 
107
        status = pj_stun_msg_encode(res_msg, (pj_uint8_t*)data, 100, 0, 
 
108
                                    NULL, &size);
 
109
        if (status != PJ_SUCCESS) {
 
110
            app_perror("   pj_stun_msg_encode()", status);
 
111
            pj_pool_release(pool);
 
112
            return PJ_TRUE;
 
113
        }
 
114
 
 
115
        /* Send back */
 
116
        sent = size;
 
117
        pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0, 
 
118
                             src_addr, addr_len);
 
119
 
 
120
        pj_pool_release(pool);
 
121
 
 
122
    } else if (srv->flag & ECHO) {
 
123
        /* Send back */
 
124
        sent = size;
 
125
        pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0, 
 
126
                             src_addr, addr_len);
 
127
 
 
128
    }
 
129
 
 
130
    return PJ_TRUE;
 
131
}
 
132
 
 
133
static pj_status_t create_server(pj_pool_t *pool,
 
134
                                 pj_ioqueue_t *ioqueue,
 
135
                                 unsigned flag,
 
136
                                 struct stun_srv **p_srv)
 
137
{
 
138
    struct stun_srv *srv;
 
139
    pj_activesock_cb activesock_cb;
 
140
    pj_status_t status;
 
141
 
 
142
    srv = PJ_POOL_ZALLOC_T(pool, struct stun_srv);
 
143
    srv->flag = flag;
 
144
    srv->ip_to_send = pj_str("1.1.1.1");
 
145
    srv->port_to_send = 1000;
 
146
 
 
147
    status = pj_sockaddr_in_init(&srv->addr.ipv4, NULL, 0);
 
148
    if (status != PJ_SUCCESS)
 
149
        return status;
 
150
 
 
151
    pj_bzero(&activesock_cb, sizeof(activesock_cb));
 
152
    activesock_cb.on_data_recvfrom = &srv_on_data_recvfrom;
 
153
    status = pj_activesock_create_udp(pool, &srv->addr, NULL, ioqueue,
 
154
                                      &activesock_cb, srv, &srv->asock, 
 
155
                                      &srv->addr);
 
156
    if (status != PJ_SUCCESS)
 
157
        return status;
 
158
 
 
159
    pj_ioqueue_op_key_init(&srv->send_key, sizeof(srv->send_key));
 
160
 
 
161
    status = pj_activesock_start_recvfrom(srv->asock, pool, 512, 0);
 
162
    if (status != PJ_SUCCESS) {
 
163
        pj_activesock_close(srv->asock);
 
164
        return status;
 
165
    }
 
166
 
 
167
    *p_srv = srv;
 
168
    return PJ_SUCCESS;
 
169
}
 
170
 
 
171
static void destroy_server(struct stun_srv *srv)
 
172
{
 
173
    pj_activesock_close(srv->asock);
 
174
}
 
175
 
 
176
 
 
177
struct stun_client
 
178
{
 
179
    pj_pool_t           *pool;
 
180
    pj_stun_sock        *sock;
 
181
 
 
182
    pj_ioqueue_op_key_t  send_key;
 
183
    pj_bool_t            destroy_on_err;
 
184
 
 
185
    unsigned             on_status_cnt;
 
186
    pj_stun_sock_op      last_op;
 
187
    pj_status_t          last_status;
 
188
 
 
189
    unsigned             on_rx_data_cnt;
 
190
};
 
191
 
 
192
static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock, 
 
193
                                     pj_stun_sock_op op,
 
194
                                     pj_status_t status)
 
195
{
 
196
    struct stun_client *client;
 
197
 
 
198
    client = (struct stun_client*) pj_stun_sock_get_user_data(stun_sock);
 
199
    client->on_status_cnt++;
 
200
    client->last_op = op;
 
201
    client->last_status = status;
 
202
 
 
203
    if (status != PJ_SUCCESS && client->destroy_on_err) {
 
204
        pj_stun_sock_destroy(client->sock);
 
205
        client->sock = NULL;
 
206
        return PJ_FALSE;
 
207
    }
 
208
 
 
209
    return PJ_TRUE;
 
210
}
 
211
 
 
212
static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
 
213
                                      void *pkt,
 
214
                                      unsigned pkt_len,
 
215
                                      const pj_sockaddr_t *src_addr,
 
216
                                      unsigned addr_len)
 
217
{
 
218
    struct stun_client *client;
 
219
 
 
220
    PJ_UNUSED_ARG(pkt);
 
221
    PJ_UNUSED_ARG(pkt_len);
 
222
    PJ_UNUSED_ARG(src_addr);
 
223
    PJ_UNUSED_ARG(addr_len);
 
224
 
 
225
    client = (struct stun_client*) pj_stun_sock_get_user_data(stun_sock);
 
226
    client->on_rx_data_cnt++;
 
227
 
 
228
    return PJ_TRUE;
 
229
}
 
230
 
 
231
static pj_status_t create_client(pj_stun_config *cfg,
 
232
                                 struct stun_client **p_client,
 
233
                                 pj_bool_t destroy_on_err)
 
234
{
 
235
    pj_pool_t *pool;
 
236
    struct stun_client *client;
 
237
    pj_stun_sock_cfg sock_cfg;
 
238
    pj_stun_sock_cb cb;
 
239
    pj_status_t status;
 
240
 
 
241
    pool = pj_pool_create(mem, "test", 512, 512, NULL);
 
242
    client = PJ_POOL_ZALLOC_T(pool, struct stun_client);
 
243
    client->pool = pool;
 
244
 
 
245
    pj_stun_sock_cfg_default(&sock_cfg);
 
246
 
 
247
    pj_bzero(&cb, sizeof(cb));
 
248
    cb.on_status = &stun_sock_on_status;
 
249
    cb.on_rx_data = &stun_sock_on_rx_data;
 
250
    status = pj_stun_sock_create(cfg, NULL, pj_AF_INET(), &cb,
 
251
                                 &sock_cfg, client, &client->sock);
 
252
    if (status != PJ_SUCCESS) {
 
253
        app_perror("   pj_stun_sock_create()", status);
 
254
        pj_pool_release(pool);
 
255
        return status;
 
256
    }
 
257
 
 
258
    pj_stun_sock_set_user_data(client->sock, client);
 
259
 
 
260
    pj_ioqueue_op_key_init(&client->send_key, sizeof(client->send_key));
 
261
 
 
262
    client->destroy_on_err = destroy_on_err;
 
263
 
 
264
    *p_client = client;
 
265
 
 
266
    return PJ_SUCCESS;
 
267
}
 
268
 
 
269
 
 
270
static void destroy_client(struct stun_client *client)
 
271
{
 
272
    if (client->sock) {
 
273
        pj_stun_sock_destroy(client->sock);
 
274
        client->sock = NULL;
 
275
    }
 
276
    pj_pool_release(client->pool);
 
277
}
 
278
 
 
279
static void handle_events(pj_stun_config *cfg, unsigned msec_delay)
 
280
{
 
281
    pj_time_val delay;
 
282
 
 
283
    pj_timer_heap_poll(cfg->timer_heap, NULL);
 
284
 
 
285
    delay.sec = 0;
 
286
    delay.msec = msec_delay;
 
287
    pj_time_val_normalize(&delay);
 
288
 
 
289
    pj_ioqueue_poll(cfg->ioqueue, &delay);
 
290
}
 
291
 
 
292
/*
 
293
 * Timeout test: scenario when no response is received from server
 
294
 */
 
295
static int timeout_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
 
296
{
 
297
    struct stun_srv *srv;
 
298
    struct stun_client *client;
 
299
    pj_str_t srv_addr;
 
300
    pj_time_val timeout, t;
 
301
    int i, ret = 0;
 
302
    pj_status_t status;
 
303
 
 
304
    PJ_LOG(3,(THIS_FILE, "  timeout test [%d]", destroy_on_err));
 
305
 
 
306
    status =  create_client(cfg, &client, destroy_on_err);
 
307
    if (status != PJ_SUCCESS)
 
308
        return -10;
 
309
 
 
310
    status = create_server(client->pool, cfg->ioqueue, 0, &srv);
 
311
    if (status != PJ_SUCCESS) {
 
312
        destroy_client(client);
 
313
        return -20;
 
314
    }
 
315
 
 
316
    srv_addr = pj_str("127.0.0.1");
 
317
    status = pj_stun_sock_start(client->sock, &srv_addr, 
 
318
                                pj_ntohs(srv->addr.ipv4.sin_port), NULL);
 
319
    if (status != PJ_SUCCESS) {
 
320
        destroy_server(srv);
 
321
        destroy_client(client);
 
322
        return -30;
 
323
    }
 
324
 
 
325
    /* Wait until on_status() callback is called with the failure */
 
326
    pj_gettimeofday(&timeout);
 
327
    timeout.sec += 60;
 
328
    do {
 
329
        handle_events(cfg, 100);
 
330
        pj_gettimeofday(&t);
 
331
    } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
 
332
 
 
333
    /* Check that callback with correct operation is called */
 
334
    if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
 
335
        PJ_LOG(3,(THIS_FILE, "    error: expecting Binding operation status"));
 
336
        ret = -40;
 
337
        goto on_return;
 
338
    }
 
339
    /* .. and with the correct status */
 
340
    if (client->last_status != PJNATH_ESTUNTIMEDOUT) {
 
341
        PJ_LOG(3,(THIS_FILE, "    error: expecting PJNATH_ESTUNTIMEDOUT"));
 
342
        ret = -50;
 
343
        goto on_return;
 
344
    }
 
345
    /* Check that server received correct retransmissions */
 
346
    if (srv->rx_cnt != PJ_STUN_MAX_TRANSMIT_COUNT) {
 
347
        PJ_LOG(3,(THIS_FILE, "    error: expecting %d retransmissions, got %d",
 
348
                   PJ_STUN_MAX_TRANSMIT_COUNT, srv->rx_cnt));
 
349
        ret = -60;
 
350
        goto on_return;
 
351
    }
 
352
    /* Check that client doesn't receive anything */
 
353
    if (client->on_rx_data_cnt != 0) {
 
354
        PJ_LOG(3,(THIS_FILE, "    error: client shouldn't have received anything"));
 
355
        ret = -70;
 
356
        goto on_return;
 
357
    }
 
358
 
 
359
on_return:
 
360
    destroy_server(srv);
 
361
    destroy_client(client);
 
362
    for (i=0; i<7; ++i)
 
363
        handle_events(cfg, 50);
 
364
    return ret;
 
365
}
 
366
 
 
367
 
 
368
/*
 
369
 * Invalid response scenario: when server returns no MAPPED-ADDRESS or
 
370
 * XOR-MAPPED-ADDRESS attribute.
 
371
 */
 
372
static int missing_attr_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
 
373
{
 
374
    struct stun_srv *srv;
 
375
    struct stun_client *client;
 
376
    pj_str_t srv_addr;
 
377
    pj_time_val timeout, t;
 
378
    int i, ret = 0;
 
379
    pj_status_t status;
 
380
 
 
381
    PJ_LOG(3,(THIS_FILE, "  missing attribute test [%d]", destroy_on_err));
 
382
 
 
383
    status =  create_client(cfg, &client, destroy_on_err);
 
384
    if (status != PJ_SUCCESS)
 
385
        return -110;
 
386
 
 
387
    status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN, &srv);
 
388
    if (status != PJ_SUCCESS) {
 
389
        destroy_client(client);
 
390
        return -120;
 
391
    }
 
392
 
 
393
    srv_addr = pj_str("127.0.0.1");
 
394
    status = pj_stun_sock_start(client->sock, &srv_addr, 
 
395
                                pj_ntohs(srv->addr.ipv4.sin_port), NULL);
 
396
    if (status != PJ_SUCCESS) {
 
397
        destroy_server(srv);
 
398
        destroy_client(client);
 
399
        return -130;
 
400
    }
 
401
 
 
402
    /* Wait until on_status() callback is called with the failure */
 
403
    pj_gettimeofday(&timeout);
 
404
    timeout.sec += 60;
 
405
    do {
 
406
        handle_events(cfg, 100);
 
407
        pj_gettimeofday(&t);
 
408
    } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
 
409
 
 
410
    /* Check that callback with correct operation is called */
 
411
    if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
 
412
        PJ_LOG(3,(THIS_FILE, "    error: expecting Binding operation status"));
 
413
        ret = -140;
 
414
        goto on_return;
 
415
    }
 
416
    if (client->last_status != PJNATH_ESTUNNOMAPPEDADDR) {
 
417
        PJ_LOG(3,(THIS_FILE, "    error: expecting PJNATH_ESTUNNOMAPPEDADDR"));
 
418
        ret = -150;
 
419
        goto on_return;
 
420
    }
 
421
    /* Check that client doesn't receive anything */
 
422
    if (client->on_rx_data_cnt != 0) {
 
423
        PJ_LOG(3,(THIS_FILE, "    error: client shouldn't have received anything"));
 
424
        ret = -170;
 
425
        goto on_return;
 
426
    }
 
427
 
 
428
on_return:
 
429
    destroy_server(srv);
 
430
    destroy_client(client);
 
431
    for (i=0; i<7; ++i)
 
432
        handle_events(cfg, 50);
 
433
    return ret;
 
434
}
 
435
 
 
436
/*
 
437
 * Keep-alive test.
 
438
 */
 
439
static int keep_alive_test(pj_stun_config *cfg)
 
440
{
 
441
    struct stun_srv *srv;
 
442
    struct stun_client *client;
 
443
    pj_sockaddr_in mapped_addr;
 
444
    pj_stun_sock_info info;
 
445
    pj_str_t srv_addr;
 
446
    pj_time_val timeout, t;
 
447
    int i, ret = 0;
 
448
    pj_status_t status;
 
449
 
 
450
    PJ_LOG(3,(THIS_FILE, "  normal operation"));
 
451
 
 
452
    status =  create_client(cfg, &client, PJ_TRUE);
 
453
    if (status != PJ_SUCCESS)
 
454
        return -310;
 
455
 
 
456
    status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN|WITH_XOR_MAPPED, &srv);
 
457
    if (status != PJ_SUCCESS) {
 
458
        destroy_client(client);
 
459
        return -320;
 
460
    }
 
461
 
 
462
    /*
 
463
     * Part 1: initial Binding resolution.
 
464
     */
 
465
    PJ_LOG(3,(THIS_FILE, "    initial Binding request"));
 
466
    srv_addr = pj_str("127.0.0.1");
 
467
    status = pj_stun_sock_start(client->sock, &srv_addr, 
 
468
                                pj_ntohs(srv->addr.ipv4.sin_port), NULL);
 
469
    if (status != PJ_SUCCESS) {
 
470
        destroy_server(srv);
 
471
        destroy_client(client);
 
472
        return -330;
 
473
    }
 
474
 
 
475
    /* Wait until on_status() callback is called with success status */
 
476
    pj_gettimeofday(&timeout);
 
477
    timeout.sec += 60;
 
478
    do {
 
479
        handle_events(cfg, 100);
 
480
        pj_gettimeofday(&t);
 
481
    } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
 
482
 
 
483
    /* Check that callback with correct operation is called */
 
484
    if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
 
485
        PJ_LOG(3,(THIS_FILE, "    error: expecting Binding operation status"));
 
486
        ret = -340;
 
487
        goto on_return;
 
488
    }
 
489
    if (client->last_status != PJ_SUCCESS) {
 
490
        PJ_LOG(3,(THIS_FILE, "    error: expecting PJ_SUCCESS status"));
 
491
        ret = -350;
 
492
        goto on_return;
 
493
    }
 
494
    /* Check that client doesn't receive anything */
 
495
    if (client->on_rx_data_cnt != 0) {
 
496
        PJ_LOG(3,(THIS_FILE, "    error: client shouldn't have received anything"));
 
497
        ret = -370;
 
498
        goto on_return;
 
499
    }
 
500
 
 
501
    /* Get info */
 
502
    pj_bzero(&info, sizeof(info));
 
503
    pj_stun_sock_get_info(client->sock, &info);
 
504
 
 
505
    /* Check that we have server address */
 
506
    if (!pj_sockaddr_has_addr(&info.srv_addr)) {
 
507
        PJ_LOG(3,(THIS_FILE, "    error: missing server address"));
 
508
        ret = -380;
 
509
        goto on_return;
 
510
    }
 
511
    /* .. and bound address port must not be zero */
 
512
    if (pj_sockaddr_get_port(&info.bound_addr)==0) {
 
513
        PJ_LOG(3,(THIS_FILE, "    error: bound address is zero"));
 
514
        ret = -381;
 
515
        goto on_return;
 
516
    }
 
517
    /* .. and mapped address */
 
518
    if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
 
519
        PJ_LOG(3,(THIS_FILE, "    error: missing mapped address"));
 
520
        ret = -382;
 
521
        goto on_return;
 
522
    }
 
523
    /* verify the mapped address */
 
524
    pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
 
525
    if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
 
526
        PJ_LOG(3,(THIS_FILE, "    error: mapped address mismatched"));
 
527
        ret = -383;
 
528
        goto on_return;
 
529
    }
 
530
 
 
531
    /* .. and at least one alias */
 
532
    if (info.alias_cnt == 0) {
 
533
        PJ_LOG(3,(THIS_FILE, "    error: must have at least one alias"));
 
534
        ret = -384;
 
535
        goto on_return;
 
536
    }
 
537
    if (!pj_sockaddr_has_addr(&info.aliases[0])) {
 
538
        PJ_LOG(3,(THIS_FILE, "    error: missing alias"));
 
539
        ret = -386;
 
540
        goto on_return;
 
541
    }
 
542
 
 
543
 
 
544
    /*
 
545
     * Part 2: sending and receiving data
 
546
     */
 
547
    PJ_LOG(3,(THIS_FILE, "    sending/receiving data"));
 
548
 
 
549
    /* Change server operation mode to echo back data */
 
550
    srv->flag = ECHO;
 
551
 
 
552
    /* Reset server */
 
553
    srv->rx_cnt = 0;
 
554
 
 
555
    /* Client sending data to echo server */
 
556
    {
 
557
        char txt[100];
 
558
        PJ_LOG(3,(THIS_FILE, "     sending to %s", pj_sockaddr_print(&info.srv_addr, txt, sizeof(txt), 3)));
 
559
    }
 
560
    status = pj_stun_sock_sendto(client->sock, NULL, &ret, sizeof(ret),
 
561
                                 0, &info.srv_addr, 
 
562
                                 pj_sockaddr_get_len(&info.srv_addr));
 
563
    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
 
564
        app_perror("    error: server sending data", status);
 
565
        ret = -390;
 
566
        goto on_return;
 
567
    }
 
568
 
 
569
    /* Wait for a short period until client receives data. We can't wait for
 
570
     * too long otherwise the keep-alive will kick in.
 
571
     */
 
572
    pj_gettimeofday(&timeout);
 
573
    timeout.sec += 1;
 
574
    do {
 
575
        handle_events(cfg, 100);
 
576
        pj_gettimeofday(&t);
 
577
    } while (client->on_rx_data_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
 
578
 
 
579
    /* Check that data is received in server */
 
580
    if (srv->rx_cnt == 0) {
 
581
        PJ_LOG(3,(THIS_FILE, "    error: server didn't receive data"));
 
582
        ret = -395;
 
583
        goto on_return;
 
584
    }
 
585
 
 
586
    /* Check that status is still OK */
 
587
    if (client->last_status != PJ_SUCCESS) {
 
588
        app_perror("    error: client has failed", client->last_status);
 
589
        ret = -400;
 
590
        goto on_return;
 
591
    }
 
592
    /* Check that data has been received */
 
593
    if (client->on_rx_data_cnt == 0) {
 
594
        PJ_LOG(3,(THIS_FILE, "    error: client doesn't receive data"));
 
595
        ret = -410;
 
596
        goto on_return;
 
597
    }
 
598
 
 
599
    /*
 
600
     * Part 3: Successful keep-alive,
 
601
     */
 
602
    PJ_LOG(3,(THIS_FILE, "    successful keep-alive scenario"));
 
603
 
 
604
    /* Change server operation mode to normal mode */
 
605
    srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
 
606
 
 
607
    /* Reset server */
 
608
    srv->rx_cnt = 0;
 
609
 
 
610
    /* Reset client */
 
611
    client->on_status_cnt = 0;
 
612
    client->last_status = PJ_SUCCESS;
 
613
    client->on_rx_data_cnt = 0;
 
614
 
 
615
    /* Wait for keep-alive duration to see if client actually sends the
 
616
     * keep-alive.
 
617
     */
 
618
    pj_gettimeofday(&timeout);
 
619
    timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
 
620
    do {
 
621
        handle_events(cfg, 100);
 
622
        pj_gettimeofday(&t);
 
623
    } while (PJ_TIME_VAL_LT(t, timeout));
 
624
 
 
625
    /* Check that server receives some packets */
 
626
    if (srv->rx_cnt == 0) {
 
627
        PJ_LOG(3, (THIS_FILE, "    error: no keep-alive was received"));
 
628
        ret = -420;
 
629
        goto on_return;
 
630
    }
 
631
    /* Check that client status is still okay and on_status() callback is NOT
 
632
     * called
 
633
     */
 
634
    /* No longer valid due to this ticket:
 
635
     *  http://trac.pjsip.org/repos/ticket/742
 
636
 
 
637
    if (client->on_status_cnt != 0) {
 
638
        PJ_LOG(3, (THIS_FILE, "    error: on_status() must not be called on successful"
 
639
                              "keep-alive when mapped-address does not change"));
 
640
        ret = -430;
 
641
        goto on_return;
 
642
    }
 
643
    */
 
644
    /* Check that client doesn't receive anything */
 
645
    if (client->on_rx_data_cnt != 0) {
 
646
        PJ_LOG(3,(THIS_FILE, "    error: client shouldn't have received anything"));
 
647
        ret = -440;
 
648
        goto on_return;
 
649
    }
 
650
 
 
651
 
 
652
    /*
 
653
     * Part 4: Successful keep-alive with IP address change
 
654
     */
 
655
    PJ_LOG(3,(THIS_FILE, "    mapped IP address change"));
 
656
 
 
657
    /* Change server operation mode to normal mode */
 
658
    srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
 
659
 
 
660
    /* Change mapped address in the response */
 
661
    srv->ip_to_send = pj_str("2.2.2.2");
 
662
    srv->port_to_send++;
 
663
 
 
664
    /* Reset server */
 
665
    srv->rx_cnt = 0;
 
666
 
 
667
    /* Reset client */
 
668
    client->on_status_cnt = 0;
 
669
    client->last_status = PJ_SUCCESS;
 
670
    client->on_rx_data_cnt = 0;
 
671
 
 
672
    /* Wait for keep-alive duration to see if client actually sends the
 
673
     * keep-alive.
 
674
     */
 
675
    pj_gettimeofday(&timeout);
 
676
    timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
 
677
    do {
 
678
        handle_events(cfg, 100);
 
679
        pj_gettimeofday(&t);
 
680
    } while (PJ_TIME_VAL_LT(t, timeout));
 
681
 
 
682
    /* Check that server receives some packets */
 
683
    if (srv->rx_cnt == 0) {
 
684
        PJ_LOG(3, (THIS_FILE, "    error: no keep-alive was received"));
 
685
        ret = -450;
 
686
        goto on_return;
 
687
    }
 
688
    /* Check that on_status() callback is called (because mapped address
 
689
     * has changed)
 
690
     */
 
691
    if (client->on_status_cnt != 1) {
 
692
        PJ_LOG(3, (THIS_FILE, "    error: on_status() was not called"));
 
693
        ret = -460;
 
694
        goto on_return;
 
695
    }
 
696
    /* Check that callback was called with correct operation */
 
697
    if (client->last_op != PJ_STUN_SOCK_MAPPED_ADDR_CHANGE) {
 
698
        PJ_LOG(3,(THIS_FILE, "    error: expecting keep-alive operation status"));
 
699
        ret = -470;
 
700
        goto on_return;
 
701
    }
 
702
    /* Check that last status is still success */
 
703
    if (client->last_status != PJ_SUCCESS) {
 
704
        PJ_LOG(3, (THIS_FILE, "    error: expecting successful status"));
 
705
        ret = -480;
 
706
        goto on_return;
 
707
    }
 
708
    /* Check that client doesn't receive anything */
 
709
    if (client->on_rx_data_cnt != 0) {
 
710
        PJ_LOG(3,(THIS_FILE, "    error: client shouldn't have received anything"));
 
711
        ret = -490;
 
712
        goto on_return;
 
713
    }
 
714
 
 
715
    /* Get info */
 
716
    pj_bzero(&info, sizeof(info));
 
717
    pj_stun_sock_get_info(client->sock, &info);
 
718
 
 
719
    /* Check that we have server address */
 
720
    if (!pj_sockaddr_has_addr(&info.srv_addr)) {
 
721
        PJ_LOG(3,(THIS_FILE, "    error: missing server address"));
 
722
        ret = -500;
 
723
        goto on_return;
 
724
    }
 
725
    /* .. and mapped address */
 
726
    if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
 
727
        PJ_LOG(3,(THIS_FILE, "    error: missing mapped address"));
 
728
        ret = -510;
 
729
        goto on_return;
 
730
    }
 
731
    /* verify the mapped address */
 
732
    pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
 
733
    if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
 
734
        PJ_LOG(3,(THIS_FILE, "    error: mapped address mismatched"));
 
735
        ret = -520;
 
736
        goto on_return;
 
737
    }
 
738
 
 
739
    /* .. and at least one alias */
 
740
    if (info.alias_cnt == 0) {
 
741
        PJ_LOG(3,(THIS_FILE, "    error: must have at least one alias"));
 
742
        ret = -530;
 
743
        goto on_return;
 
744
    }
 
745
    if (!pj_sockaddr_has_addr(&info.aliases[0])) {
 
746
        PJ_LOG(3,(THIS_FILE, "    error: missing alias"));
 
747
        ret = -540;
 
748
        goto on_return;
 
749
    }
 
750
 
 
751
 
 
752
    /*
 
753
     * Part 5: Failed keep-alive
 
754
     */
 
755
    PJ_LOG(3,(THIS_FILE, "    failed keep-alive scenario"));
 
756
    
 
757
    /* Change server operation mode to respond without attribute */
 
758
    srv->flag = RESPOND_STUN;
 
759
 
 
760
    /* Reset server */
 
761
    srv->rx_cnt = 0;
 
762
 
 
763
    /* Reset client */
 
764
    client->on_status_cnt = 0;
 
765
    client->last_status = PJ_SUCCESS;
 
766
    client->on_rx_data_cnt = 0;
 
767
 
 
768
    /* Wait until on_status() is called with failure. */
 
769
    pj_gettimeofday(&timeout);
 
770
    timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + PJ_STUN_TIMEOUT_VALUE + 5);
 
771
    do {
 
772
        handle_events(cfg, 100);
 
773
        pj_gettimeofday(&t);
 
774
    } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
 
775
 
 
776
    /* Check that callback with correct operation is called */
 
777
    if (client->last_op != PJ_STUN_SOCK_KEEP_ALIVE_OP) {
 
778
        PJ_LOG(3,(THIS_FILE, "    error: expecting keep-alive operation status"));
 
779
        ret = -600;
 
780
        goto on_return;
 
781
    }
 
782
    if (client->last_status == PJ_SUCCESS) {
 
783
        PJ_LOG(3,(THIS_FILE, "    error: expecting failed keep-alive"));
 
784
        ret = -610;
 
785
        goto on_return;
 
786
    }
 
787
    /* Check that client doesn't receive anything */
 
788
    if (client->on_rx_data_cnt != 0) {
 
789
        PJ_LOG(3,(THIS_FILE, "    error: client shouldn't have received anything"));
 
790
        ret = -620;
 
791
        goto on_return;
 
792
    }
 
793
 
 
794
 
 
795
on_return:
 
796
    destroy_server(srv);
 
797
    destroy_client(client);
 
798
    for (i=0; i<7; ++i)
 
799
        handle_events(cfg, 50);
 
800
    return ret;
 
801
}
 
802
 
 
803
 
 
804
#define DO_TEST(expr)       \
 
805
            capture_pjlib_state(&stun_cfg, &pjlib_state); \
 
806
            ret = expr; \
 
807
            if (ret != 0) goto on_return; \
 
808
            ret = check_pjlib_state(&stun_cfg, &pjlib_state); \
 
809
            if (ret != 0) goto on_return;
 
810
 
 
811
 
 
812
int stun_sock_test(void)
 
813
{
 
814
    struct pjlib_state pjlib_state;
 
815
    pj_stun_config stun_cfg;
 
816
    pj_ioqueue_t *ioqueue = NULL;
 
817
    pj_timer_heap_t *timer_heap = NULL;
 
818
    pj_pool_t *pool = NULL;
 
819
    pj_status_t status;
 
820
    int ret = 0;
 
821
 
 
822
    pool = pj_pool_create(mem, NULL, 512, 512, NULL);
 
823
 
 
824
    status = pj_ioqueue_create(pool, 12, &ioqueue);
 
825
    if (status != PJ_SUCCESS) {
 
826
        app_perror("   pj_ioqueue_create()", status);
 
827
        ret = -4;
 
828
        goto on_return;
 
829
    }
 
830
 
 
831
    status = pj_timer_heap_create(pool, 100, &timer_heap);
 
832
    if (status != PJ_SUCCESS) {
 
833
        app_perror("   pj_timer_heap_create()", status);
 
834
        ret = -8;
 
835
        goto on_return;
 
836
    }
 
837
    
 
838
    pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap);
 
839
 
 
840
    DO_TEST(timeout_test(&stun_cfg, PJ_FALSE));
 
841
    DO_TEST(timeout_test(&stun_cfg, PJ_TRUE));
 
842
 
 
843
    DO_TEST(missing_attr_test(&stun_cfg, PJ_FALSE));
 
844
    DO_TEST(missing_attr_test(&stun_cfg, PJ_TRUE));
 
845
 
 
846
    DO_TEST(keep_alive_test(&stun_cfg));
 
847
 
 
848
on_return:
 
849
    if (timer_heap) pj_timer_heap_destroy(timer_heap);
 
850
    if (ioqueue) pj_ioqueue_destroy(ioqueue);
 
851
    if (pool) pj_pool_release(pool);
 
852
    return ret;
 
853
}
 
854
 
 
855