~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/turn_session.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: turn_session.c 4368 2013-02-21 21:53:28Z 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 <pjnath/turn_session.h>
 
21
#include <pjnath/errno.h>
 
22
#include <pjlib-util/srv_resolver.h>
 
23
#include <pj/addr_resolv.h>
 
24
#include <pj/assert.h>
 
25
#include <pj/errno.h>
 
26
#include <pj/hash.h>
 
27
#include <pj/lock.h>
 
28
#include <pj/log.h>
 
29
#include <pj/os.h>
 
30
#include <pj/pool.h>
 
31
#include <pj/rand.h>
 
32
#include <pj/sock.h>
 
33
 
 
34
#define PJ_TURN_CHANNEL_MIN         0x4000
 
35
#define PJ_TURN_CHANNEL_MAX         0x7FFF  /* inclusive */
 
36
#define PJ_TURN_CHANNEL_HTABLE_SIZE 8
 
37
#define PJ_TURN_PERM_HTABLE_SIZE    8
 
38
 
 
39
static const char *state_names[] = 
 
40
{
 
41
    "Null",
 
42
    "Resolving",
 
43
    "Resolved",
 
44
    "Allocating",
 
45
    "Ready",
 
46
    "Deallocating",
 
47
    "Deallocated",
 
48
    "Destroying"
 
49
};
 
50
 
 
51
enum timer_id_t
 
52
{
 
53
    TIMER_NONE,
 
54
    TIMER_KEEP_ALIVE,
 
55
    TIMER_DESTROY
 
56
};
 
57
 
 
58
/* This structure describes a channel binding. A channel binding is index by
 
59
 * the channel number or IP address and port number of the peer.
 
60
 */
 
61
struct ch_t
 
62
{
 
63
    /* The channel number */
 
64
    pj_uint16_t     num;
 
65
 
 
66
    /* PJ_TRUE if we've received successful response to ChannelBind request
 
67
     * for this channel.
 
68
     */
 
69
    pj_bool_t       bound;
 
70
 
 
71
    /* The peer IP address and port */
 
72
    pj_sockaddr     addr;
 
73
 
 
74
    /* The channel binding expiration */
 
75
    pj_time_val     expiry;
 
76
};
 
77
 
 
78
 
 
79
/* This structure describes a permission. A permission is identified by the
 
80
 * IP address only.
 
81
 */
 
82
struct perm_t
 
83
{
 
84
    /* Cache of hash value to speed-up lookup */
 
85
    pj_uint32_t     hval;
 
86
 
 
87
    /* The permission IP address. The port number MUST be zero */
 
88
    pj_sockaddr     addr;
 
89
 
 
90
    /* Number of peers that uses this permission. */
 
91
    unsigned        peer_cnt;
 
92
 
 
93
    /* Automatically renew this permission once it expires? */
 
94
    pj_bool_t       renew;
 
95
 
 
96
    /* The permission expiration */
 
97
    pj_time_val     expiry;
 
98
 
 
99
    /* Arbitrary/random pointer value (token) to map this perm with the 
 
100
     * request to create it. It is used to invalidate this perm when the 
 
101
     * request fails.
 
102
     */
 
103
    void           *req_token;
 
104
};
 
105
 
 
106
 
 
107
/* The TURN client session structure */
 
108
struct pj_turn_session
 
109
{
 
110
    pj_pool_t           *pool;
 
111
    const char          *obj_name;
 
112
    pj_turn_session_cb   cb;
 
113
    void                *user_data;
 
114
    pj_stun_config       stun_cfg;
 
115
    pj_bool_t            is_destroying;
 
116
 
 
117
    pj_grp_lock_t       *grp_lock;
 
118
    int                  busy;
 
119
 
 
120
    pj_turn_state_t      state;
 
121
    pj_status_t          last_status;
 
122
    pj_bool_t            pending_destroy;
 
123
    pj_bool_t            destroy_notified;
 
124
 
 
125
    pj_stun_session     *stun;
 
126
 
 
127
    unsigned             lifetime;
 
128
    int                  ka_interval;
 
129
    pj_time_val          expiry;
 
130
 
 
131
    pj_timer_heap_t     *timer_heap;
 
132
    pj_timer_entry       timer;
 
133
 
 
134
    pj_dns_srv_async_query *dns_async;
 
135
    pj_uint16_t          default_port;
 
136
 
 
137
    pj_uint16_t          af;
 
138
    pj_turn_tp_type      conn_type;
 
139
    pj_uint16_t          srv_addr_cnt;
 
140
    pj_sockaddr         *srv_addr_list;
 
141
    pj_sockaddr         *srv_addr;
 
142
 
 
143
    pj_bool_t            pending_alloc;
 
144
    pj_turn_alloc_param  alloc_param;
 
145
 
 
146
    pj_sockaddr          mapped_addr;
 
147
    pj_sockaddr          relay_addr;
 
148
 
 
149
    pj_hash_table_t     *ch_table;
 
150
    pj_hash_table_t     *perm_table;
 
151
 
 
152
    pj_uint32_t          send_ind_tsx_id[3];
 
153
    /* tx_pkt must be 16bit aligned */
 
154
    pj_uint8_t           tx_pkt[PJ_TURN_MAX_PKT_LEN];
 
155
 
 
156
    pj_uint16_t          next_ch;
 
157
};
 
158
 
 
159
 
 
160
/*
 
161
 * Prototypes.
 
162
 */
 
163
static void sess_shutdown(pj_turn_session *sess,
 
164
                          pj_status_t status);
 
165
static void turn_sess_on_destroy(void *comp);
 
166
static void do_destroy(pj_turn_session *sess);
 
167
static void send_refresh(pj_turn_session *sess, int lifetime);
 
168
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
 
169
                                    void *token,
 
170
                                    const void *pkt,
 
171
                                    pj_size_t pkt_size,
 
172
                                    const pj_sockaddr_t *dst_addr,
 
173
                                    unsigned addr_len);
 
174
static void stun_on_request_complete(pj_stun_session *sess,
 
175
                                     pj_status_t status,
 
176
                                     void *token,
 
177
                                     pj_stun_tx_data *tdata,
 
178
                                     const pj_stun_msg *response,
 
179
                                     const pj_sockaddr_t *src_addr,
 
180
                                     unsigned src_addr_len);
 
181
static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
 
182
                                         const pj_uint8_t *pkt,
 
183
                                         unsigned pkt_len,
 
184
                                         const pj_stun_msg *msg,
 
185
                                         void *token,
 
186
                                         const pj_sockaddr_t *src_addr,
 
187
                                         unsigned src_addr_len);
 
188
static void dns_srv_resolver_cb(void *user_data,
 
189
                                pj_status_t status,
 
190
                                const pj_dns_srv_record *rec);
 
191
static struct ch_t *lookup_ch_by_addr(pj_turn_session *sess,
 
192
                                      const pj_sockaddr_t *addr,
 
193
                                      unsigned addr_len,
 
194
                                      pj_bool_t update,
 
195
                                      pj_bool_t bind_channel);
 
196
static struct ch_t *lookup_ch_by_chnum(pj_turn_session *sess,
 
197
                                       pj_uint16_t chnum);
 
198
static struct perm_t *lookup_perm(pj_turn_session *sess,
 
199
                                  const pj_sockaddr_t *addr,
 
200
                                  unsigned addr_len,
 
201
                                  pj_bool_t update);
 
202
static void invalidate_perm(pj_turn_session *sess,
 
203
                            struct perm_t *perm);
 
204
static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e);
 
205
 
 
206
 
 
207
/*
 
208
 * Create default pj_turn_alloc_param.
 
209
 */
 
210
PJ_DEF(void) pj_turn_alloc_param_default(pj_turn_alloc_param *prm)
 
211
{
 
212
    pj_bzero(prm, sizeof(*prm));
 
213
}
 
214
 
 
215
/*
 
216
 * Duplicate pj_turn_alloc_param.
 
217
 */
 
218
PJ_DEF(void) pj_turn_alloc_param_copy( pj_pool_t *pool, 
 
219
                                       pj_turn_alloc_param *dst,
 
220
                                       const pj_turn_alloc_param *src)
 
221
{
 
222
    PJ_UNUSED_ARG(pool);
 
223
    pj_memcpy(dst, src, sizeof(*dst));
 
224
}
 
225
 
 
226
/*
 
227
 * Get TURN state name.
 
228
 */
 
229
PJ_DEF(const char*) pj_turn_state_name(pj_turn_state_t state)
 
230
{
 
231
    return state_names[state];
 
232
}
 
233
 
 
234
/*
 
235
 * Create TURN client session.
 
236
 */
 
237
PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
 
238
                                            const char *name,
 
239
                                            int af,
 
240
                                            pj_turn_tp_type conn_type,
 
241
                                            pj_grp_lock_t *grp_lock,
 
242
                                            const pj_turn_session_cb *cb,
 
243
                                            unsigned options,
 
244
                                            void *user_data,
 
245
                                            pj_turn_session **p_sess)
 
246
{
 
247
    pj_pool_t *pool;
 
248
    pj_turn_session *sess;
 
249
    pj_stun_session_cb stun_cb;
 
250
    pj_status_t status;
 
251
 
 
252
    PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL);
 
253
    PJ_ASSERT_RETURN(cb->on_send_pkt, PJ_EINVAL);
 
254
 
 
255
    PJ_UNUSED_ARG(options);
 
256
 
 
257
    if (name == NULL)
 
258
        name = "turn%p";
 
259
 
 
260
    /* Allocate and create TURN session */
 
261
    pool = pj_pool_create(cfg->pf, name, PJNATH_POOL_LEN_TURN_SESS,
 
262
                          PJNATH_POOL_INC_TURN_SESS, NULL);
 
263
    sess = PJ_POOL_ZALLOC_T(pool, pj_turn_session);
 
264
    sess->pool = pool;
 
265
    sess->obj_name = pool->obj_name;
 
266
    sess->timer_heap = cfg->timer_heap;
 
267
    sess->af = (pj_uint16_t)af;
 
268
    sess->conn_type = conn_type;
 
269
    sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
 
270
    sess->user_data = user_data;
 
271
    sess->next_ch = PJ_TURN_CHANNEL_MIN;
 
272
 
 
273
    /* Copy STUN session */
 
274
    pj_memcpy(&sess->stun_cfg, cfg, sizeof(pj_stun_config));
 
275
 
 
276
    /* Copy callback */
 
277
    pj_memcpy(&sess->cb, cb, sizeof(*cb));
 
278
 
 
279
    /* Peer hash table */
 
280
    sess->ch_table = pj_hash_create(pool, PJ_TURN_CHANNEL_HTABLE_SIZE);
 
281
 
 
282
    /* Permission hash table */
 
283
    sess->perm_table = pj_hash_create(pool, PJ_TURN_PERM_HTABLE_SIZE);
 
284
 
 
285
    /* Session lock */
 
