1
/* $Id: turn_session.c 4368 2013-02-21 21:53:28Z bennylp $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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>
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
39
static const char *state_names[] =
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.
63
/* The channel number */
66
/* PJ_TRUE if we've received successful response to ChannelBind request
71
/* The peer IP address and port */
74
/* The channel binding expiration */
79
/* This structure describes a permission. A permission is identified by the
84
/* Cache of hash value to speed-up lookup */
87
/* The permission IP address. The port number MUST be zero */
90
/* Number of peers that uses this permission. */
93
/* Automatically renew this permission once it expires? */
96
/* The permission expiration */
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
107
/* The TURN client session structure */
108
struct pj_turn_session
111
const char *obj_name;
112
pj_turn_session_cb cb;
114
pj_stun_config stun_cfg;
115
pj_bool_t is_destroying;
117
pj_grp_lock_t *grp_lock;
120
pj_turn_state_t state;
121
pj_status_t last_status;
122
pj_bool_t pending_destroy;
123
pj_bool_t destroy_notified;
125
pj_stun_session *stun;
131
pj_timer_heap_t *timer_heap;
132
pj_timer_entry timer;
134
pj_dns_srv_async_query *dns_async;
135
pj_uint16_t default_port;
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;
143
pj_bool_t pending_alloc;
144
pj_turn_alloc_param alloc_param;
146
pj_sockaddr mapped_addr;
147
pj_sockaddr relay_addr;
149
pj_hash_table_t *ch_table;
150
pj_hash_table_t *perm_table;
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];
163
static void sess_shutdown(pj_turn_session *sess,
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,
172
const pj_sockaddr_t *dst_addr,
174
static void stun_on_request_complete(pj_stun_session *sess,
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,
184
const pj_stun_msg *msg,
186
const pj_sockaddr_t *src_addr,
187
unsigned src_addr_len);
188
static void dns_srv_resolver_cb(void *user_data,
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,
195
pj_bool_t bind_channel);
196
static struct ch_t *lookup_ch_by_chnum(pj_turn_session *sess,
198
static struct perm_t *lookup_perm(pj_turn_session *sess,
199
const pj_sockaddr_t *addr,
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);
208
* Create default pj_turn_alloc_param.
210
PJ_DEF(void) pj_turn_alloc_param_default(pj_turn_alloc_param *prm)
212
pj_bzero(prm, sizeof(*prm));
216
* Duplicate pj_turn_alloc_param.
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)
223
pj_memcpy(dst, src, sizeof(*dst));
227
* Get TURN state name.
229
PJ_DEF(const char*) pj_turn_state_name(pj_turn_state_t state)
231
return state_names[state];
235
* Create TURN client session.
237
PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
240
pj_turn_tp_type conn_type,
241
pj_grp_lock_t *grp_lock,
242
const pj_turn_session_cb *cb,
245
pj_turn_session **p_sess)
248
pj_turn_session *sess;
249
pj_stun_session_cb stun_cb;
252
PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL);
253
PJ_ASSERT_RETURN(cb->on_send_pkt, PJ_EINVAL);
255
PJ_UNUSED_ARG(options);
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);
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;
273
/* Copy STUN session */
274
pj_memcpy(&sess->stun_cfg, cfg, sizeof(pj_stun_config));
277
pj_memcpy(&sess->cb, cb, sizeof(*cb));
279
/* Peer hash table */
280
sess->ch_table = pj_hash_create(pool, PJ_TURN_CHANNEL_HTABLE_SIZE);
282
/* Permission hash table */
283
sess->perm_table = pj_hash_create(pool, PJ_TURN_PERM_HTABLE_SIZE);
287
sess->grp_lock = grp_lock;
289
status = pj_grp_lock_create(pool, NULL, &sess->grp_lock);
290
if (status != PJ_SUCCESS) {
291
pj_pool_release(pool);
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);
301
pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event);
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) {
315
/* Attach ourself to STUN session */
316
pj_stun_session_set_user_data(sess->stun, sess);
320
PJ_LOG(4,(sess->obj_name, "TURN client session created"));
327
static void turn_sess_on_destroy(void *comp)
329
pj_turn_session *sess = (pj_turn_session*) comp;
333
pj_pool_t *pool = sess->pool;
335
PJ_LOG(4,(sess->obj_name, "TURN client session destroyed"));
338
pj_pool_release(pool);
343
static void do_destroy(pj_turn_session *sess)
345
PJ_LOG(4,(sess->obj_name, "TURN session destroy request, ref_cnt=%d",
346
pj_grp_lock_get_ref(sess->grp_lock)));
348
pj_grp_lock_acquire(sess->grp_lock);
349
if (sess->is_destroying) {
350
pj_grp_lock_release(sess->grp_lock);
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);
358
pj_grp_lock_dec_ref(sess->grp_lock);
359
pj_grp_lock_release(sess->grp_lock);
363
/* Set session state */
364
static void set_state(pj_turn_session *sess, enum pj_turn_state_t state)
366
pj_turn_state_t old_state = sess->state;
368
if (state==sess->state)
371
PJ_LOG(4,(sess->obj_name, "State changed %s --> %s",
372
state_names[old_state], state_names[state]));
375
if (sess->cb.on_state) {
376
(*sess->cb.on_state)(sess, old_state, state);
381
* Notify application and shutdown the TURN session.
383
static void sess_shutdown(pj_turn_session *sess,
386
pj_bool_t can_destroy = PJ_TRUE;
388
PJ_LOG(4,(sess->obj_name, "Request to shutdown in state %s, cause:%d",
389
state_names[sess->state], status));
391
if (sess->last_status == PJ_SUCCESS && status != PJ_SUCCESS)
392
sess->last_status = status;
394
switch (sess->state) {
395
case PJ_TURN_STATE_NULL:
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;
403
case PJ_TURN_STATE_RESOLVED:
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;
410
case PJ_TURN_STATE_READY:
411
/* Send REFRESH with LIFETIME=0 */
412
can_destroy = PJ_FALSE;
413
send_refresh(sess, 0);
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.
420
/* No need to deallocate as we're already deallocating!
421
* See https://trac.pjsip.org/repos/ticket/1551
422
send_refresh(sess, 0);
425
case PJ_TURN_STATE_DEALLOCATED:
426
case PJ_TURN_STATE_DESTROYING:
431
/* Schedule destroy */
432
pj_time_val delay = {0, 0};
434
set_state(sess, PJ_TURN_STATE_DESTROYING);
436
pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
438
pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
439
&delay, TIMER_DESTROY,
446
* Public API to destroy TURN client session.
448
PJ_DEF(pj_status_t) pj_turn_session_shutdown(pj_turn_session *sess)
450
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
452
pj_grp_lock_acquire(sess->grp_lock);
454
sess_shutdown(sess, PJ_SUCCESS);
456
pj_grp_lock_release(sess->grp_lock);
463
* Forcefully destroy the TURN session.
465
PJ_DEF(pj_status_t) pj_turn_session_destroy( pj_turn_session *sess,
466
pj_status_t last_err)
468
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
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);
479
* Get TURN session info.
481
PJ_DEF(pj_status_t) pj_turn_session_get_info( pj_turn_session *sess,
482
pj_turn_session_info *info)
486
PJ_ASSERT_RETURN(sess && info, PJ_EINVAL);
488
pj_gettimeofday(&now);
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;
496
pj_memcpy(&info->server, sess->srv_addr, sizeof(info->server));
498
pj_bzero(&info->server, sizeof(info->server));
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));
510
* Re-assign user data.
512
PJ_DEF(pj_status_t) pj_turn_session_set_user_data( pj_turn_session *sess,
515
sess->user_data = user_data;
521
* Retrieve user data.
523
PJ_DEF(void*) pj_turn_session_get_user_data(pj_turn_session *sess)
525
return sess->user_data;
530
* Configure message logging. By default all flags are enabled.
532
* @param sess The TURN client session.
533
* @param flags Bitmask combination of #pj_stun_sess_msg_log_flag
535
PJ_DEF(void) pj_turn_session_set_log( pj_turn_session *sess,
538
pj_stun_session_set_log(sess->stun, flags);
545
PJ_DEF(pj_status_t) pj_turn_session_set_software_name( pj_turn_session *sess,
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);
559
* Set the server or domain name of the server.
561
PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
562
const pj_str_t *domain,
564
pj_dns_resolver *resolver)
566
pj_sockaddr tmp_addr;
567
pj_bool_t is_ip_addr;
570
PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL);
571
PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP);
573
pj_grp_lock_acquire(sess->grp_lock);
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);
581
if (!is_ip_addr && resolver) {
582
/* Resolve with DNS SRV resolution, and fallback to DNS A resolution
583
* if default_port is specified.
588
switch (sess->conn_type) {
590
res_name = pj_str("_turn._udp.");
593
res_name = pj_str("_turn._tcp.");
596
res_name = pj_str("_turns._tcp.");
599
status = PJNATH_ETURNINTP;
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;
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);
614
/* User may have destroyed us in the callback */
615
if (sess->state != PJ_TURN_STATE_RESOLVING) {
616
status = PJ_ECANCELLED;
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);
629
/* Resolver is not specified, resolve with standard gethostbyname().
630
* The default_port MUST be specified in this case.
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;
639
cnt = PJ_TURN_MAX_DNS_SRV_CNT;
641
pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo));
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);
647
/* User may have destroyed us in the callback */
648
if (sess->state != PJ_TURN_STATE_RESOLVING) {
649
status = PJ_ECANCELLED;
653
status = pj_getaddrinfo(sess->af, domain, &cnt, ai);
654
if (status != PJ_SUCCESS)
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);
668
sess->srv_addr = &sess->srv_addr_list[0];
669
set_state(sess, PJ_TURN_STATE_RESOLVED);
673
pj_grp_lock_release(sess->grp_lock);
679
* Set credential to be used by the session.
681
PJ_DEF(pj_status_t) pj_turn_session_set_credential(pj_turn_session *sess,
682
const pj_stun_auth_cred *cred)
684
PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL);
685
PJ_ASSERT_RETURN(sess->stun, PJ_EINVALIDOP);
687
pj_grp_lock_acquire(sess->grp_lock);
689
pj_stun_session_set_credential(sess->stun, PJ_STUN_AUTH_LONG_TERM, cred);
691
pj_grp_lock_release(sess->grp_lock);
698
* Create TURN allocation.
700
PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
701
const pj_turn_alloc_param *param)
703
pj_stun_tx_data *tdata;
704
pj_bool_t retransmit;
707
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
708
PJ_ASSERT_RETURN(sess->state>PJ_TURN_STATE_NULL &&
709
sess->state<=PJ_TURN_STATE_RESOLVED,
712
pj_grp_lock_acquire(sess->grp_lock);
714
if (param && param != &sess->alloc_param)
715
pj_turn_alloc_param_copy(sess->pool, &sess->alloc_param, param);
717
if (sess->state < PJ_TURN_STATE_RESOLVED) {
718
sess->pending_alloc = PJ_TRUE;
720
PJ_LOG(4,(sess->obj_name, "Pending ALLOCATE in state %s",
721
state_names[sess->state]));
723
pj_grp_lock_release(sess->grp_lock);
728
/* Ready to allocate */
729
pj_assert(sess->state == PJ_TURN_STATE_RESOLVED);
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);
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));
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);
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);
758
/* Server address must be set */
759
pj_assert(sess->srv_addr != NULL);
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),
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.
772
set_state(sess, PJ_TURN_STATE_RESOLVED);
775
pj_grp_lock_release(sess->grp_lock);
781
* Install or renew permissions
783
PJ_DEF(pj_status_t) pj_turn_session_set_perm( pj_turn_session *sess,
785
const pj_sockaddr addr[],
788
pj_stun_tx_data *tdata;
789
pj_hash_iterator_t it_buf, *it;
791
unsigned i, attr_added=0;
794
PJ_ASSERT_RETURN(sess && addr_cnt && addr, PJ_EINVAL);
796
pj_grp_lock_acquire(sess->grp_lock);
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);
807
/* Create request token to map the request to the perm structures
808
* which the request belongs.
810
req_token = (void*)(long)pj_rand();
812
/* Process the addresses */
813
for (i=0; i<addr_cnt; ++i) {
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]),
819
perm->renew = (options & 0x01);
821
/* Only add to the request if the request doesn't contain this
824
if (perm->req_token != req_token) {
825
perm->req_token = req_token;
827
/* Add XOR-PEER-ADDRESS */
828
status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
829
PJ_STUN_ATTR_XOR_PEER_ADDR,
833
if (status != PJ_SUCCESS)
840
pj_assert(attr_added != 0);
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),
846
pj_sockaddr_get_len(sess->srv_addr),
848
if (status != PJ_SUCCESS) {
849
/* tdata is already destroyed */
854
pj_grp_lock_release(sess->grp_lock);
860
pj_stun_msg_destroy_tdata(sess->stun, tdata);
862
/* invalidate perm structures associated with this request */
863
it = pj_hash_first(sess->perm_table, &it_buf);
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);
871
pj_grp_lock_release(sess->grp_lock);
878
static void send_refresh(pj_turn_session *sess, int lifetime)
880
pj_stun_tx_data *tdata;
883
PJ_ASSERT_ON_FAIL(sess->state==PJ_TURN_STATE_READY, return);
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)
893
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
894
PJ_STUN_ATTR_LIFETIME, lifetime);
899
set_state(sess, PJ_TURN_STATE_DEALLOCATING);
902
status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
903
(sess->conn_type==PJ_TURN_TP_UDP),
905
pj_sockaddr_get_len(sess->srv_addr),
907
if (status != PJ_SUCCESS)
914
set_state(sess, PJ_TURN_STATE_DEALLOCATED);
915
sess_shutdown(sess, status);
921
* Relay data to the specified peer through the session.
923
PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
924
const pj_uint8_t *pkt,
926
const pj_sockaddr_t *addr,
933
PJ_ASSERT_RETURN(sess && pkt && pkt_len && addr && addr_len,
936
/* Return error if we're not ready */
937
if (sess->state != PJ_TURN_STATE_READY) {
941
/* Lock session now */
942
pj_grp_lock_acquire(sess->grp_lock);
944
/* Lookup permission first */
945
perm = lookup_perm(sess, addr, pj_sockaddr_get_len(addr), PJ_FALSE);
947
/* Permission doesn't exist, install it first */
948
char ipstr[PJ_INET6_ADDRSTRLEN+2];
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)));
954
status = pj_turn_session_set_perm(sess, 1, (const pj_sockaddr*)addr,
956
if (status != PJ_SUCCESS) {
957
pj_grp_lock_release(sess->grp_lock);
962
/* See if the peer is bound to a channel number */
963
ch = lookup_ch_by_addr(sess, addr, pj_sockaddr_get_len(addr),
965
if (ch && ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound) {
968
/* Peer is assigned a channel number, we can use ChannelData */
969
pj_turn_channel_data *cd = (pj_turn_channel_data*)sess->tx_pkt;
971
pj_assert(sizeof(*cd)==4);
973
/* Calculate total length, including paddings */
974
total_len = (pkt_len + sizeof(*cd) + 3) & (~3);
975
if (total_len > sizeof(sess->tx_pkt)) {
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);
984
pj_assert(sess->srv_addr != NULL);
986
status = sess->cb.on_send_pkt(sess, sess->tx_pkt, total_len,
988
pj_sockaddr_get_len(sess->srv_addr));
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;
997
/* Increment counter */
998
++sess->send_ind_tsx_id[2];
1000
/* Create blank SEND-INDICATION */
1001
status = pj_stun_msg_init(&send_ind, PJ_STUN_SEND_INDICATION,
1003
(const pj_uint8_t*)sess->send_ind_tsx_id);
1004
if (status != PJ_SUCCESS)
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);
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);
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)
1025
/* Send the Send Indication */
1026
status = sess->cb.on_send_pkt(sess, sess->tx_pkt, send_ind_len,
1028
pj_sockaddr_get_len(sess->srv_addr));
1032
pj_grp_lock_release(sess->grp_lock);
1038
* Bind a peer address to a channel number.
1040
PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
1041
const pj_sockaddr_t *peer_adr,
1045
pj_stun_tx_data *tdata;
1049
PJ_ASSERT_RETURN(sess && peer_adr && addr_len, PJ_EINVAL);
1050
PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP);
1052
pj_grp_lock_acquire(sess->grp_lock);
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)
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),
1066
if (ch->num != PJ_TURN_INVALID_CHANNEL) {
1067
/* Channel is already bound. This is a refresh request. */
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++;
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));
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);
1085
/* Send the request, associate peer data structure with tdata
1086
* for future reference when we receive the ChannelBind response.
1088
status = pj_stun_session_send_msg(sess->stun, ch, PJ_FALSE,
1089
(sess->conn_type==PJ_TURN_TP_UDP),
1091
pj_sockaddr_get_len(sess->srv_addr),
1095
pj_grp_lock_release(sess->grp_lock);
1101
* Notify TURN client session upon receiving a packet from server.
1102
* The packet maybe a STUN packet or ChannelData packet.
1104
PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
1107
pj_size_t *parsed_len)
1111
pj_bool_t is_datagram;
1113
/* Packet could be ChannelData or STUN message (response or
1117
/* Start locking the session */
1118
pj_grp_lock_acquire(sess->grp_lock);
1120
is_datagram = (sess->conn_type==PJ_TURN_TP_UDP);
1122
/* Quickly check if this is STUN message */
1123
is_stun = ((((pj_uint8_t*)pkt)[0] & 0xC0) == 0);
1126
/* This looks like STUN, give it to the STUN session */
1129
options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
1131
options |= PJ_STUN_IS_DATAGRAM;
1132
status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,
1133
options, NULL, parsed_len,
1135
pj_sockaddr_get_len(sess->srv_addr));
1138
/* This must be ChannelData. */
1139
pj_turn_channel_data cd;
1143
if (parsed_len) *parsed_len = 0;
1144
return PJ_ETOOSMALL;
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);
1152
/* Check that size is sane */
1153
if (pkt_len < cd.length+sizeof(cd)) {
1156
/* Discard the datagram */
1157
*parsed_len = pkt_len;
1159
/* Insufficient fragment */
1163
status = PJ_ETOOSMALL;
1167
/* Apply padding too */
1168
*parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd);
1172
/* Lookup channel */
1173
ch = lookup_ch_by_chnum(sess, cd.ch_number);
1174
if (!ch || !ch->bound) {
1175
status = PJ_ENOTFOUND;
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));
1186
status = PJ_SUCCESS;
1190
pj_grp_lock_release(sess->grp_lock);
1196
* This is a callback from STUN session to send outgoing packet.
1198
static pj_status_t stun_on_send_msg(pj_stun_session *stun,
1202
const pj_sockaddr_t *dst_addr,
1205
pj_turn_session *sess;
1207
PJ_UNUSED_ARG(token);
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);
1216
* Handle failed ALLOCATE or REFRESH request. This may switch to alternate
1217
* server if we have one.
1219
static void on_session_fail( pj_turn_session *sess,
1220
enum pj_stun_method_e method,
1222
const pj_str_t *reason)
1224
sess->last_status = status;
1228
char err_msg[PJ_ERR_MSG_SIZE];
1230
if (reason == NULL) {
1231
pj_strerror(status, err_msg, sizeof(err_msg));
1232
reason1 = pj_str(err_msg);
1236
PJ_LOG(4,(sess->obj_name, "%s error: %.*s",
1237
pj_stun_get_method_name(method),
1238
(int)reason->slen, reason->ptr));
1240
/* If this is ALLOCATE response and we don't have more server
1241
* addresses to try, notify application and destroy the TURN
1244
if (method==PJ_STUN_ALLOCATE_METHOD &&
1245
sess->srv_addr == &sess->srv_addr_list[sess->srv_addr_cnt-1])
1248
set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1249
sess_shutdown(sess, status);
1253
/* Otherwise if this is not ALLOCATE response, notify application
1254
* that session has been TERMINATED.
1256
if (method!=PJ_STUN_ALLOCATE_METHOD) {
1257
set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1258
sess_shutdown(sess, status);
1262
/* Try next server */
1266
PJ_LOG(4,(sess->obj_name, "Trying next server"));
1267
set_state(sess, PJ_TURN_STATE_RESOLVED);
1274
* Handle successful response to ALLOCATE or REFRESH request.
1276
static void on_allocate_success(pj_turn_session *sess,
1277
enum pj_stun_method_e method,
1278
const pj_stun_msg *msg)
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;
1284
pj_time_val timeout;
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"));
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);
1302
/* Update lifetime and keep-alive interval */
1303
sess->lifetime = lf_attr->value;
1304
pj_gettimeofday(&sess->expiry);
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"));
1312
sess->ka_interval = sess->lifetime - 2;
1313
sess->expiry.sec += (sess->ka_interval-1);
1317
sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
1319
timeout = sess->lifetime - PJ_TURN_REFRESH_SEC_BEFORE;
1320
if (timeout < sess->ka_interval)
1321
timeout = sess->ka_interval - 1;
1323
sess->expiry.sec += timeout;
1326
/* Check that relayed transport address contains correct
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"));
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 "
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"));
1351
/* Save relayed address */
1353
/* If we already have relay address, check if the relay address
1354
* in the response matches our relay address.
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"));
1364
/* Otherwise save the relayed address */
1365
pj_memcpy(&sess->relay_addr, &raddr_attr->sockaddr,
1366
sizeof(pj_sockaddr));
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);
1374
pj_memcpy(&sess->mapped_addr, &mapped_attr->sockaddr,
1375
sizeof(mapped_attr->sockaddr));
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,
1387
/* Start keep-alive timer once allocation succeeds */
1388
if (sess->state < PJ_TURN_STATE_DEALLOCATING) {
1389
timeout.sec = sess->ka_interval;
1392
pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
1393
&timeout, TIMER_KEEP_ALIVE,
1396
set_state(sess, PJ_TURN_STATE_READY);
1401
* Notification from STUN session on request completion.
1403
static void stun_on_request_complete(pj_stun_session *stun,
1406
pj_stun_tx_data *tdata,
1407
const pj_stun_msg *response,
1408
const pj_sockaddr_t *src_addr,
1409
unsigned src_addr_len)
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);
1415
PJ_UNUSED_ARG(src_addr);
1416
PJ_UNUSED_ARG(src_addr_len);
1418
sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
1420
if (method == PJ_STUN_ALLOCATE_METHOD) {
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;
1427
sess->state = PJ_TURN_STATE_DEALLOCATED;
1428
sess_shutdown(sess, PJ_SUCCESS);
1432
/* Handle ALLOCATE response */
1433
if (status==PJ_SUCCESS &&
1434
PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1437
/* Successful Allocate response */
1438
on_allocate_success(sess, method, response);
1441
/* Failed Allocate request */
1442
const pj_str_t *err_msg = NULL;
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);
1450
status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1451
err_msg = &err_attr->reason;
1453
status = PJNATH_EINSTUNMSG;
1457
on_session_fail(sess, method, status, err_msg);
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))
1465
/* Success, schedule next refresh. */
1466
on_allocate_success(sess, method, response);
1469
/* Failed Refresh request */
1470
const pj_str_t *err_msg = NULL;
1472
pj_assert(status != PJ_SUCCESS);
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);
1480
status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1481
err_msg = &err_attr->reason;
1485
/* Notify and destroy */
1486
on_session_fail(sess, method, status, err_msg);
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))
1494
/* Successful ChannelBind response */
1495
struct ch_t *ch = (struct ch_t*)token;
1497
pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL);
1498
ch->bound = PJ_TRUE;
1500
/* Update hash table */
1501
lookup_ch_by_addr(sess, &ch->addr,
1502
pj_sockaddr_get_len(&ch->addr),
1506
/* Failed ChannelBind response */
1507
pj_str_t reason = {"", 0};
1509
char errbuf[PJ_ERR_MSG_SIZE];
1511
pj_assert(status != PJ_SUCCESS);
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);
1519
err_code = err_attr->err_code;
1520
status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1521
reason = err_attr->reason;
1525
reason = pj_strerror(status, errbuf, sizeof(errbuf));
1528
PJ_LOG(1,(sess->obj_name, "ChannelBind failed: %d/%.*s",
1529
err_code, (int)reason.slen, reason.ptr));
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,
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))
1544
/* No special handling when the request is successful. */
1546
/* Iterate the permission table and invalidate all permissions
1547
* that are related to this request.
1549
pj_hash_iterator_t it_buf, *it;
1550
char ipstr[PJ_INET6_ADDRSTRLEN+10];
1552
char errbuf[PJ_ERR_MSG_SIZE];
1555
pj_assert(status != PJ_SUCCESS);
1558
const pj_stun_errcode_attr *eattr;
1560
eattr = (const pj_stun_errcode_attr*)
1561
pj_stun_msg_find_attr(response,
1562
PJ_STUN_ATTR_ERROR_CODE, 0);
1564
err_code = eattr->err_code;
1565
reason = eattr->reason;
1568
reason = pj_str("?");
1572
reason = pj_strerror(status, errbuf, sizeof(errbuf));
1575
it = pj_hash_first(sess->perm_table, &it_buf);
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);
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,
1586
err_code, (int)reason.slen, reason.ptr));
1588
invalidate_perm(sess, perm);
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,
1601
PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s response",
1602
pj_stun_get_method_name(response->hdr.type)));
1608
* Notification from STUN session on incoming STUN Indication
1611
static pj_status_t stun_on_rx_indication(pj_stun_session *stun,
1612
const pj_uint8_t *pkt,
1614
const pj_stun_msg *msg,
1616
const pj_sockaddr_t *src_addr,
1617
unsigned src_addr_len)
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;
1624
PJ_UNUSED_ARG(token);
1626
PJ_UNUSED_ARG(pkt_len);
1627
PJ_UNUSED_ARG(src_addr);
1628
PJ_UNUSED_ARG(src_addr_len);
1630
sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
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;
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);
1643
/* This is a forwarded ICMP packet. Ignore it for now */
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);
1651
/* Get DATA attribute */
1652
data_attr = (pj_stun_data_attr*)
1653
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
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;
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));
1674
* Notification on completion of DNS SRV resolution.
1676
static void dns_srv_resolver_cb(void *user_data,
1678
const pj_dns_srv_record *rec)
1680
pj_turn_session *sess = (pj_turn_session*) user_data;
1681
unsigned i, cnt, tot_cnt;
1683
/* Clear async resolver */
1684
sess->dns_async = NULL;
1687
if (status != PJ_SUCCESS) {
1688
sess_shutdown(sess, status);
1692
/* Calculate total number of server entries in the response */
1694
for (i=0; i<rec->count; ++i) {
1695
tot_cnt += rec->entry[i].server.addr_count;
1698
if (tot_cnt > PJ_TURN_MAX_DNS_SRV_CNT)
1699
tot_cnt = PJ_TURN_MAX_DNS_SRV_CNT;
1701
/* Allocate server entries */
1702
sess->srv_addr_list = (pj_sockaddr*)
1703
pj_pool_calloc(sess->pool, tot_cnt,
1704
sizeof(pj_sockaddr));
1706
/* Copy results to server entries */
1707
for (i=0, cnt=0; i<rec->count && cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++i) {
1710
for (j=0; j<rec->entry[i].server.addr_count &&
1711
cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++j)
1713
pj_sockaddr_in *addr = &sess->srv_addr_list[cnt].ipv4;
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;
1722
sess->srv_addr_cnt = (pj_uint16_t)cnt;
1724
/* Set current server */
1725
sess->srv_addr = &sess->srv_addr_list[0];
1727
/* Set state to PJ_TURN_STATE_RESOLVED */
1728
set_state(sess, PJ_TURN_STATE_RESOLVED);
1730
/* Run pending allocation */
1731
if (sess->pending_alloc) {
1732
pj_turn_session_alloc(sess, NULL);
1738
* Lookup peer descriptor from its address.
1740
static struct ch_t *lookup_ch_by_addr(pj_turn_session *sess,
1741
const pj_sockaddr_t *addr,
1744
pj_bool_t bind_channel)
1746
pj_uint32_t hval = 0;
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);
1756
/* Register by peer address */
1757
pj_hash_set(sess->pool, sess->ch_table, &ch->addr, addr_len,
1762
pj_gettimeofday(&ch->expiry);
1763
ch->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
1766
pj_uint32_t hval = 0;
1767
/* Register by channel number */
1768
pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound);
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);
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.
1784
lookup_perm(sess, &ch->addr, pj_sockaddr_get_len(&ch->addr), PJ_TRUE);
1792
* Lookup channel descriptor from its channel number.
1794
static struct ch_t *lookup_ch_by_chnum(pj_turn_session *sess,
1797
return (struct ch_t*) pj_hash_get(sess->ch_table, &chnum,
1798
sizeof(chnum), NULL);
1803
* Lookup permission and optionally create if it doesn't exist.
1805
static struct perm_t *lookup_perm(pj_turn_session *sess,
1806
const pj_sockaddr_t *addr,
1810
pj_uint32_t hval = 0;
1811
pj_sockaddr perm_addr;
1812
struct perm_t *perm;
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);
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);
1829
pj_hash_set(sess->pool, sess->perm_table, &perm->addr, addr_len,
1833
if (perm && update) {
1834
pj_gettimeofday(&perm->expiry);
1835
perm->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
1845
static void invalidate_perm(pj_turn_session *sess,
1846
struct perm_t *perm)
1848
pj_hash_set(NULL, sess->perm_table, &perm->addr,
1849
pj_sockaddr_get_len(&perm->addr), perm->hval, NULL);
1853
* Scan permission's hash table to refresh the permission.
1855
static unsigned refresh_permissions(pj_turn_session *sess,
1856
const pj_time_val *now)
1858
pj_stun_tx_data *tdata = NULL;
1860
void *req_token = NULL;
1861
pj_hash_iterator_t *it, itbuf;
1864
it = pj_hash_first(sess->perm_table, &itbuf);
1866
struct perm_t *perm = (struct perm_t*)
1867
pj_hash_this(sess->perm_table, it);
1869
it = pj_hash_next(sess->perm_table, it);
1871
if (perm->expiry.sec-1 <= now->sec) {
1873
/* Renew this permission */
1874
if (tdata == NULL) {
1875
/* Create a bare CreatePermission request */
1876
status = pj_stun_session_create_req(
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",
1887
/* Create request token to map the request to the perm
1888
* structures which the request belongs.
1890
req_token = (void*)(long)pj_rand();
1893
status = pj_stun_msg_add_sockaddr_attr(
1896
PJ_STUN_ATTR_XOR_PEER_ADDR,
1899
sizeof(perm->addr));
1900
if (status != PJ_SUCCESS) {
1901
pj_stun_msg_destroy_tdata(sess->stun, tdata);
1905
perm->expiry = *now;
1906
perm->expiry.sec += PJ_TURN_PERM_TIMEOUT-sess->ka_interval-1;
1907
perm->req_token = req_token;
1911
/* This permission has expired and app doesn't want
1912
* us to renew, so delete it from the hash table.
1914
invalidate_perm(sess, perm);
1920
status = pj_stun_session_send_msg(sess->stun, req_token, PJ_FALSE,
1921
(sess->conn_type==PJ_TURN_TP_UDP),
1923
pj_sockaddr_get_len(sess->srv_addr),
1925
if (status != PJ_SUCCESS) {
1926
PJ_LOG(1,(sess->obj_name,
1927
"Error sending CreatePermission request: %d",
1940
static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
1942
pj_turn_session *sess = (pj_turn_session*)e->user_data;
1943
enum timer_id_t eid;
1947
pj_grp_lock_acquire(sess->grp_lock);
1949
eid = (enum timer_id_t) e->id;
1952
if (eid == TIMER_KEEP_ALIVE) {
1954
pj_hash_iterator_t itbuf, *it;
1955
pj_bool_t resched = PJ_TRUE;
1956
pj_bool_t pkt_sent = PJ_FALSE;
1958
if (sess->state >= PJ_TURN_STATE_DEALLOCATING) {
1959
/* Ignore if we're deallocating */
1963
pj_gettimeofday(&now);
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;
1972
send_refresh(sess, lifetime);
1977
/* Scan hash table to refresh bound channels */
1978
it = pj_hash_first(sess->ch_table, &itbuf);
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)) {
1984
/* Send ChannelBind to refresh channel binding and
1987
pj_turn_session_bind_channel(sess, &ch->addr,
1988
pj_sockaddr_get_len(&ch->addr));
1992
it = pj_hash_next(sess->ch_table, it);
1995
/* Scan permission table to refresh permissions */
1996
if (refresh_permissions(sess, &now))
1999
/* If no packet is sent, send a blank Send indication to
2000
* refresh local NAT.
2002
if (!pkt_sent && sess->alloc_param.ka_interval > 0) {
2003
pj_stun_tx_data *tdata;
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);
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),
2022
/* Reshcedule timer */
2026
delay.sec = sess->ka_interval;
2029
pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
2030
&delay, TIMER_KEEP_ALIVE,
2034
} else if (eid == TIMER_DESTROY) {
2035
/* Time to destroy */
2038
pj_assert(!"Unknown timer event");
2042
pj_grp_lock_release(sess->grp_lock);