286
    if (grp_lock) {
 
287
        sess->grp_lock = grp_lock;
 
288
    } else {
 
289
        status = pj_grp_lock_create(pool, NULL, &sess->grp_lock);
 
290
        if (status != PJ_SUCCESS) {
 
291
            pj_pool_release(pool);
 
292
            return status;
 
293
        }
 
294
    }
 
295
 
 
296
    pj_grp_lock_add_ref(sess->grp_lock);
 
297
    pj_grp_lock_add_handler(sess->grp_lock, pool, sess,
 
298
                            &turn_sess_on_destroy);
 
299
 
 
300
    /* Timer */
 
301
    pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event);
 
302
 
 
303
    /* Create STUN session */
 
304
    pj_bzero(&stun_cb, sizeof(stun_cb));
 
305
    stun_cb.on_send_msg = &stun_on_send_msg;
 
306
    stun_cb.on_request_complete = &stun_on_request_complete;
 
307
    stun_cb.on_rx_indication = &stun_on_rx_indication;
 
308
    status = pj_stun_session_create(&sess->stun_cfg, sess->obj_name, &stun_cb,
 
309
                                    PJ_FALSE, sess->grp_lock, &sess->stun);
 
310
    if (status != PJ_SUCCESS) {
 
311
        do_destroy(sess);
 
312
        return status;
 
313
    }
 
314
 
 
315
    /* Attach ourself to STUN session */
 
316
    pj_stun_session_set_user_data(sess->stun, sess);
 
317
 
 
318
    /* Done */
 
319
 
 
320
    PJ_LOG(4,(sess->obj_name, "TURN client session created"));
 
321
 
 
322
    *p_sess = sess;
 
323
    return PJ_SUCCESS;
 
324
}
 
325
 
 
326
 
 
327
static void turn_sess_on_destroy(void *comp)
 
328
{
 
329
    pj_turn_session *sess = (pj_turn_session*) comp;
 
330
 
 
331
    /* Destroy pool */
 
332
    if (sess->pool) {
 
333
        pj_pool_t *pool = sess->pool;
 
334
 
 
335
        PJ_LOG(4,(sess->obj_name, "TURN client session destroyed"));
 
336
 
 
337
        sess->pool = NULL;
 
338
        pj_pool_release(pool);
 
339
    }
 
340
}
 
341
 
 
342
/* Destroy */
 
343
static void do_destroy(pj_turn_session *sess)
 
344
{
 
345
    PJ_LOG(4,(sess->obj_name, "TURN session destroy request, ref_cnt=%d",
 
346
              pj_grp_lock_get_ref(sess->grp_lock)));
 
347
 
 
348
    pj_grp_lock_acquire(sess->grp_lock);
 
349
    if (sess->is_destroying) {
 
350
        pj_grp_lock_release(sess->grp_lock);
 
351
        return;
 
352
    }
 
353
 
 
354
    sess->is_destroying = PJ_TRUE;
 
355
    pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer, TIMER_NONE);
 
356
    pj_stun_session_destroy(sess->stun);
 
357
 
 
358
    pj_grp_lock_dec_ref(sess->grp_lock);
 
359
    pj_grp_lock_release(sess->grp_lock);
 
360
}
 
361
 
 
362
 
 
363
/* Set session state */
 
364
static void set_state(pj_turn_session *sess, enum pj_turn_state_t state)
 
365
{
 
366
    pj_turn_state_t old_state = sess->state;
 
367
 
 
368
    if (state==sess->state)
 
369
        return;
 
370
 
 
371
    PJ_LOG(4,(sess->obj_name, "State changed %s --> %s",
 
372
              state_names[old_state], state_names[state]));
 
373
    sess->state = state;
 
374
 
 
375
    if (sess->cb.on_state) {
 
376
        (*sess->cb.on_state)(sess, old_state, state);
 
377
    }
 
378
}
 
379
 
 
380
/*
 
381
 * Notify application and shutdown the TURN session.
 
382
 */
 
383
static void sess_shutdown(pj_turn_session *sess,
 
384
                          pj_status_t status)
 
385
{
 
386
    pj_bool_t can_destroy = PJ_TRUE;
 
387
 
 
388
    PJ_LOG(4,(sess->obj_name, "Request to shutdown in state %s, cause:%d",
 
389
              state_names[sess->state], status));
 
390
 
 
391
    if (sess->last_status == PJ_SUCCESS && status != PJ_SUCCESS)
 
392
        sess->last_status = status;
 
393
 
 
394
    switch (sess->state) {
 
395
    case PJ_TURN_STATE_NULL:
 
396
        break;
 
397
    case PJ_TURN_STATE_RESOLVING:
 
398
        if (sess->dns_async != NULL) {
 
399
            pj_dns_srv_cancel_query(sess->dns_async, PJ_FALSE);
 
400
            sess->dns_async = NULL;
 
401
        }
 
402
        break;
 
403
    case PJ_TURN_STATE_RESOLVED:
 
404
        break;
 
405
    case PJ_TURN_STATE_ALLOCATING:
 
406
        /* We need to wait until allocation complete */
 
407
        sess->pending_destroy = PJ_TRUE;
 
408
        can_destroy = PJ_FALSE;
 
409
        break;
 
410
    case PJ_TURN_STATE_READY:
 
411
        /* Send REFRESH with LIFETIME=0 */
 
412
        can_destroy = PJ_FALSE;
 
413
        send_refresh(sess, 0);
 
414
        break;
 
415
    case PJ_TURN_STATE_DEALLOCATING:
 
416
        can_destroy = PJ_FALSE;
 
417
        /* This may recursively call this function again with
 
418
         * state==PJ_TURN_STATE_DEALLOCATED.
 
419
         */
 
420
        /* No need to deallocate as we're already deallocating!
 
421
         * See https://trac.pjsip.org/repos/ticket/1551
 
422
        send_refresh(sess, 0);
 
423
        */
 
424
        break;
 
425
    case PJ_TURN_STATE_DEALLOCATED:
 
426
    case PJ_TURN_STATE_DESTROYING:
 
427
        break;
 
428
    }
 
429
 
 
430
    if (can_destroy) {
 
431
        /* Schedule destroy */
 
432
        pj_time_val delay = {0, 0};
 
433
 
 
434
        set_state(sess, PJ_TURN_STATE_DESTROYING);
 
435
 
 
436
        pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
 
437
                                       TIMER_NONE);
 
438
        pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
 
439
                                          &delay, TIMER_DESTROY,
 
440
                                          sess->grp_lock);
 
441
    }
 
442
}
 
443
 
 
444
 
 
445
/*
 
446
 * Public API to destroy TURN client session.
 
447
 */
 
448
PJ_DEF(pj_status_t) pj_turn_session_shutdown(pj_turn_session *sess)
 
449
{
 
450
    PJ_ASSERT_RETURN(sess, PJ_EINVAL);
 
451
 
 
452
    pj_grp_lock_acquire(sess->grp_lock);
 
453
 
 
454
    sess_shutdown(sess, PJ_SUCCESS);
 
455
 
 
456
    pj_grp_lock_release(sess->grp_lock);
 
457
 
 
458
    return PJ_SUCCESS;
 
459
}
 
460
 
 
461
 
 
462
/**
 
463
 * Forcefully destroy the TURN session.
 
464
 */
 
465
PJ_DEF(pj_status_t) pj_turn_session_destroy( pj_turn_session *sess,
 
466
                                             pj_status_t last_err)
 
467
{
 
468
    PJ_ASSERT_RETURN(sess, PJ_EINVAL);
 
469
 
 
470
    if (last_err != PJ_SUCCESS && sess->last_status == PJ_SUCCESS)
 
471
        sess->last_status = last_err;
 
472
    set_state(sess, PJ_TURN_STATE_DEALLOCATED);
 
473
    sess_shutdown(sess, PJ_SUCCESS);
 
474
    return PJ_SUCCESS;
 
475
}
 
476
 
 
477
 
 
478
/*
 
479
 * Get TURN session info.
 
480
 */
 
481
PJ_DEF(pj_status_t) pj_turn_session_get_info( pj_turn_session *sess,
 
482
                                              pj_turn_session_info *info)
 
483
{
 
484
    pj_time_val now;
 
485
 
 
486
    PJ_ASSERT_RETURN(sess && info, PJ_EINVAL);
 
487
 
 
488
    pj_gettimeofday(&now);
 
489
 
 
490
    info->state = sess->state;
 
491
    info->conn_type = sess->conn_type;
 
492
    info->lifetime = sess->expiry.sec - now.sec;
 
493
    info->last_status = sess->last_status;
 
494
 
 
495
    if (sess->srv_addr)
 
496
        pj_memcpy(&info->server, sess->srv_addr, sizeof(info->server));
 
497
    else
 
498
        pj_bzero(&info->server, sizeof(info->server));
 
499
 
 
500
    pj_memcpy(&info->mapped_addr, &sess->mapped_addr, 
 
501
              sizeof(sess->mapped_addr));
 
502
    pj_memcpy(&info->relay_addr, &sess->relay_addr, 
 
503
              sizeof(sess->relay_addr));
 
504
 
 
505
    return PJ_SUCCESS;
 
506
}
 
507
 
 
508
 
 
509
/*
 
510
 * Re-assign user data.
 
511
 */
 
512
PJ_DEF(pj_status_t) pj_turn_session_set_user_data( pj_turn_session *sess,
 
513
                                                   void *user_data)
 
514
{
 
515
    sess->user_data = user_data;
 
516
    return PJ_SUCCESS;
 
517
}
 
518
 
 
519
 
 
520
/**
 
521
 * Retrieve user data.
 
522
 */
 
523
PJ_DEF(void*) pj_turn_session_get_user_data(pj_turn_session *sess)
 
524
{
 
525
    return sess->user_data;
 
526
}
 
527
 
 
528
 
 
529
/*
 
530
 * Configure message logging. By default all flags are enabled.
 
531
 *
 
532
 * @param sess          The TURN client session.
 
533
 * @param flags         Bitmask combination of #pj_stun_sess_msg_log_flag
 
534
 */
 
535
PJ_DEF(void) pj_turn_session_set_log( pj_turn_session *sess,
 
536
                                      unsigned flags)
 
537
{
 
538
    pj_stun_session_set_log(sess->stun, flags);
 
539
}
 
540
 
 
541
 
 
542
/*
 
543
 * Set software name
 
544
 */
 
545
PJ_DEF(pj_status_t) pj_turn_session_set_software_name( pj_turn_session *sess,
 
546
                                                       const pj_str_t *sw)
 
547
{
 
548
    pj_status_t status;
 
549
 
 
550
    pj_grp_lock_acquire(sess->grp_lock);
 
551
    status = pj_stun_session_set_software_name(sess->stun, sw);
 
552
    pj_grp_lock_release(sess->grp_lock);
 
553
 
 
554
    return status;
 
555
}
 
556
 
 
557
 
 
558
/**
 
559
 * Set the server or domain name of the server.
 
560
 */
 
561
PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
 
562
                                                const pj_str_t *domain,
 
563
                                                int default_port,
 
564
                                                pj_dns_resolver *resolver)
 
565
{
 
566
    pj_sockaddr tmp_addr;
 
567
    pj_bool_t is_ip_addr;
 
568
    pj_status_t status;
 
569
 
 
570
    PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL);
 
571
    PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP);
 
572
 
 
573
    pj_grp_lock_acquire(sess->grp_lock);
 
574
 
 
575
    /* See if "domain" contains just IP address */
 
576
    tmp_addr.addr.sa_family = sess->af;
 
577
    status = pj_inet_pton(sess->af, domain, 
 
578
                          pj_sockaddr_get_addr(&tmp_addr));
 
579
    is_ip_addr = (status == PJ_SUCCESS);
 
580
 
 
581
    if (!is_ip_addr && resolver) {
 
582
        /* Resolve with DNS SRV resolution, and fallback to DNS A resolution
 
583
         * if default_port is specified.
 
584
         */
 
585
        unsigned opt = 0;
 
586
        pj_str_t res_name;
 
587
 
 
588
        switch (sess->conn_type) {
 
589
        case PJ_TURN_TP_UDP:
 
590
            res_name = pj_str("_turn._udp.");
 
591
            break;
 
592
        case PJ_TURN_TP_TCP:
 
593
            res_name = pj_str("_turn._tcp.");
 
594
            break;
 
595
        case PJ_TURN_TP_TLS:
 
596
            res_name = pj_str("_turns._tcp.");
 
597
            break;
 
598
        default:
 
599
            status = PJNATH_ETURNINTP;
 
600
            goto on_return;
 
601
        }
 
602
 
 
603
        /* Fallback to DNS A only if default port is specified */
 
604
        if (default_port>0 && default_port<65536) {
 
605
            opt = PJ_DNS_SRV_FALLBACK_A;
 
606
            sess->default_port = (pj_uint16_t)default_port;
 
607
        }
 
608
 
 
609
        PJ_LOG(5,(sess->obj_name, "Resolving %.*s%.*s with DNS SRV",
 
610
                  (int)res_name.slen, res_name.ptr,
 
611
                  (int)domain->slen, domain->ptr));
 
612
        set_state(sess, PJ_TURN_STATE_RESOLVING);
 
613
 
 
614
        /* User may have destroyed us in the callback */
 
615
        if (sess->state != PJ_TURN_STATE_RESOLVING) {
 
616
            status = PJ_ECANCELLED;
 
617
            goto on_return;
 
618
        }
 
619
 
 
620
        status = pj_dns_srv_resolve(domain, &res_name, default_port, 
 
621
                                    sess->pool, resolver, opt, sess, 
 
622
                                    &dns_srv_resolver_cb, &sess->dns_async);
 
623
        if (status != PJ_SUCCESS) {
 
624
            set_state(sess, PJ_TURN_STATE_NULL);
 
625
            goto on_return;
 
626
        }
 
627
 
 
628
    } else {
 
629
        /* Resolver is not specified, resolve with standard gethostbyname().
 
630
         * The default_port MUST be specified in this case.
 
631
         */
 
632
        pj_addrinfo *ai;
 
633
        unsigned i, cnt;
 
634
 
 
635
        /* Default port must be specified */
 
636
        PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL);
 
637
        sess->default_port = (pj_uint16_t)default_port;
 
638
 
 
639
        cnt = PJ_TURN_MAX_DNS_SRV_CNT;
 
640
        ai = (pj_addrinfo*)
 
641
             pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo));
 
642
 
 
643
        PJ_LOG(5,(sess->obj_name, "Resolving %.*s with DNS A",
 
644
                  (int)domain->slen, domain->ptr));
 
645
        set_state(sess, PJ_TURN_STATE_RESOLVING);
 
646
 
 
647
        /* User may have destroyed us in the callback */
 
648
        if (sess->state != PJ_TURN_STATE_RESOLVING) {
 
649
            status = PJ_ECANCELLED;
 
650
            goto on_return;
 
651
        }
 
652
 
 
653
        status = pj_getaddrinfo(sess->af, domain, &cnt, ai);
 
654
        if (status != PJ_SUCCESS)
 
655
            goto on_return;
 
656
 
 
657
        sess->srv_addr_cnt = (pj_uint16_t)cnt;
 
658
        sess->srv_addr_list = (pj_sockaddr*)
 
659
                              pj_pool_calloc(sess->pool, cnt, 
 
660
                                             sizeof(pj_sockaddr));
 
661
        for (i=0; i<cnt; ++i) {
 
662
            pj_sockaddr *addr = &sess->srv_addr_list[i];
 
663
            pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr));
 
664
            addr->addr.sa_family = sess->af;
 
665
            addr->ipv4.sin_port = pj_htons(sess->default_port);
 
666
        }
 
667
 
 
668
        sess->srv_addr = &sess->srv_addr_list[0];
 
669
        set_state(sess, PJ_TURN_STATE_RESOLVED);
 
670
    }
 
671
 
 
672
on_return:
 
673
    pj_grp_lock_release(sess->grp_lock);
 
674
    return status;
 
675
}
 
676
 
 
677
 
 
678
/**
 
679
 * Set credential to be used by the session.
 
680
 */
 
681
PJ_DEF(pj_status_t) pj_turn_session_set_credential(pj_turn_session *sess,
 
682
                                             const pj_stun_auth_cred *cred)
 
683
{
 
684
    PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL);
 
685
    PJ_ASSERT_RETURN(sess->stun, PJ_EINVALIDOP);
 
686
 
 
687
    pj_grp_lock_acquire(sess->grp_lock);
 
688
 
 
689
    pj_stun_session_set_credential(sess->stun, PJ_STUN_AUTH_LONG_TERM, cred);
 
690
 
 
691
    pj_grp_lock_release(sess->grp_lock);
 
692
 
 
693
    return PJ_SUCCESS;
 
694
}
 
695
 
 
696
 
 
697
/**
 
698
 * Create TURN allocation.
 
699
 */
 
700
PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
 
701
                                          const pj_turn_alloc_param *param)
 
702
{
 
703
    pj_stun_tx_data *tdata;
 
704
    pj_bool_t retransmit;
 
705
    pj_status_t status;
 
706
 
 
707
    PJ_ASSERT_RETURN(sess, PJ_EINVAL);
 
708
    PJ_ASSERT_RETURN(sess->state>PJ_TURN_STATE_NULL && 
 
709
                     sess->state<=PJ_TURN_STATE_RESOLVED, 
 
710
                     PJ_EINVALIDOP);
 
711
 
 
712
    pj_grp_lock_acquire(sess->grp_lock);
 
713
 
 
714
    if (param && param != &sess->alloc_param) 
 
715
        pj_turn_alloc_param_copy(sess->pool, &sess->alloc_param, param);
 
716
 
 
717
    if (sess->state < PJ_TURN_STATE_RESOLVED) {
 
718
        sess->pending_alloc = PJ_TRUE;
 
719
 
 
720
        PJ_LOG(4,(sess->obj_name, "Pending ALLOCATE in state %s",
 
721
                  state_names[sess->state]));
 
722
 
 
723
        pj_grp_lock_release(sess->grp_lock);
 
724
        return PJ_SUCCESS;
 
725
 
 
726
    }
 
727
 
 
728
    /* Ready to allocate */
 
729
    pj_assert(sess->state == PJ_TURN_STATE_RESOLVED);
 
730
    
 
731
    /* Create a bare request */
 
732
    status = pj_stun_session_create_req(sess->stun, PJ_STUN_ALLOCATE_REQUEST,
 
733
                                        PJ_STUN_MAGIC, NULL, &tdata);
 
734
    if (status != PJ_SUCCESS) {
 
735
        pj_grp_lock_release(sess->grp_lock);
 
736
        return status;
 
737
    }
 
738
 
 
739
    /* MUST include REQUESTED-TRANSPORT attribute */
 
740
    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
 
741
                              PJ_STUN_ATTR_REQ_TRANSPORT, 
 
742
                              PJ_STUN_SET_RT_PROTO(PJ_TURN_TP_UDP));
 
743
 
 
744
    /* Include BANDWIDTH if requested */
 
745
    if (sess->alloc_param.bandwidth > 0) {
 
746
        pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
 
747
                                  PJ_STUN_ATTR_BANDWIDTH,
 
748
                                  sess->alloc_param.bandwidth);
 
749
    }
 
750
 
 
751
    /* Include LIFETIME if requested */
 
752
    if (sess->alloc_param.lifetime > 0) {
 
753
        pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
 
754
                                  PJ_STUN_ATTR_LIFETIME,
 
755
                                  sess->alloc_param.lifetime);
 
756
    }
 
757
 
 
758
    /* Server address must be set */
 
759
    pj_assert(sess->srv_addr != NULL);
 
760
 
 
761
    /* Send request */
 
762
    set_state(sess, PJ_TURN_STATE_ALLOCATING);
 
763
    retransmit = (sess->conn_type == PJ_TURN_TP_UDP);
 
764
    status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE, 
 
765
                                      retransmit, sess->srv_addr,
 
766
                                      pj_sockaddr_get_len(sess->srv_addr), 
 
767
                                      tdata);
 
768
    if (status != PJ_SUCCESS) {
 
769
        /* Set state back to RESOLVED. We don't want to destroy session now,
 
770
         * let the application do it if it wants to.
 
771
         */
 
772
        set_state(sess, PJ_TURN_STATE_RESOLVED);
 
773
    }
 
774
 
 
775
    pj_grp_lock_release(sess->grp_lock);
 
776
    return status;
 
777
}
 
778
 
 
779
 
 
780
/*
 
781
 * Install or renew permissions
 
782
 */
 
783
PJ_DEF(pj_status_t) pj_turn_session_set_perm( pj_turn_session *sess,
 
784
                                              unsigned addr_cnt,
 
785
                                              const pj_sockaddr addr[],
 
786
                                              unsigned options)
 
787
{
 
788
    pj_stun_tx_data *tdata;
 
789
    pj_hash_iterator_t it_buf, *it;
 
790
    void *req_token;
 
791
    unsigned i, attr_added=0;
 
792
    pj_status_t status;
 
793
 
 
794
    PJ_ASSERT_RETURN(sess && addr_cnt && addr, PJ_EINVAL);
 
795
 
 
796
    pj_grp_lock_acquire(sess->grp_lock);
 
797
 
 
798
    /* Create a bare CreatePermission request */
 
799
    status = pj_stun_session_create_req(sess->stun, 
 
800
                                        PJ_STUN_CREATE_PERM_REQUEST,
 
801
                                        PJ_STUN_MAGIC, NULL, &tdata);
 
802
    if (status != PJ_SUCCESS) {
 
803
        pj_grp_lock_release(sess->grp_lock);
 
804
        return status;
 
805
    }
 
806
 
 
807
    /* Create request token to map the request to the perm structures
 
808
     * which the request belongs.
 
809
     */
 
810
    req_token = (void*)(long)pj_rand();
 
811
 
 
812
    /* Process the addresses */
 
813
    for (i=0; i<addr_cnt; ++i) {
 
814
        struct perm_t *perm;
 
815
 
 
816
        /* Lookup the perm structure and create if it doesn't exist */
 
817
        perm = lookup_perm(sess, &addr[i], pj_sockaddr_get_len(&addr[i]),
 
818
                           PJ_TRUE);
 
819
        perm->renew = (options & 0x01);
 
820
 
 
821
        /* Only add to the request if the request doesn't contain this
 
822
         * address yet.
 
823
         */
 
824
        if (perm->req_token != req_token) {
 
825
            perm->req_token = req_token;
 
826
 
 
827
            /* Add XOR-PEER-ADDRESS */
 
828
            status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
 
829
                                                   PJ_STUN_ATTR_XOR_PEER_ADDR,
 
830
                                                   PJ_TRUE,
 
831
                                                   &addr[i],
 
832
                                                   sizeof(addr[i]));
 
833
            if (status != PJ_SUCCESS)
 
834
                goto on_error;
 
835
 
 
836
            ++attr_added;
 
837
        }
 
838
    }
 
839
 
 
840
    pj_assert(attr_added != 0);
 
841
 
 
842
    /* Send the request */
 
843
    status = pj_stun_session_send_msg(sess->stun, req_token, PJ_FALSE, 
 
844
                                      (sess->conn_type==PJ_TURN_TP_UDP),
 
845
                                      sess->srv_addr,
 
846
                                      pj_sockaddr_get_len(sess->srv_addr), 
 
847
                                      tdata);
 
848
    if (status != PJ_SUCCESS) {
 
849
        /* tdata is already destroyed */
 
850
        tdata = NULL;
 
851
        goto on_error;
 
852
    }
 
853
 
 
854
    pj_grp_lock_release(sess->grp_lock);
 
855
    return PJ_SUCCESS;
 
856
 
 
857
on_error:
 
858
    /* destroy tdata */
 
859
    if (tdata) {
 
860
        pj_stun_msg_destroy_tdata(sess->stun, tdata);
 
861
    }
 
862
    /* invalidate perm structures associated with this request */
 
863
    it = pj_hash_first(sess->perm_table, &it_buf);
 
864
    while (it) {
 
865
        struct perm_t *perm = (struct perm_t*)
 
866
                              pj_hash_this(sess->perm_table, it);
 
867
        it = pj_hash_next(sess->perm_table, it);
 
868
        if (perm->req_token == req_token)
 
869
            invalidate_perm(sess, perm);
 
870
    }
 
871
    pj_grp_lock_release(sess->grp_lock);
 
872
    return status;
 
873
}
 
874
 
 
875
/*
 
876
 * Send REFRESH
 
877
 */
 
878
static void send_refresh(pj_turn_session *sess, int lifetime)
 
879
{
 
880
    pj_stun_tx_data *tdata;
 
881
    pj_status_t status;
 
882
 
 
883
    PJ_ASSERT_ON_FAIL(sess->state==PJ_TURN_STATE_READY, return);
 
884
 
 
885
    /* Create a bare REFRESH request */
 
886
    status = pj_stun_session_create_req(sess->stun, PJ_STUN_REFRESH_REQUEST,
 
887
                                        PJ_STUN_MAGIC, NULL, &tdata);
 
888
    if (status != PJ_SUCCESS)
 
889
        goto on_error;
 
890
 
 
891
    /* Add LIFETIME */
 
892
    if (lifetime >= 0) {
 
893
        pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
 
894
                                  PJ_STUN_ATTR_LIFETIME, lifetime);
 
895
    }
 
896
 
 
897
    /* Send request */
 
898
    if (lifetime == 0) {
 
899
        set_state(sess, PJ_TURN_STATE_DEALLOCATING);
 
900
    }
 
901
 
 
902
    status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE, 
 
903
                                      (sess->conn_type==PJ_TURN_TP_UDP),
 
904
                                      sess->srv_addr,
 
905
                                      pj_sockaddr_get_len(sess->srv_addr), 
 
906
                                      tdata);
 
907
    if (status != PJ_SUCCESS)
 
908
        goto on_error;
 
909
 
 
910
    return;
 
911
 
 
912
on_error:
 
913
    if (lifetime == 0) {
 
914
        set_state(sess, PJ_TURN_STATE_DEALLOCATED);
 
915
        sess_shutdown(sess, status);
 
916
    }
 
917
}
 
918
 
 
919
 
 
920
/**
 
921
 * Relay data to the specified peer through the session.
 
922
 */
 
923
PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
 
924
                                            const pj_uint8_t *pkt,
 
925
                                            unsigned pkt_len,
 
926
                                            const pj_sockaddr_t *addr,
 
927
                                            unsigned addr_len)
 
928
{
 
929
    struct ch_t *ch;
 
930
    struct perm_t *perm;
 
931
    pj_status_t status;
 
932
 
 
933
    PJ_ASSERT_RETURN(sess && pkt && pkt_len && addr && addr_len, 
 
934
                     PJ_EINVAL);
 
935
 
 
936
    /* Return error if we're not ready */
 
937
    if (sess->state != PJ_TURN_STATE_READY) {
 
938
        return PJ_EIGNORED;
 
939
    }
 
940
 
 
941
    /* Lock session now */
 
942
    pj_grp_lock_acquire(sess->grp_lock);
 
943
 
 
944
    /* Lookup permission first */
 
945
    perm = lookup_perm(sess, addr, pj_sockaddr_get_len(addr), PJ_FALSE);
 
946
    if (perm == NULL) {
 
947
        /* Permission doesn't exist, install it first */
 
948
        char ipstr[PJ_INET6_ADDRSTRLEN+2];
 
949
 
 
950
        PJ_LOG(4,(sess->obj_name, 
 
951
                  "sendto(): IP %s has no permission, requesting it first..",
 
952
                  pj_sockaddr_print(addr, ipstr, sizeof(ipstr), 2)));
 
953
 
 
954
        status = pj_turn_session_set_perm(sess, 1, (const pj_sockaddr*)addr, 
 
955
                                          0);
 
956
        if (status != PJ_SUCCESS) {
 
957
            pj_grp_lock_release(sess->grp_lock);
 
958
            return status;
 
959
        }
 
960
    }
 
961
 
 
962
    /* See if the peer is bound to a channel number */
 
963
    ch = lookup_ch_by_addr(sess, addr, pj_sockaddr_get_len(addr), 
 
964
                           PJ_FALSE, PJ_FALSE);
 
965
    if (ch && ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound) {
 
966
        unsigned total_len;
 
967
 
 
968
        /* Peer is assigned a channel number, we can use ChannelData */
 
969
        pj_turn_channel_data *cd = (pj_turn_channel_data*)sess->tx_pkt;
 
970
        
 
971
        pj_assert(sizeof(*cd)==4);
 
972
 
 
973
        /* Calculate total length, including paddings */
 
974
        total_len = (pkt_len + sizeof(*cd) + 3) & (~3);
 
975
        if (total_len > sizeof(sess->tx_pkt)) {
 
976
            status = PJ_ETOOBIG;
 
977
            goto on_return;
 
978
        }
 
979
 
 
980
        cd->ch_number = pj_htons((pj_uint16_t)ch->num);
 
981
        cd->length = pj_htons((pj_uint16_t)pkt_len);
 
982
        pj_memcpy(cd+1, pkt, pkt_len);
 
983
 
 
984
        pj_assert(sess->srv_addr != NULL);
 
985
 
 
986
        status = sess->cb.on_send_pkt(sess, sess->tx_pkt, total_len,
 
987
                                      sess->srv_addr,
 
988
                                      pj_sockaddr_get_len(sess->srv_addr));
 
989
 
 
990
    } else {
 
991
        /* Use Send Indication. */
 
992
        pj_stun_sockaddr_attr peer_attr;
 
993
        pj_stun_binary_attr data_attr;
 
994
        pj_stun_msg send_ind;
 
995
        pj_size_t send_ind_len;
 
996
 
 
997
        /* Increment counter */
 
998
        ++sess->send_ind_tsx_id[2];
 
999
 
 
1000
        /* Create blank SEND-INDICATION */
 
1001
        status = pj_stun_msg_init(&send_ind, PJ_STUN_SEND_INDICATION,
 
1002
                                  PJ_STUN_MAGIC, 
 
1003
                                  (const pj_uint8_t*)sess->send_ind_tsx_id);
 
1004
        if (status != PJ_SUCCESS)
 
1005
            goto on_return;
 
1006
 
 
1007
        /* Add XOR-PEER-ADDRESS */
 
1008
        pj_stun_sockaddr_attr_init(&peer_attr, PJ_STUN_ATTR_XOR_PEER_ADDR,
 
1009
                                   PJ_TRUE, addr, addr_len);
 
1010
        pj_stun_msg_add_attr(&send_ind, (pj_stun_attr_hdr*)&peer_attr);
 
1011
 
 
1012
        /* Add DATA attribute */
 
1013
        pj_stun_binary_attr_init(&data_attr, NULL, PJ_STUN_ATTR_DATA, NULL, 0);
 
1014
        data_attr.data = (pj_uint8_t*)pkt;
 
1015
        data_attr.length = pkt_len;
 
1016
        pj_stun_msg_add_attr(&send_ind, (pj_stun_attr_hdr*)&data_attr);
 
1017
 
 
1018
        /* Encode the message */
 
1019
        status = pj_stun_msg_encode(&send_ind, sess->tx_pkt, 
 
1020
                                    sizeof(sess->tx_pkt), 0,
 
1021
                                    NULL, &send_ind_len);
 
1022
        if (status != PJ_SUCCESS)
 
1023
            goto on_return;
 
1024
 
 
1025
        /* Send the Send Indication */
 
1026
        status = sess->cb.on_send_pkt(sess, sess->tx_pkt, send_ind_len,
 
1027
                                      sess->srv_addr,
 
1028
                                      pj_sockaddr_get_len(sess->srv_addr));
 
1029
    }
 
1030
 
 
1031
on_return:
 
1032
    pj_grp_lock_release(sess->grp_lock);
 
1033
    return status;
 
1034
}
 
1035
 
 
1036
 
 
1037
/**
 
1038
 * Bind a peer address to a channel number.
 
1039
 */
 
1040
PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
 
1041
                                                 const pj_sockaddr_t *peer_adr,
 
1042
                                                 unsigned addr_len)
 
1043
{
 
1044
    struct ch_t *ch;
 
1045
    pj_stun_tx_data *tdata;
 
1046
    pj_uint16_t ch_num;
 
1047
    pj_status_t status;
 
1048
 
 
1049
    PJ_ASSERT_RETURN(sess && peer_adr && addr_len, PJ_EINVAL);
 
1050
    PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP);
 
1051
 
 
1052
    pj_grp_lock_acquire(sess->grp_lock);
 
1053
 
 
1054
    /* Create blank ChannelBind request */
 
1055
    status = pj_stun_session_create_req(sess->stun, 
 
1056
                                        PJ_STUN_CHANNEL_BIND_REQUEST,
 
1057
                                        PJ_STUN_MAGIC, NULL, &tdata);
 
1058
    if (status != PJ_SUCCESS)
 
1059
        goto on_return;
 
1060
 
 
1061
    /* Lookup if this peer has already been assigned a number */
 
1062
    ch = lookup_ch_by_addr(sess, peer_adr, pj_sockaddr_get_len(peer_adr),
 
1063
                           PJ_TRUE, PJ_FALSE);
 
1064
    pj_assert(ch);
 
1065
 
 
1066
    if (ch->num != PJ_TURN_INVALID_CHANNEL) {
 
1067
        /* Channel is already bound. This is a refresh request. */
 
1068
        ch_num = ch->num;
 
1069
    } else {
 
1070
        PJ_ASSERT_ON_FAIL(sess->next_ch <= PJ_TURN_CHANNEL_MAX, 
 
1071
                            {status=PJ_ETOOMANY; goto on_return;});
 
1072
        ch->num = ch_num = sess->next_ch++;
 
1073
    }
 
1074
 
 
1075
    /* Add CHANNEL-NUMBER attribute */
 
1076
    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
 
1077
                              PJ_STUN_ATTR_CHANNEL_NUMBER,
 
1078
                              PJ_STUN_SET_CH_NB(ch_num));
 
1079
 
 
1080
    /* Add XOR-PEER-ADDRESS attribute */
 
1081
    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
 
1082
                                  PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE,
 
1083
                                  peer_adr, addr_len);
 
1084
 
 
1085
    /* Send the request, associate peer data structure with tdata 
 
1086
     * for future reference when we receive the ChannelBind response.
 
1087
     */
 
1088
    status = pj_stun_session_send_msg(sess->stun, ch, PJ_FALSE, 
 
1089
                                      (sess->conn_type==PJ_TURN_TP_UDP),
 
1090
                                      sess->srv_addr,
 
1091
                                      pj_sockaddr_get_len(sess->srv_addr),
 
1092
                                      tdata);
 
1093
 
 
1094
on_return:
 
1095
    pj_grp_lock_release(sess->grp_lock);
 
1096
    return status;
 
1097
}
 
1098
 
 
1099
 
 
1100
/**
 
1101
 * Notify TURN client session upon receiving a packet from server.
 
1102
 * The packet maybe a STUN packet or ChannelData packet.
 
1103
 */
 
1104
PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
 
1105
                                              void *pkt,
 
1106
                                              pj_size_t pkt_len,
 
1107
                                              pj_size_t *parsed_len)
 
1108
{
 
1109
    pj_bool_t is_stun;
 
1110
    pj_status_t status;
 
1111
    pj_bool_t is_datagram;
 
1112
 
 
1113
    /* Packet could be ChannelData or STUN message (response or
 
1114
     * indication).
 
1115
     */
 
1116
 
 
1117
    /* Start locking the session */
 
1118
    pj_grp_lock_acquire(sess->grp_lock);
 
1119
 
 
1120
    is_datagram = (sess->conn_type==PJ_TURN_TP_UDP);
 
1121
 
 
1122
    /* Quickly check if this is STUN message */
 
1123
    is_stun = ((((pj_uint8_t*)pkt)[0] & 0xC0) == 0);
 
1124
 
 
1125
    if (is_stun) {
 
1126
        /* This looks like STUN, give it to the STUN session */
 
1127
        unsigned options;
 
1128
 
 
1129
        options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
 
1130
        if (is_datagram)
 
1131
            options |= PJ_STUN_IS_DATAGRAM;
 
1132
        status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,
 
1133
                                         options, NULL, parsed_len,
 
1134
                                         sess->srv_addr,
 
1135
                                         pj_sockaddr_get_len(sess->srv_addr));
 
1136
 
 
1137
    } else {
 
1138
        /* This must be ChannelData. */
 
1139
        pj_turn_channel_data cd;
 
1140
        struct ch_t *ch;
 
1141
 
 
1142
        if (pkt_len < 4) {
 
1143
            if (parsed_len) *parsed_len = 0;
 
1144
            return PJ_ETOOSMALL;
 
1145
        }
 
1146
 
 
1147
        /* Decode ChannelData packet */
 
1148
        pj_memcpy(&cd, pkt, sizeof(pj_turn_channel_data));
 
1149
        cd.ch_number = pj_ntohs(cd.ch_number);
 
1150
        cd.length = pj_ntohs(cd.length);
 
1151
 
 
1152
        /* Check that size is sane */
 
1153
        if (pkt_len < cd.length+sizeof(cd)) {
 
1154
            if (parsed_len) {
 
1155
                if (is_datagram) {
 
1156
                    /* Discard the datagram */
 
1157
                    *parsed_len = pkt_len;
 
1158
                } else {
 
1159
                    /* Insufficient fragment */
 
1160
                    *parsed_len = 0;
 
1161
                }
 
1162
            }
 
1163
            status = PJ_ETOOSMALL;
 
1164
            goto on_return;
 
1165
        } else {
 
1166
            if (parsed_len) {
 
1167
                /* Apply padding too */
 
1168
                *parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd);
 
1169
            }
 
1170
        }
 
1171
 
 
1172
        /* Lookup channel */
 
1173
        ch = lookup_ch_by_chnum(sess, cd.ch_number);
 
1174
        if (!ch || !ch->bound) {
 
1175
            status = PJ_ENOTFOUND;
 
1176
            goto on_return;
 
1177
        }
 
1178
 
 
1179
        /* Notify application */
 
1180
        if (sess->cb.on_rx_data) {
 
1181
            (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd), 
 
1182
                                   cd.length, &ch->addr,
 
1183
                                   pj_sockaddr_get_len(&ch->addr));
 
1184
        }
 
1185
 
 
1186
        status = PJ_SUCCESS;
 
1187
    }
 
1188
 
 
1189
on_return:
 
1190
    pj_grp_lock_release(sess->grp_lock);
 
1191
    return status;
 
1192
}
 
1193
 
 
1194
 
 
1195
/*
 
1196
 * This is a callback from STUN session to send outgoing packet.
 
1197
 */
 
1198
static pj_status_t stun_on_send_msg(pj_stun_session *stun,
 
1199
                                    void *token,
 
1200
                                    const void *pkt,
 
1201
                                    pj_size_t pkt_size,
 
1202
                                    const pj_sockaddr_t *dst_addr,
 
1203
                                    unsigned addr_len)
 
1204
{
 
1205
    pj_turn_session *sess;
 
1206
 
 
1207
    PJ_UNUSED_ARG(token);
 
1208
 
 
1209
    sess = (pj_turn_session*) pj_stun_session_get_user_data(stun);
 
1210
    return (*sess->cb.on_send_pkt)(sess, (const pj_uint8_t*)pkt, pkt_size, 
 
1211
                                   dst_addr, addr_len);
 
1212
}
 
1213
 
 
1214
 
 
1215
/*
 
1216
 * Handle failed ALLOCATE or REFRESH request. This may switch to alternate
 
1217
 * server if we have one.
 
1218
 */
 
1219
static void on_session_fail( pj_turn_session *sess, 
 
1220
                             enum pj_stun_method_e method,
 
1221
                             pj_status_t status,
 
1222
                             const pj_str_t *reason)
 
1223
{
 
1224
    sess->last_status = status;
 
1225
 
 
1226
    do {
 
1227
        pj_str_t reason1;
 
1228
        char err_msg[PJ_ERR_MSG_SIZE];
 
1229
 
 
1230
        if (reason == NULL) {
 
1231
            pj_strerror(status, err_msg, sizeof(err_msg));
 
1232
            reason1 = pj_str(err_msg);
 
1233
            reason = &reason1;
 
1234
        }
 
1235
 
 
1236
        PJ_LOG(4,(sess->obj_name, "%s error: %.*s",
 
1237
                  pj_stun_get_method_name(method),
 
1238
                  (int)reason->slen, reason->ptr));
 
1239
 
 
1240
        /* If this is ALLOCATE response and we don't have more server 
 
1241
         * addresses to try, notify application and destroy the TURN
 
1242
         * session.
 
1243
         */
 
1244
        if (method==PJ_STUN_ALLOCATE_METHOD &&
 
1245
            sess->srv_addr == &sess->srv_addr_list[sess->srv_addr_cnt-1]) 
 
1246
        {
 
1247
 
 
1248
            set_state(sess, PJ_TURN_STATE_DEALLOCATED);
 
1249
            sess_shutdown(sess, status);
 
1250
            return;
 
1251
        }
 
1252
 
 
1253
        /* Otherwise if this is not ALLOCATE response, notify application
 
1254
         * that session has been TERMINATED.
 
1255
         */
 
1256
        if (method!=PJ_STUN_ALLOCATE_METHOD) {
 
1257
            set_state(sess, PJ_TURN_STATE_DEALLOCATED);
 
1258
            sess_shutdown(sess, status);
 
1259
            return;
 
1260
        }
 
1261
 
 
1262
        /* Try next server */
 
1263
        ++sess->srv_addr;
 
1264
        reason = NULL;
 
1265
 
 
1266
        PJ_LOG(4,(sess->obj_name, "Trying next server"));
 
1267
        set_state(sess, PJ_TURN_STATE_RESOLVED);
 
1268
 
 
1269
    } while (0);
 
1270
}
 
1271
 
 
1272
 
 
1273
/*
 
1274
 * Handle successful response to ALLOCATE or REFRESH request.
 
1275
 */
 
1276
static void on_allocate_success(pj_turn_session *sess, 
 
1277
                                enum pj_stun_method_e method,
 
1278
                                const pj_stun_msg *msg)
 
1279
{
 
1280
    const pj_stun_lifetime_attr *lf_attr;
 
1281
    const pj_stun_xor_relayed_addr_attr *raddr_attr;
 
1282
    const pj_stun_sockaddr_attr *mapped_attr;
 
1283
    pj_str_t s;
 
1284
    pj_time_val timeout;
 
1285
 
 
1286
    /* Must have LIFETIME attribute */
 
1287
    lf_attr = (const pj_stun_lifetime_attr*)
 
1288
              pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
 
1289
    if (lf_attr == NULL) {
 
1290
        on_session_fail(sess, method, PJNATH_EINSTUNMSG,
 
1291
                        pj_cstr(&s, "Error: Missing LIFETIME attribute"));
 
1292
        return;
 
1293
    }
 
1294
 
 
1295
    /* If LIFETIME is zero, this is a deallocation */
 
1296
    if (lf_attr->value == 0) {
 
1297
        set_state(sess, PJ_TURN_STATE_DEALLOCATED);
 
1298
        sess_shutdown(sess, PJ_SUCCESS);
 
1299
        return;
 
1300
    }
 
1301
 
 
1302
    /* Update lifetime and keep-alive interval */
 
1303
    sess->lifetime = lf_attr->value;
 
1304
    pj_gettimeofday(&sess->expiry);
 
1305
 
 
1306
    if (sess->lifetime < PJ_TURN_KEEP_ALIVE_SEC) {
 
1307
        if (sess->lifetime <= 2) {
 
1308
            on_session_fail(sess, method, PJ_ETOOSMALL,
 
1309
                             pj_cstr(&s, "Error: LIFETIME too small"));
 
1310
            return;
 
1311
        }
 
1312
        sess->ka_interval = sess->lifetime - 2;
 
1313
        sess->expiry.sec += (sess->ka_interval-1);
 
1314
    } else {
 
1315
        int timeout;
 
1316
 
 
1317
        sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
 
1318
 
 
1319
        timeout = sess->lifetime - PJ_TURN_REFRESH_SEC_BEFORE;
 
1320
        if (timeout < sess->ka_interval)
 
1321
            timeout = sess->ka_interval - 1;
 
1322
 
 
1323
        sess->expiry.sec += timeout;
 
1324
    }
 
1325
 
 
1326
    /* Check that relayed transport address contains correct
 
1327
     * address family.
 
1328
     */
 
1329
    raddr_attr = (const pj_stun_xor_relayed_addr_attr*)
 
1330
                 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_RELAYED_ADDR, 0);
 
1331
    if (raddr_attr == NULL && method==PJ_STUN_ALLOCATE_METHOD) {
 
1332
        on_session_fail(sess, method, PJNATH_EINSTUNMSG,
 
1333
                        pj_cstr(&s, "Error: Received ALLOCATE without "
 
1334
                                    "RELAY-ADDRESS attribute"));
 
1335
        return;
 
1336
    }
 
1337
    if (raddr_attr && raddr_attr->sockaddr.addr.sa_family != sess->af) {
 
1338
        on_session_fail(sess, method, PJNATH_EINSTUNMSG,
 
1339
                        pj_cstr(&s, "Error: RELAY-ADDRESS with non IPv4"
 
1340
                                    " address family is not supported "
 
1341
                                    "for now"));
 
1342
        return;
 
1343
    }
 
1344
    if (raddr_attr && !pj_sockaddr_has_addr(&raddr_attr->sockaddr)) {
 
1345
        on_session_fail(sess, method, PJNATH_EINSTUNMSG,
 
1346
                        pj_cstr(&s, "Error: Invalid IP address in "
 
1347
                                    "RELAY-ADDRESS attribute"));
 
1348
        return;
 
1349
    }
 
1350
    
 
1351
    /* Save relayed address */
 
1352
    if (raddr_attr) {
 
1353
        /* If we already have relay address, check if the relay address 
 
1354
         * in the response matches our relay address.
 
1355
         */
 
1356
        if (pj_sockaddr_has_addr(&sess->relay_addr)) {
 
1357
            if (pj_sockaddr_cmp(&sess->relay_addr, &raddr_attr->sockaddr)) {
 
1358
                on_session_fail(sess, method, PJNATH_EINSTUNMSG,
 
1359
                                pj_cstr(&s, "Error: different RELAY-ADDRESS is"
 
1360
                                            "returned by server"));
 
1361
                return;
 
1362
            }
 
1363
        } else {
 
1364
            /* Otherwise save the relayed address */
 
1365
            pj_memcpy(&sess->relay_addr, &raddr_attr->sockaddr, 
 
1366
                      sizeof(pj_sockaddr));
 
1367
        }
 
1368
    }
 
1369
 
 
1370
    /* Get mapped address */
 
1371
    mapped_attr = (const pj_stun_sockaddr_attr*)
 
1372
                  pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0);
 
1373
    if (mapped_attr) {
 
1374
        pj_memcpy(&sess->mapped_addr, &mapped_attr->sockaddr,
 
1375
                  sizeof(mapped_attr->sockaddr));
 
1376
    }
 
1377
 
 
1378
    /* Success */
 
1379
 
 
1380
    /* Cancel existing keep-alive timer, if any */
 
1381
    pj_assert(sess->timer.id != TIMER_DESTROY);
 
1382
    if (sess->timer.id == TIMER_KEEP_ALIVE) {
 
1383
        pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
 
1384
                                       TIMER_NONE);
 
1385
    }
 
1386
 
 
1387
    /* Start keep-alive timer once allocation succeeds */
 
1388
    if (sess->state < PJ_TURN_STATE_DEALLOCATING) {
 
1389
        timeout.sec = sess->ka_interval;
 
1390
        timeout.msec = 0;
 
1391
 
 
1392
        pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
 
1393
                                          &timeout, TIMER_KEEP_ALIVE,
 
1394
                                          sess->grp_lock);
 
1395
 
 
1396
        set_state(sess, PJ_TURN_STATE_READY);
 
1397
    }
 
1398
}
 
1399
 
 
1400
/*
 
1401
 * Notification from STUN session on request completion.
 
1402
 */
 
1403
static void stun_on_request_complete(pj_stun_session *stun,
 
1404
                                     pj_status_t status,
 
1405
                                     void *token,
 
1406
                                     pj_stun_tx_data *tdata,
 
1407
                                     const pj_stun_msg *response,
 
1408
                                     const pj_sockaddr_t *src_addr,
 
1409
                                     unsigned src_addr_len)
 
1410
{
 
1411
    pj_turn_session *sess;
 
1412
    enum pj_stun_method_e method = (enum pj_stun_method_e) 
 
1413
                                   PJ_STUN_GET_METHOD(tdata->msg->hdr.type);
 
1414
 
 
1415
    PJ_UNUSED_ARG(src_addr);
 
1416
    PJ_UNUSED_ARG(src_addr_len);
 
1417
 
 
1418
    sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
 
1419
 
 
1420
    if (method == PJ_STUN_ALLOCATE_METHOD) {
 
1421
 
 
1422
        /* Destroy if we have pending destroy request */
 
1423
        if (sess->pending_destroy) {
 
1424
            if (status == PJ_SUCCESS)
 
1425
                sess->state = PJ_TURN_STATE_READY;
 
1426
            else
 
1427
                sess->state = PJ_TURN_STATE_DEALLOCATED;
 
1428
            sess_shutdown(sess, PJ_SUCCESS);
 
1429
            return;
 
1430
        }
 
1431
 
 
1432
        /* Handle ALLOCATE response */
 
1433
        if (status==PJ_SUCCESS && 
 
1434
            PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 
 
1435
        {
 
1436
 
 
1437
            /* Successful Allocate response */
 
1438
            on_allocate_success(sess, method, response);
 
1439
 
 
1440
        } else {
 
1441
            /* Failed Allocate request */
 
1442
            const pj_str_t *err_msg = NULL;
 
1443
 
 
1444
            if (status == PJ_SUCCESS) {
 
1445
                const pj_stun_errcode_attr *err_attr;
 
1446
                err_attr = (const pj_stun_errcode_attr*)
 
1447
                           pj_stun_msg_find_attr(response,
 
1448
                                                 PJ_STUN_ATTR_ERROR_CODE, 0);
 
1449
                if (err_attr) {
 
1450
                    status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
 
1451
                    err_msg = &err_attr->reason;
 
1452
                } else {
 
1453
                    status = PJNATH_EINSTUNMSG;
 
1454
                }
 
1455
            }
 
1456
 
 
1457
            on_session_fail(sess, method, status, err_msg);
 
1458
        }
 
1459
 
 
1460
    } else if (method == PJ_STUN_REFRESH_METHOD) {
 
1461
        /* Handle Refresh response */
 
1462
        if (status==PJ_SUCCESS && 
 
1463
            PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 
 
1464
        {
 
1465
            /* Success, schedule next refresh. */
 
1466
            on_allocate_success(sess, method, response);
 
1467
 
 
1468
        } else {
 
1469
            /* Failed Refresh request */
 
1470
            const pj_str_t *err_msg = NULL;
 
1471
 
 
1472
            pj_assert(status != PJ_SUCCESS);
 
1473
 
 
1474
            if (response) {
 
1475
                const pj_stun_errcode_attr *err_attr;
 
1476
                err_attr = (const pj_stun_errcode_attr*)
 
1477
                           pj_stun_msg_find_attr(response,
 
1478
                                                 PJ_STUN_ATTR_ERROR_CODE, 0);
 
1479
                if (err_attr) {
 
1480
                    status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
 
1481
                    err_msg = &err_attr->reason;
 
1482
                }
 
1483
            }
 
1484
 
 
1485
            /* Notify and destroy */
 
1486
            on_session_fail(sess, method, status, err_msg);
 
1487
        }
 
1488
 
 
1489
    } else if (method == PJ_STUN_CHANNEL_BIND_METHOD) {
 
1490
        /* Handle ChannelBind response */
 
1491
        if (status==PJ_SUCCESS && 
 
1492
            PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 
 
1493
        {
 
1494
            /* Successful ChannelBind response */
 
1495
            struct ch_t *ch = (struct ch_t*)token;
 
1496
 
 
1497
            pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL);
 
1498
            ch->bound = PJ_TRUE;
 
1499
 
 
1500
            /* Update hash table */
 
1501
            lookup_ch_by_addr(sess, &ch->addr,
 
1502
                              pj_sockaddr_get_len(&ch->addr),
 
1503
                              PJ_TRUE, PJ_TRUE);
 
1504
 
 
1505
        } else {
 
1506
            /* Failed ChannelBind response */
 
1507
            pj_str_t reason = {"", 0};
 
1508
            int err_code = 0;
 
1509
            char errbuf[PJ_ERR_MSG_SIZE];
 
1510
 
 
1511
            pj_assert(status != PJ_SUCCESS);
 
1512
 
 
1513
            if (response) {
 
1514
                const pj_stun_errcode_attr *err_attr;
 
1515
                err_attr = (const pj_stun_errcode_attr*)
 
1516
                           pj_stun_msg_find_attr(response,
 
1517
                                                 PJ_STUN_ATTR_ERROR_CODE, 0);
 
1518
                if (err_attr) {
 
1519
                    err_code = err_attr->err_code;
 
1520
                    status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
 
1521
                    reason = err_attr->reason;
 
1522
                }
 
1523
            } else {
 
1524
                err_code = status;
 
1525
                reason = pj_strerror(status, errbuf, sizeof(errbuf));
 
1526
            }
 
1527
 
 
1528
            PJ_LOG(1,(sess->obj_name, "ChannelBind failed: %d/%.*s",
 
1529
                      err_code, (int)reason.slen, reason.ptr));
 
1530
 
 
1531
            if (err_code == PJ_STUN_SC_ALLOCATION_MISMATCH) {
 
1532
                /* Allocation mismatch means allocation no longer exists */
 
1533
                on_session_fail(sess, PJ_STUN_CHANNEL_BIND_METHOD,
 
1534
                                status, &reason);
 
1535
                return;
 
1536
            }
 
1537
        }
 
1538
 
 
1539
    } else if (method == PJ_STUN_CREATE_PERM_METHOD) {
 
1540
        /* Handle CreatePermission response */
 
1541
        if (status==PJ_SUCCESS && 
 
1542
            PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 
 
1543
        {
 
1544
            /* No special handling when the request is successful. */
 
1545
        } else {
 
1546
            /* Iterate the permission table and invalidate all permissions
 
1547
             * that are related to this request.
 
1548
             */
 
1549
            pj_hash_iterator_t it_buf, *it;
 
1550
            char ipstr[PJ_INET6_ADDRSTRLEN+10];
 
1551
            int err_code;
 
1552
            char errbuf[PJ_ERR_MSG_SIZE];
 
1553
            pj_str_t reason;
 
1554
 
 
1555
            pj_assert(status != PJ_SUCCESS);
 
1556
 
 
1557
            if (response) {
 
1558
                const pj_stun_errcode_attr *eattr;
 
1559
 
 
1560
                eattr = (const pj_stun_errcode_attr*)
 
1561
                        pj_stun_msg_find_attr(response, 
 
1562
                                              PJ_STUN_ATTR_ERROR_CODE, 0);
 
1563
                if (eattr) {
 
1564
                    err_code = eattr->err_code;
 
1565
                    reason = eattr->reason;
 
1566
                } else {
 
1567
                    err_code = -1;
 
1568
                    reason = pj_str("?");
 
1569
                }
 
1570
            } else {
 
1571
                err_code = status;
 
1572
                reason = pj_strerror(status, errbuf, sizeof(errbuf));
 
1573
            }
 
1574
 
 
1575
            it = pj_hash_first(sess->perm_table, &it_buf);
 
1576
            while (it) {
 
1577
                struct perm_t *perm = (struct perm_t*)
 
1578
                                      pj_hash_this(sess->perm_table, it);
 
1579
                it = pj_hash_next(sess->perm_table, it);
 
1580
 
 
1581
                if (perm->req_token == token) {
 
1582
                    PJ_LOG(1,(sess->obj_name, 
 
1583
                              "CreatePermission failed for IP %s: %d/%.*s",
 
1584
                              pj_sockaddr_print(&perm->addr, ipstr, 
 
1585
                                                sizeof(ipstr), 2),
 
1586
                              err_code, (int)reason.slen, reason.ptr));
 
1587
 
 
1588
                    invalidate_perm(sess, perm);
 
1589
                }
 
1590
            }
 
1591
 
 
1592
            if (err_code == PJ_STUN_SC_ALLOCATION_MISMATCH) {
 
1593
                /* Allocation mismatch means allocation no longer exists */
 
1594
                on_session_fail(sess, PJ_STUN_CREATE_PERM_METHOD,
 
1595
                                status, &reason);
 
1596
                return;
 
1597
            }
 
1598
        }
 
1599
 
 
1600
    } else {
 
1601
        PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s response",
 
1602
                  pj_stun_get_method_name(response->hdr.type)));
 
1603
    }
 
1604
}
 
1605
 
 
1606
 
 
1607
/*
 
1608
 * Notification from STUN session on incoming STUN Indication
 
1609
 * message.
 
1610
 */
 
1611
static pj_status_t stun_on_rx_indication(pj_stun_session *stun,
 
1612
                                         const pj_uint8_t *pkt,
 
1613
                                         unsigned pkt_len,
 
1614
                                         const pj_stun_msg *msg,
 
1615
                                         void *token,
 
1616
                                         const pj_sockaddr_t *src_addr,
 
1617
                                         unsigned src_addr_len)
 
1618
{
 
1619
    pj_turn_session *sess;
 
1620
    pj_stun_xor_peer_addr_attr *peer_attr;
 
1621
    pj_stun_icmp_attr *icmp;
 
1622
    pj_stun_data_attr *data_attr;
 
1623
 
 
1624
    PJ_UNUSED_ARG(token);
 
1625
    PJ_UNUSED_ARG(pkt);
 
1626
    PJ_UNUSED_ARG(pkt_len);
 
1627
    PJ_UNUSED_ARG(src_addr);
 
1628
    PJ_UNUSED_ARG(src_addr_len);
 
1629
 
 
1630
    sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
 
1631
 
 
1632
    /* Expecting Data Indication only */
 
1633
    if (msg->hdr.type != PJ_STUN_DATA_INDICATION) {
 
1634
        PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s indication",
 
1635
                  pj_stun_get_method_name(msg->hdr.type)));
 
1636
        return PJ_EINVALIDOP;
 
1637
    }
 
1638
 
 
1639
    /* Check if there is ICMP attribute in the message */
 
1640
    icmp = (pj_stun_icmp_attr*)
 
1641
           pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICMP, 0);
 
1642
    if (icmp != NULL) {
 
1643
        /* This is a forwarded ICMP packet. Ignore it for now */
 
1644
        return PJ_SUCCESS;
 
1645
    }
 
1646
 
 
1647
    /* Get XOR-PEER-ADDRESS attribute */
 
1648
    peer_attr = (pj_stun_xor_peer_addr_attr*)
 
1649
                pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
 
1650
 
 
1651
    /* Get DATA attribute */
 
1652
    data_attr = (pj_stun_data_attr*)
 
1653
                pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
 
1654
 
 
1655
    /* Must have both XOR-PEER-ADDRESS and DATA attributes */
 
1656
    if (!peer_attr || !data_attr) {
 
1657
        PJ_LOG(4,(sess->obj_name, 
 
1658
                  "Received Data indication with missing attributes"));
 
1659
        return PJ_EINVALIDOP;
 
1660
    }
 
1661
 
 
1662
    /* Notify application */
 
1663
    if (sess->cb.on_rx_data) {
 
1664
        (*sess->cb.on_rx_data)(sess, data_attr->data, data_attr->length, 
 
1665
                               &peer_attr->sockaddr,
 
1666
                               pj_sockaddr_get_len(&peer_attr->sockaddr));
 
1667
    }
 
1668
 
 
1669
    return PJ_SUCCESS;
 
1670
}
 
1671
 
 
1672
 
 
1673
/*
 
1674
 * Notification on completion of DNS SRV resolution.
 
1675
 */
 
1676
static void dns_srv_resolver_cb(void *user_data,
 
1677
                                pj_status_t status,
 
1678
                                const pj_dns_srv_record *rec)
 
1679
{
 
1680
    pj_turn_session *sess = (pj_turn_session*) user_data;
 
1681
    unsigned i, cnt, tot_cnt;
 
1682
 
 
1683
    /* Clear async resolver */
 
1684
    sess->dns_async = NULL;
 
1685
 
 
1686
    /* Check failure */
 
1687
    if (status != PJ_SUCCESS) {
 
1688
        sess_shutdown(sess, status);
 
1689
        return;
 
1690
    }
 
1691
 
 
1692
    /* Calculate total number of server entries in the response */
 
1693
    tot_cnt = 0;
 
1694
    for (i=0; i<rec->count; ++i) {
 
1695
        tot_cnt += rec->entry[i].server.addr_count;
 
1696
    }
 
1697
 
 
1698
    if (tot_cnt > PJ_TURN_MAX_DNS_SRV_CNT)
 
1699
        tot_cnt = PJ_TURN_MAX_DNS_SRV_CNT;
 
1700
 
 
1701
    /* Allocate server entries */
 
1702
    sess->srv_addr_list = (pj_sockaddr*)
 
1703
                           pj_pool_calloc(sess->pool, tot_cnt, 
 
1704
                                          sizeof(pj_sockaddr));
 
1705
 
 
1706
    /* Copy results to server entries */
 
1707
    for (i=0, cnt=0; i<rec->count && cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++i) {
 
1708
        unsigned j;
 
1709
 
 
1710
        for (j=0; j<rec->entry[i].server.addr_count && 
 
1711
                  cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++j) 
 
1712
        {
 
1713
            pj_sockaddr_in *addr = &sess->srv_addr_list[cnt].ipv4;
 
1714
 
 
1715
            addr->sin_family = sess->af;
 
1716
            addr->sin_port = pj_htons(rec->entry[i].port);
 
1717
            addr->sin_addr.s_addr = rec->entry[i].server.addr[j].s_addr;
 
1718
 
 
1719
            ++cnt;
 
1720
        }
 
1721
    }
 
1722
    sess->srv_addr_cnt = (pj_uint16_t)cnt;
 
1723
 
 
1724
    /* Set current server */
 
1725
    sess->srv_addr = &sess->srv_addr_list[0];
 
1726
 
 
1727
    /* Set state to PJ_TURN_STATE_RESOLVED */
 
1728
    set_state(sess, PJ_TURN_STATE_RESOLVED);
 
1729
 
 
1730
    /* Run pending allocation */
 
1731
    if (sess->pending_alloc) {
 
1732
        pj_turn_session_alloc(sess, NULL);
 
1733
    }
 
1734
}
 
1735
 
 
1736
 
 
1737
/*
 
1738
 * Lookup peer descriptor from its address.
 
1739
 */
 
1740
static struct ch_t *lookup_ch_by_addr(pj_turn_session *sess,
 
1741
                                      const pj_sockaddr_t *addr,
 
1742
                                      unsigned addr_len,
 
1743
                                      pj_bool_t update,
 
1744
                                      pj_bool_t bind_channel)
 
1745
{
 
1746
    pj_uint32_t hval = 0;
 
1747
    struct ch_t *ch;
 
1748
 
 
1749
    ch = (struct ch_t*) 
 
1750
         pj_hash_get(sess->ch_table, addr, addr_len, &hval);
 
1751
    if (ch == NULL && update) {
 
1752
        ch = PJ_POOL_ZALLOC_T(sess->pool, struct ch_t);
 
1753
        ch->num = PJ_TURN_INVALID_CHANNEL;
 
1754
        pj_memcpy(&ch->addr, addr, addr_len);
 
1755
 
 
1756
        /* Register by peer address */
 
1757
        pj_hash_set(sess->pool, sess->ch_table, &ch->addr, addr_len,
 
1758
                    hval, ch);
 
1759
    }
 
1760
 
 
1761
    if (ch && update) {
 
1762
        pj_gettimeofday(&ch->expiry);
 
1763
        ch->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
 
1764
 
 
1765
        if (bind_channel) {
 
1766
            pj_uint32_t hval = 0;
 
1767
            /* Register by channel number */
 
1768
            pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound);
 
1769
 
 
1770
            if (pj_hash_get(sess->ch_table, &ch->num, 
 
1771
                            sizeof(ch->num), &hval)==0) {
 
1772
                pj_hash_set(sess->pool, sess->ch_table, &ch->num,
 
1773
                            sizeof(ch->num), hval, ch);
 
1774
            }
 
1775
        }
 
1776
    }
 
1777
 
 
1778
    /* Also create/update permission for this destination. Ideally we
 
1779
     * should update this when we receive the successful response,
 
1780
     * but that would cause duplicate CreatePermission to be sent
 
1781
     * during refreshing.
 
1782
     */
 
1783
    if (ch && update) {
 
1784
        lookup_perm(sess, &ch->addr, pj_sockaddr_get_len(&ch->addr), PJ_TRUE);
 
1785
    }
 
1786
 
 
1787
    return ch;
 
1788
}
 
1789
 
 
1790
 
 
1791
/*
 
1792
 * Lookup channel descriptor from its channel number.
 
1793
 */
 
1794
static struct ch_t *lookup_ch_by_chnum(pj_turn_session *sess,
 
1795
                                         pj_uint16_t chnum)
 
1796
{
 
1797
    return (struct ch_t*) pj_hash_get(sess->ch_table, &chnum, 
 
1798
                                      sizeof(chnum), NULL);
 
1799
}
 
1800
 
 
1801
 
 
1802
/*
 
1803
 * Lookup permission and optionally create if it doesn't exist.
 
1804
 */
 
1805
static struct perm_t *lookup_perm(pj_turn_session *sess,
 
1806
                                  const pj_sockaddr_t *addr,
 
1807
                                  unsigned addr_len,
 
1808
                                  pj_bool_t update)
 
1809
{
 
1810
    pj_uint32_t hval = 0;
 
1811
    pj_sockaddr perm_addr;
 
1812
    struct perm_t *perm;
 
1813
 
 
1814
    /* make sure port number if zero */
 
1815
    if (pj_sockaddr_get_port(addr) != 0) {
 
1816
        pj_memcpy(&perm_addr, addr, addr_len);
 
1817
        pj_sockaddr_set_port(&perm_addr, 0);
 
1818
        addr = &perm_addr;
 
1819
    }
 
1820
 
 
1821
    /* lookup and create if it doesn't exist and wanted */
 
1822
    perm = (struct perm_t*) 
 
1823
           pj_hash_get(sess->perm_table, addr, addr_len, &hval);
 
1824
    if (perm == NULL && update) {
 
1825
        perm = PJ_POOL_ZALLOC_T(sess->pool, struct perm_t);
 
1826
        pj_memcpy(&perm->addr, addr, addr_len);
 
1827
        perm->hval = hval;
 
1828
 
 
1829
        pj_hash_set(sess->pool, sess->perm_table, &perm->addr, addr_len,
 
1830
                    perm->hval, perm);
 
1831
    }
 
1832
 
 
1833
    if (perm && update) {
 
1834
        pj_gettimeofday(&perm->expiry);
 
1835
        perm->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
 
1836
 
 
1837
    }
 
1838
 
 
1839
    return perm;
 
1840
}
 
1841
 
 
1842
/*
 
1843
 * Delete permission
 
1844
 */
 
1845
static void invalidate_perm(pj_turn_session *sess,
 
1846
                            struct perm_t *perm)
 
1847
{
 
1848
    pj_hash_set(NULL, sess->perm_table, &perm->addr,
 
1849
                pj_sockaddr_get_len(&perm->addr), perm->hval, NULL);
 
1850
}
 
1851
 
 
1852
/*
 
1853
 * Scan permission's hash table to refresh the permission.
 
1854
 */
 
1855
static unsigned refresh_permissions(pj_turn_session *sess, 
 
1856
                                    const pj_time_val *now)
 
1857
{
 
1858
    pj_stun_tx_data *tdata = NULL;
 
1859
    unsigned count = 0;
 
1860
    void *req_token = NULL;
 
1861
    pj_hash_iterator_t *it, itbuf;
 
1862
    pj_status_t status;
 
1863
 
 
1864
    it = pj_hash_first(sess->perm_table, &itbuf);
 
1865
    while (it) {
 
1866
        struct perm_t *perm = (struct perm_t*)
 
1867
                              pj_hash_this(sess->perm_table, it);
 
1868
 
 
1869
        it = pj_hash_next(sess->perm_table, it);
 
1870
 
 
1871
        if (perm->expiry.sec-1 <= now->sec) {
 
1872
            if (perm->renew) {
 
1873
                /* Renew this permission */
 
1874
                if (tdata == NULL) {
 
1875
                    /* Create a bare CreatePermission request */
 
1876
                    status = pj_stun_session_create_req(
 
1877
                                        sess->stun, 
 
1878
                                        PJ_STUN_CREATE_PERM_REQUEST,
 
1879
                                        PJ_STUN_MAGIC, NULL, &tdata);
 
1880
                    if (status != PJ_SUCCESS) {
 
1881
                        PJ_LOG(1,(sess->obj_name, 
 
1882
                                 "Error creating CreatePermission request: %d",
 
1883
                                 status));
 
1884
                        return 0;
 
1885
                    }
 
1886
 
 
1887
                    /* Create request token to map the request to the perm
 
1888
                     * structures which the request belongs.
 
1889
                     */
 
1890
                    req_token = (void*)(long)pj_rand();
 
1891
                }
 
1892
 
 
1893
                status = pj_stun_msg_add_sockaddr_attr(
 
1894
                                        tdata->pool, 
 
1895
                                        tdata->msg,
 
1896
                                        PJ_STUN_ATTR_XOR_PEER_ADDR,
 
1897
                                        PJ_TRUE,
 
1898
                                        &perm->addr,
 
1899
                                        sizeof(perm->addr));
 
1900
                if (status != PJ_SUCCESS) {
 
1901
                    pj_stun_msg_destroy_tdata(sess->stun, tdata);
 
1902
                    return 0;
 
1903
                }
 
1904
 
 
1905
                perm->expiry = *now;
 
1906
                perm->expiry.sec += PJ_TURN_PERM_TIMEOUT-sess->ka_interval-1;
 
1907
                perm->req_token = req_token;
 
1908
                ++count;
 
1909
 
 
1910
            } else {
 
1911
                /* This permission has expired and app doesn't want
 
1912
                 * us to renew, so delete it from the hash table.
 
1913
                 */
 
1914
                invalidate_perm(sess, perm);
 
1915
            }
 
1916
        }
 
1917
    }
 
1918
 
 
1919
    if (tdata) {
 
1920
        status = pj_stun_session_send_msg(sess->stun, req_token, PJ_FALSE, 
 
1921
                                          (sess->conn_type==PJ_TURN_TP_UDP),
 
1922
                                          sess->srv_addr,
 
1923
                                          pj_sockaddr_get_len(sess->srv_addr), 
 
1924
                                          tdata);
 
1925
        if (status != PJ_SUCCESS) {
 
1926
            PJ_LOG(1,(sess->obj_name, 
 
1927
                      "Error sending CreatePermission request: %d",
 
1928
                      status));
 
1929
            count = 0;
 
1930
        }
 
1931
 
 
1932
    }
 
1933
 
 
1934
    return count;
 
1935
}
 
1936
 
 
1937
/*
 
1938
 * Timer event.
 
1939
 */
 
1940
static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
 
1941
{
 
1942
    pj_turn_session *sess = (pj_turn_session*)e->user_data;
 
1943
    enum timer_id_t eid;
 
1944
 
 
1945
    PJ_UNUSED_ARG(th);
 
1946
 
 
1947
    pj_grp_lock_acquire(sess->grp_lock);
 
1948
 
 
1949
    eid = (enum timer_id_t) e->id;
 
1950
    e->id = TIMER_NONE;
 
1951
    
 
1952
    if (eid == TIMER_KEEP_ALIVE) {
 
1953
        pj_time_val now;
 
1954
        pj_hash_iterator_t itbuf, *it;
 
1955
        pj_bool_t resched = PJ_TRUE;
 
1956
        pj_bool_t pkt_sent = PJ_FALSE;
 
1957
 
 
1958
        if (sess->state >= PJ_TURN_STATE_DEALLOCATING) {
 
1959
            /* Ignore if we're deallocating */
 
1960
            goto on_return;
 
1961
        }
 
1962
 
 
1963
        pj_gettimeofday(&now);
 
1964
 
 
1965
        /* Refresh allocation if it's time to do so */
 
1966
        if (PJ_TIME_VAL_LTE(sess->expiry, now)) {
 
1967
            int lifetime = sess->alloc_param.lifetime;
 
1968
 
 
1969
            if (lifetime == 0)
 
1970
                lifetime = -1;
 
1971
 
 
1972
            send_refresh(sess, lifetime);
 
1973
            resched = PJ_FALSE;
 
1974
            pkt_sent = PJ_TRUE;
 
1975
        }
 
1976
 
 
1977
        /* Scan hash table to refresh bound channels */
 
1978
        it = pj_hash_first(sess->ch_table, &itbuf);
 
1979
        while (it) {
 
1980
            struct ch_t *ch = (struct ch_t*) 
 
1981
                              pj_hash_this(sess->ch_table, it);
 
1982
            if (ch->bound && PJ_TIME_VAL_LTE(ch->expiry, now)) {
 
1983
 
 
1984
                /* Send ChannelBind to refresh channel binding and 
 
1985
                 * permission.
 
1986
                 */
 
1987
                pj_turn_session_bind_channel(sess, &ch->addr,
 
1988
                                             pj_sockaddr_get_len(&ch->addr));
 
1989
                pkt_sent = PJ_TRUE;
 
1990
            }
 
1991
 
 
1992
            it = pj_hash_next(sess->ch_table, it);
 
1993
        }
 
1994
 
 
1995
        /* Scan permission table to refresh permissions */
 
1996
        if (refresh_permissions(sess, &now))
 
1997
            pkt_sent = PJ_TRUE;
 
1998
 
 
1999
        /* If no packet is sent, send a blank Send indication to
 
2000
         * refresh local NAT.
 
2001
         */
 
2002
        if (!pkt_sent && sess->alloc_param.ka_interval > 0) {
 
2003
            pj_stun_tx_data *tdata;
 
2004
            pj_status_t rc;
 
2005
 
 
2006
            /* Create blank SEND-INDICATION */
 
2007
            rc = pj_stun_session_create_ind(sess->stun, 
 
2008
                                            PJ_STUN_SEND_INDICATION, &tdata);
 
2009
            if (rc == PJ_SUCCESS) {
 
2010
                /* Add DATA attribute with zero length */
 
2011
                pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
 
2012
                                            PJ_STUN_ATTR_DATA, NULL, 0);
 
2013
 
 
2014
                /* Send the indication */
 
2015
                pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE, 
 
2016
                                         PJ_FALSE, sess->srv_addr,
 
2017
                                         pj_sockaddr_get_len(sess->srv_addr),
 
2018
                                         tdata);
 
2019
            }
 
2020
        }
 
2021
 
 
2022
        /* Reshcedule timer */
 
2023
        if (resched) {
 
2024
            pj_time_val delay;
 
2025
 
 
2026
            delay.sec = sess->ka_interval;
 
2027
            delay.msec = 0;
 
2028
 
 
2029
            pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
 
2030
                                              &delay, TIMER_KEEP_ALIVE,
 
2031
                                              sess->grp_lock);
 
2032
        }
 
2033
 
 
2034
    } else if (eid == TIMER_DESTROY) {
 
2035
        /* Time to destroy */
 
2036
        do_destroy(sess);
 
2037
    } else {
 
2038
        pj_assert(!"Unknown timer event");
 
2039
    }
 
2040
 
 
2041
on_return:
 
2042
    pj_grp_lock_release(sess->grp_lock);
 
2043
}
 
2044