1
/* $Id: ice_strans.c 4133 2012-05-21 14:00:17Z 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/ice_strans.h>
21
#include <pjnath/errno.h>
22
#include <pj/addr_resolv.h>
24
#include <pj/assert.h>
25
#include <pj/ip_helper.h>
31
#include <pj/string.h>
32
#include <pj/compat/socket.h>
36
# define TRACE_PKT(expr) PJ_LOG(5,expr)
38
# define TRACE_PKT(expr)
50
/* Candidate's local preference values. This is mostly used to
51
* specify preference among candidates with the same type. Since
52
* we don't have the facility to specify that, we'll just set it
53
* all to the same value.
55
#if PJNATH_ICE_PRIO_STD
56
# define SRFLX_PREF 65535
57
# define HOST_PREF 65535
58
# define RELAY_PREF 65535
66
/* The candidate type preference when STUN candidate is used */
67
static pj_uint8_t srflx_pref_table[4] =
69
#if PJNATH_ICE_PRIO_STD
70
100, /**< PJ_ICE_HOST_PREF */
71
110, /**< PJ_ICE_SRFLX_PREF */
72
126, /**< PJ_ICE_PRFLX_PREF */
73
0 /**< PJ_ICE_RELAYED_PREF */
75
/* Keep it to 2 bits */
76
1, /**< PJ_ICE_HOST_PREF */
77
2, /**< PJ_ICE_SRFLX_PREF */
78
3, /**< PJ_ICE_PRFLX_PREF */
79
0 /**< PJ_ICE_RELAYED_PREF */
85
static void on_ice_complete(pj_ice_sess *ice, pj_status_t status);
86
static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
88
unsigned transport_id,
89
const void *pkt, pj_size_t size,
90
const pj_sockaddr_t *dst_addr,
91
unsigned dst_addr_len);
92
static void ice_rx_data(pj_ice_sess *ice,
94
unsigned transport_id,
95
void *pkt, pj_size_t size,
96
const pj_sockaddr_t *src_addr,
97
unsigned src_addr_len);
100
/* STUN socket callbacks */
101
/* Notification when incoming packet has been received. */
102
static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
105
const pj_sockaddr_t *src_addr,
107
/* Notifification when asynchronous send operation has completed. */
108
static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
109
pj_ioqueue_op_key_t *send_key,
111
/* Notification when the status of the STUN transport has changed. */
112
static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
118
static void turn_on_rx_data(pj_turn_sock *turn_sock,
121
const pj_sockaddr_t *peer_addr,
123
static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
124
pj_turn_state_t new_state);
129
static void destroy_ice_st(pj_ice_strans *ice_st);
130
#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
131
static void sess_init_update(pj_ice_strans *ice_st);
133
static void sess_add_ref(pj_ice_strans *ice_st);
134
static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st);
137
* This structure describes an ICE stream transport component. A component
138
* in ICE stream transport typically corresponds to a single socket created
139
* for this component, and bound to a specific transport address. This
140
* component may have multiple alias addresses, for example one alias
141
* address for each interfaces in multi-homed host, another for server
142
* reflexive alias, and another for relayed alias. For each transport
143
* address alias, an ICE stream transport candidate (#pj_ice_sess_cand) will
144
* be created, and these candidates will eventually registered to the ICE
147
typedef struct pj_ice_strans_comp
149
pj_ice_strans *ice_st; /**< ICE stream transport. */
150
unsigned comp_id; /**< Component ID. */
152
pj_stun_sock *stun_sock; /**< STUN transport. */
153
pj_turn_sock *turn_sock; /**< TURN relay transport. */
154
pj_bool_t turn_log_off; /**< TURN loggin off? */
155
unsigned turn_err_cnt; /**< TURN disconnected count. */
157
unsigned cand_cnt; /**< # of candidates/aliaes. */
158
pj_ice_sess_cand cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */
160
unsigned default_cand; /**< Default candidate. */
162
} pj_ice_strans_comp;
166
* This structure represents the ICE stream transport.
170
char *obj_name; /**< Log ID. */
171
pj_pool_t *pool; /**< Pool used by this object. */
172
void *user_data; /**< Application data. */
173
pj_ice_strans_cfg cfg; /**< Configuration. */
174
pj_ice_strans_cb cb; /**< Application callback. */
175
pj_lock_t *init_lock; /**< Initialization mutex. */
177
pj_ice_strans_state state; /**< Session state. */
178
pj_ice_sess *ice; /**< ICE session. */
179
pj_time_val start_time;/**< Time when ICE was started */
181
unsigned comp_cnt; /**< Number of components. */
182
pj_ice_strans_comp **comp; /**< Components array. */
184
pj_timer_entry ka_timer; /**< STUN keep-alive timer. */
186
pj_atomic_t *busy_cnt; /**< To prevent destroy */
187
pj_bool_t destroy_req;/**< Destroy has been called? */
188
pj_bool_t cb_called; /**< Init error callback called?*/
192
/* Validate configuration */
193
static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg)
197
status = pj_stun_config_check_valid(&cfg->stun_cfg);
206
* Initialize ICE transport configuration with default values.
208
PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg)
210
pj_bzero(cfg, sizeof(*cfg));
212
pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL);
213
pj_stun_sock_cfg_default(&cfg->stun.cfg);
214
pj_turn_alloc_param_default(&cfg->turn.alloc_param);
215
pj_turn_sock_cfg_default(&cfg->turn.cfg);
217
pj_ice_sess_options_default(&cfg->opt);
219
cfg->af = pj_AF_INET();
220
cfg->stun.port = PJ_STUN_PORT;
221
cfg->turn.conn_type = PJ_TURN_TP_UDP;
223
cfg->stun.max_host_cands = 64;
224
cfg->stun.ignore_stun_error = PJ_FALSE;
229
* Copy configuration.
231
PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool,
232
pj_ice_strans_cfg *dst,
233
const pj_ice_strans_cfg *src)
235
pj_memcpy(dst, src, sizeof(*src));
237
if (src->stun.server.slen)
238
pj_strdup(pool, &dst->stun.server, &src->stun.server);
239
if (src->turn.server.slen)
240
pj_strdup(pool, &dst->turn.server, &src->turn.server);
241
pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred,
242
&src->turn.auth_cred);
247
* Add or update TURN candidate.
249
static pj_status_t add_update_turn(pj_ice_strans *ice_st,
250
pj_ice_strans_comp *comp)
252
pj_turn_sock_cb turn_sock_cb;
253
pj_ice_sess_cand *cand = NULL;
257
/* Find relayed candidate in the component */
258
for (i=0; i<comp->cand_cnt; ++i) {
259
if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) {
260
cand = &comp->cand_list[i];
265
/* If candidate is found, invalidate it first */
267
cand->status = PJ_EPENDING;
269
/* Also if this component's default candidate is set to relay,
270
* move it temporarily to something else.
272
if ((int)comp->default_cand == cand - comp->cand_list) {
273
/* Init to something */
274
comp->default_cand = 0;
275
/* Use srflx candidate as the default, if any */
276
for (i=0; i<comp->cand_cnt; ++i) {
277
if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
278
comp->default_cand = i;
285
/* Init TURN socket */
286
pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
287
turn_sock_cb.on_rx_data = &turn_on_rx_data;
288
turn_sock_cb.on_state = &turn_on_state;
290
/* Override with component specific QoS settings, if any */
291
if (ice_st->cfg.comp[comp->comp_id-1].qos_type) {
292
ice_st->cfg.turn.cfg.qos_type =
293
ice_st->cfg.comp[comp->comp_id-1].qos_type;
295
if (ice_st->cfg.comp[comp->comp_id-1].qos_params.flags) {
296
pj_memcpy(&ice_st->cfg.turn.cfg.qos_params,
297
&ice_st->cfg.comp[comp->comp_id-1].qos_params,
298
sizeof(ice_st->cfg.turn.cfg.qos_params));
301
/* Create the TURN transport */
302
status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af,
303
ice_st->cfg.turn.conn_type,
304
&turn_sock_cb, &ice_st->cfg.turn.cfg,
305
comp, &comp->turn_sock);
306
if (status != PJ_SUCCESS) {
310
/* Add pending job */
311
///sess_add_ref(ice_st);
313
/* Start allocation */
314
status=pj_turn_sock_alloc(comp->turn_sock,
315
&ice_st->cfg.turn.server,
316
ice_st->cfg.turn.port,
317
ice_st->cfg.resolver,
318
&ice_st->cfg.turn.auth_cred,
319
&ice_st->cfg.turn.alloc_param);
320
if (status != PJ_SUCCESS) {
321
///sess_dec_ref(ice_st);
325
/* Add relayed candidate with pending status if there's no existing one */
327
cand = &comp->cand_list[comp->cand_cnt++];
328
cand->type = PJ_ICE_CAND_TYPE_RELAYED;
329
cand->status = PJ_EPENDING;
330
cand->local_pref = RELAY_PREF;
331
cand->transport_id = TP_TURN;
332
cand->comp_id = (pj_uint8_t) comp->comp_id;
335
PJ_LOG(4,(ice_st->obj_name,
336
"Comp %d: TURN relay candidate waiting for allocation",
344
* Create the component.
346
static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id)
348
pj_ice_strans_comp *comp = NULL;
351
/* Verify arguments */
352
PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
354
/* Check that component ID present */
355
PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
357
/* Create component */
358
comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp);
359
comp->ice_st = ice_st;
360
comp->comp_id = comp_id;
362
ice_st->comp[comp_id-1] = comp;
364
/* Initialize default candidate */
365
comp->default_cand = 0;
367
/* Create STUN transport if configured */
368
if (ice_st->cfg.stun.server.slen || ice_st->cfg.stun.max_host_cands) {
369
pj_stun_sock_cb stun_sock_cb;
370
pj_ice_sess_cand *cand;
372
pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
373
stun_sock_cb.on_rx_data = &stun_on_rx_data;
374
stun_sock_cb.on_status = &stun_on_status;
375
stun_sock_cb.on_data_sent = &stun_on_data_sent;
377
/* Override component specific QoS settings, if any */
378
if (ice_st->cfg.comp[comp_id-1].qos_type) {
379
ice_st->cfg.stun.cfg.qos_type =
380
ice_st->cfg.comp[comp_id-1].qos_type;
382
if (ice_st->cfg.comp[comp_id-1].qos_params.flags) {
383
pj_memcpy(&ice_st->cfg.stun.cfg.qos_params,
384
&ice_st->cfg.comp[comp_id-1].qos_params,
385
sizeof(ice_st->cfg.stun.cfg.qos_params));
388
/* Create the STUN transport */
389
status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL,
390
ice_st->cfg.af, &stun_sock_cb,
391
&ice_st->cfg.stun.cfg,
392
comp, &comp->stun_sock);
393
if (status != PJ_SUCCESS)
396
/* Start STUN Binding resolution and add srflx candidate
397
* only if server is set
399
if (ice_st->cfg.stun.server.slen) {
400
pj_stun_sock_info stun_sock_info;
402
/* Add pending job */
403
///sess_add_ref(ice_st);
405
PJ_LOG(4,(ice_st->obj_name,
406
"Comp %d: srflx candidate starts Binding discovery",
409
pj_log_push_indent();
411
/* Start Binding resolution */
412
status = pj_stun_sock_start(comp->stun_sock,
413
&ice_st->cfg.stun.server,
414
ice_st->cfg.stun.port,
415
ice_st->cfg.resolver);
416
if (status != PJ_SUCCESS) {
417
///sess_dec_ref(ice_st);
422
/* Enumerate addresses */
423
status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info);
424
if (status != PJ_SUCCESS) {
425
///sess_dec_ref(ice_st);
430
/* Add srflx candidate with pending status. */
431
cand = &comp->cand_list[comp->cand_cnt++];
432
cand->type = PJ_ICE_CAND_TYPE_SRFLX;
433
cand->status = PJ_EPENDING;
434
cand->local_pref = SRFLX_PREF;
435
cand->transport_id = TP_STUN;
436
cand->comp_id = (pj_uint8_t) comp_id;
437
pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]);
438
pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr);
439
pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
440
cand->type, &cand->base_addr);
442
/* Set default candidate to srflx */
443
comp->default_cand = cand - comp->cand_list;
448
/* Add local addresses to host candidates, unless max_host_cands
451
if (ice_st->cfg.stun.max_host_cands) {
452
pj_stun_sock_info stun_sock_info;
455
/* Enumerate addresses */
456
status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info);
457
if (status != PJ_SUCCESS)
460
for (i=0; i<stun_sock_info.alias_cnt &&
461
i<ice_st->cfg.stun.max_host_cands; ++i)
463
char addrinfo[PJ_INET6_ADDRSTRLEN+10];
464
const pj_sockaddr *addr = &stun_sock_info.aliases[i];
466
/* Leave one candidate for relay */
467
if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) {
468
PJ_LOG(4,(ice_st->obj_name, "Too many host candidates"));
472
/* Ignore loopback addresses unless cfg->stun.loop_addr
475
if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) {
476
if (ice_st->cfg.stun.loop_addr==PJ_FALSE)
480
cand = &comp->cand_list[comp->cand_cnt++];
482
cand->type = PJ_ICE_CAND_TYPE_HOST;
483
cand->status = PJ_SUCCESS;
484
cand->local_pref = HOST_PREF;
485
cand->transport_id = TP_STUN;
486
cand->comp_id = (pj_uint8_t) comp_id;
487
pj_sockaddr_cp(&cand->addr, addr);
488
pj_sockaddr_cp(&cand->base_addr, addr);
489
pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr));
490
pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
491
cand->type, &cand->base_addr);
493
PJ_LOG(4,(ice_st->obj_name,
494
"Comp %d: host candidate %s added",
495
comp_id, pj_sockaddr_print(&cand->addr, addrinfo,
496
sizeof(addrinfo), 3)));
501
/* Create TURN relay if configured. */
502
if (ice_st->cfg.turn.server.slen) {
503
add_update_turn(ice_st, comp);
511
* Create ICE stream transport
513
PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name,
514
const pj_ice_strans_cfg *cfg,
517
const pj_ice_strans_cb *cb,
518
pj_ice_strans **p_ice_st)
521
pj_ice_strans *ice_st;
525
status = pj_ice_strans_cfg_check_valid(cfg);
526
if (status != PJ_SUCCESS)
529
PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st &&
530
comp_cnt <= PJ_ICE_MAX_COMP , PJ_EINVAL);
535
pool = pj_pool_create(cfg->stun_cfg.pf, name, PJNATH_POOL_LEN_ICE_STRANS,
536
PJNATH_POOL_INC_ICE_STRANS, NULL);
537
ice_st = PJ_POOL_ZALLOC_T(pool, pj_ice_strans);
539
ice_st->obj_name = pool->obj_name;
540
ice_st->user_data = user_data;
542
PJ_LOG(4,(ice_st->obj_name,
543
"Creating ICE stream transport with %d component(s)",
545
pj_log_push_indent();
547
pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg);
548
pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
550
status = pj_atomic_create(pool, 0, &ice_st->busy_cnt);
551
if (status != PJ_SUCCESS) {
552
destroy_ice_st(ice_st);
556
status = pj_lock_create_recursive_mutex(pool, ice_st->obj_name,
558
if (status != PJ_SUCCESS) {
559
destroy_ice_st(ice_st);
564
ice_st->comp_cnt = comp_cnt;
565
ice_st->comp = (pj_ice_strans_comp**)
566
pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*));
568
/* Move state to candidate gathering */
569
ice_st->state = PJ_ICE_STRANS_STATE_INIT;
571
/* Acquire initialization mutex to prevent callback to be
572
* called before we finish initialization.
574
pj_lock_acquire(ice_st->init_lock);
576
for (i=0; i<comp_cnt; ++i) {
577
status = create_comp(ice_st, i+1);
578
if (status != PJ_SUCCESS) {
579
pj_lock_release(ice_st->init_lock);
580
destroy_ice_st(ice_st);
586
/* Done with initialization */
587
pj_lock_release(ice_st->init_lock);
589
PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created"));
593
/* Check if all candidates are ready (this may call callback) */
594
sess_init_update(ice_st);
602
static void destroy_ice_st(pj_ice_strans *ice_st)
606
PJ_LOG(5,(ice_st->obj_name, "ICE stream transport destroying.."));
607
pj_log_push_indent();
609
/* Destroy ICE if we have ICE */
611
pj_ice_sess_destroy(ice_st->ice);
615
/* Destroy all components */
616
for (i=0; i<ice_st->comp_cnt; ++i) {
617
if (ice_st->comp[i]) {
618
if (ice_st->comp[i]->stun_sock) {
619
pj_stun_sock_set_user_data(ice_st->comp[i]->stun_sock, NULL);
620
pj_stun_sock_destroy(ice_st->comp[i]->stun_sock);
621
ice_st->comp[i]->stun_sock = NULL;
623
if (ice_st->comp[i]->turn_sock) {
624
pj_turn_sock_set_user_data(ice_st->comp[i]->turn_sock, NULL);
625
pj_turn_sock_destroy(ice_st->comp[i]->turn_sock);
626
ice_st->comp[i]->turn_sock = NULL;
630
ice_st->comp_cnt = 0;
633
if (ice_st->init_lock) {
634
pj_lock_acquire(ice_st->init_lock);
635
pj_lock_release(ice_st->init_lock);
636
pj_lock_destroy(ice_st->init_lock);
637
ice_st->init_lock = NULL;
640
/* Destroy reference counter */
641
if (ice_st->busy_cnt) {
642
pj_assert(pj_atomic_get(ice_st->busy_cnt)==0);
643
pj_atomic_destroy(ice_st->busy_cnt);
644
ice_st->busy_cnt = NULL;
647
PJ_LOG(4,(ice_st->obj_name, "ICE stream transport destroyed"));
650
pj_pool_release(ice_st->pool);
654
/* Get ICE session state. */
655
PJ_DEF(pj_ice_strans_state) pj_ice_strans_get_state(pj_ice_strans *ice_st)
657
return ice_st->state;
661
PJ_DEF(const char*) pj_ice_strans_state_name(pj_ice_strans_state state)
663
const char *names[] = {
665
"Candidate Gathering",
666
"Candidate Gathering Complete",
667
"Session Initialized",
668
"Negotiation In Progress",
669
"Negotiation Success",
673
PJ_ASSERT_RETURN(state <= PJ_ICE_STRANS_STATE_FAILED, "???");
677
/* Notification about failure */
678
static void sess_fail(pj_ice_strans *ice_st, pj_ice_strans_op op,
679
const char *title, pj_status_t status)
681
char errmsg[PJ_ERR_MSG_SIZE];
683
pj_strerror(status, errmsg, sizeof(errmsg));
684
PJ_LOG(4,(ice_st->obj_name, "%s: %s", title, errmsg));
685
pj_log_push_indent();
687
if (op==PJ_ICE_STRANS_OP_INIT && ice_st->cb_called) {
692
ice_st->cb_called = PJ_TRUE;
694
if (ice_st->cb.on_ice_complete)
695
(*ice_st->cb.on_ice_complete)(ice_st, op, status);
700
/* Update initialization status */
701
static void sess_init_update(pj_ice_strans *ice_st)
705
/* Ignore if init callback has been called */
706
if (ice_st->cb_called)
709
/* Notify application when all candidates have been gathered */
710
for (i=0; i<ice_st->comp_cnt; ++i) {
712
pj_ice_strans_comp *comp = ice_st->comp[i];
714
for (j=0; j<comp->cand_cnt; ++j) {
715
pj_ice_sess_cand *cand = &comp->cand_list[j];
717
if (cand->status == PJ_EPENDING)
722
/* All candidates have been gathered */
723
ice_st->cb_called = PJ_TRUE;
724
ice_st->state = PJ_ICE_STRANS_STATE_READY;
725
if (ice_st->cb.on_ice_complete)
726
(*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT,
731
* Destroy ICE stream transport.
733
PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st)
735
PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
737
ice_st->destroy_req = PJ_TRUE;
738
if (pj_atomic_get(ice_st->busy_cnt) > 0) {
739
PJ_LOG(5,(ice_st->obj_name,
740
"ICE strans object is busy, will destroy later"));
744
destroy_ice_st(ice_st);
750
* Increment busy counter.
752
static void sess_add_ref(pj_ice_strans *ice_st)
754
pj_atomic_inc(ice_st->busy_cnt);
758
* Decrement busy counter. If the counter has reached zero and destroy
759
* has been requested, destroy the object and return FALSE.
761
static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st)
763
int count = pj_atomic_dec_and_get(ice_st->busy_cnt);
764
pj_assert(count >= 0);
765
if (count==0 && ice_st->destroy_req) {
766
pj_ice_strans_destroy(ice_st);
776
PJ_DEF(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st)
778
PJ_ASSERT_RETURN(ice_st, NULL);
779
return ice_st->user_data;
784
* Get the value of various options of the ICE stream transport.
786
PJ_DEF(pj_status_t) pj_ice_strans_get_options( pj_ice_strans *ice_st,
787
pj_ice_sess_options *opt)
789
PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
790
pj_memcpy(opt, &ice_st->cfg.opt, sizeof(*opt));
795
* Specify various options for this ICE stream transport.
797
PJ_DEF(pj_status_t) pj_ice_strans_set_options(pj_ice_strans *ice_st,
798
const pj_ice_sess_options *opt)
800
PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
801
pj_memcpy(&ice_st->cfg.opt, opt, sizeof(*opt));
803
pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
810
PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
811
pj_ice_sess_role role,
812
const pj_str_t *local_ufrag,
813
const pj_str_t *local_passwd)
817
pj_ice_sess_cb ice_cb;
818
//const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };
820
/* Check arguments */
821
PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
822
/* Must not have ICE */
823
PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EINVALIDOP);
824
/* Components must have been created */
825
PJ_ASSERT_RETURN(ice_st->comp[0] != NULL, PJ_EINVALIDOP);
828
pj_bzero(&ice_cb, sizeof(ice_cb));
829
ice_cb.on_ice_complete = &on_ice_complete;
830
ice_cb.on_rx_data = &ice_rx_data;
831
ice_cb.on_tx_pkt = &ice_tx_pkt;
834
status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
835
ice_st->comp_cnt, &ice_cb,
836
local_ufrag, local_passwd, &ice_st->ice);
837
if (status != PJ_SUCCESS)
840
/* Associate user data */
841
ice_st->ice->user_data = (void*)ice_st;
844
pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
846
/* If default candidate for components are SRFLX one, upload a custom
847
* type priority to ICE session so that SRFLX candidates will get
850
if (ice_st->comp[0]->default_cand >= 0 &&
851
ice_st->comp[0]->cand_list[ice_st->comp[0]->default_cand].type
852
== PJ_ICE_CAND_TYPE_SRFLX)
854
pj_ice_sess_set_prefs(ice_st->ice, srflx_pref_table);
857
/* Add components/candidates */
858
for (i=0; i<ice_st->comp_cnt; ++i) {
860
pj_ice_strans_comp *comp = ice_st->comp[i];
862
/* Re-enable logging for Send/Data indications */
863
if (comp->turn_sock) {
864
PJ_LOG(5,(ice_st->obj_name,
865
"Disabling STUN Indication logging for "
866
"component %d", i+1));
867
pj_turn_sock_set_log(comp->turn_sock, 0xFFFF);
868
comp->turn_log_off = PJ_FALSE;
871
for (j=0; j<comp->cand_cnt; ++j) {
872
pj_ice_sess_cand *cand = &comp->cand_list[j];
873
unsigned ice_cand_id;
875
/* Skip if candidate is not ready */
876
if (cand->status != PJ_SUCCESS) {
877
PJ_LOG(5,(ice_st->obj_name,
878
"Candidate %d of comp %d is not added (pending)",
883
/* Must have address */
884
pj_assert(pj_sockaddr_has_addr(&cand->addr));
886
/* Add the candidate */
887
status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,
888
cand->transport_id, cand->type,
890
&cand->foundation, &cand->addr,
891
&cand->base_addr, &cand->rel_addr,
892
pj_sockaddr_get_len(&cand->addr),
893
(unsigned*)&ice_cand_id);
894
if (status != PJ_SUCCESS)
899
/* ICE session is ready for negotiation */
900
ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY;
905
pj_ice_strans_stop_ice(ice_st);
910
* Check if the ICE stream transport has the ICE session created.
912
PJ_DEF(pj_bool_t) pj_ice_strans_has_sess(pj_ice_strans *ice_st)
914
PJ_ASSERT_RETURN(ice_st, PJ_FALSE);
915
return ice_st->ice != NULL;
919
* Check if ICE negotiation is still running.
921
PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_running(pj_ice_strans *ice_st)
923
return ice_st && ice_st->ice && ice_st->ice->rcand_cnt &&
924
!pj_ice_strans_sess_is_complete(ice_st);
929
* Check if ICE negotiation has completed.
931
PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_complete(pj_ice_strans *ice_st)
933
return ice_st && ice_st->ice && ice_st->ice->is_complete;
938
* Get the current/running component count.
940
PJ_DEF(unsigned) pj_ice_strans_get_running_comp_cnt(pj_ice_strans *ice_st)
942
PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
944
if (ice_st->ice && ice_st->ice->rcand_cnt) {
945
return ice_st->ice->comp_cnt;
947
return ice_st->comp_cnt;
953
* Get the ICE username fragment and password of the ICE session.
955
PJ_DEF(pj_status_t) pj_ice_strans_get_ufrag_pwd( pj_ice_strans *ice_st,
961
PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
963
if (loc_ufrag) *loc_ufrag = ice_st->ice->rx_ufrag;
964
if (loc_pwd) *loc_pwd = ice_st->ice->rx_pass;
966
if (rem_ufrag || rem_pwd) {
967
PJ_ASSERT_RETURN(ice_st->ice->rcand_cnt != 0, PJ_EINVALIDOP);
968
if (rem_ufrag) *rem_ufrag = ice_st->ice->tx_ufrag;
969
if (rem_pwd) *rem_pwd = ice_st->ice->tx_pass;
976
* Get number of candidates
978
PJ_DEF(unsigned) pj_ice_strans_get_cands_count(pj_ice_strans *ice_st,
983
PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
984
comp_id <= ice_st->comp_cnt, 0);
987
for (i=0; i<ice_st->ice->lcand_cnt; ++i) {
988
if (ice_st->ice->lcand[i].comp_id != comp_id)
999
PJ_DEF(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st,
1002
pj_ice_sess_cand cand[])
1006
PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
1007
comp_id <= ice_st->comp_cnt && count && cand, PJ_EINVAL);
1010
for (i=0; i<ice_st->ice->lcand_cnt && cnt<*count; ++i) {
1011
if (ice_st->ice->lcand[i].comp_id != comp_id)
1013
pj_memcpy(&cand[cnt], &ice_st->ice->lcand[i],
1014
sizeof(pj_ice_sess_cand));
1023
* Get default candidate.
1025
PJ_DEF(pj_status_t) pj_ice_strans_get_def_cand( pj_ice_strans *ice_st,
1027
pj_ice_sess_cand *cand)
1029
const pj_ice_sess_check *valid_pair;
1031
PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1034
valid_pair = pj_ice_strans_get_valid_pair(ice_st, comp_id);
1036
pj_memcpy(cand, valid_pair->lcand, sizeof(pj_ice_sess_cand));
1038
pj_ice_strans_comp *comp = ice_st->comp[comp_id - 1];
1039
pj_assert(comp->default_cand>=0 && comp->default_cand<comp->cand_cnt);
1040
pj_memcpy(cand, &comp->cand_list[comp->default_cand],
1041
sizeof(pj_ice_sess_cand));
1047
* Get the current ICE role.
1049
PJ_DEF(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st)
1051
PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_ICE_SESS_ROLE_UNKNOWN);
1052
return ice_st->ice->role;
1056
* Change session role.
1058
PJ_DEF(pj_status_t) pj_ice_strans_change_role( pj_ice_strans *ice_st,
1059
pj_ice_sess_role new_role)
1061
PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
1062
return pj_ice_sess_change_role(ice_st->ice, new_role);
1066
* Start ICE processing !
1068
PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st,
1069
const pj_str_t *rem_ufrag,
1070
const pj_str_t *rem_passwd,
1071
unsigned rem_cand_cnt,
1072
const pj_ice_sess_cand rem_cand[])
1076
PJ_ASSERT_RETURN(ice_st && rem_ufrag && rem_passwd &&
1077
rem_cand_cnt && rem_cand, PJ_EINVAL);
1079
/* Mark start time */
1080
pj_gettimeofday(&ice_st->start_time);
1082
/* Build check list */
1083
status = pj_ice_sess_create_check_list(ice_st->ice, rem_ufrag, rem_passwd,
1084
rem_cand_cnt, rem_cand);
1085
if (status != PJ_SUCCESS)
1088
/* If we have TURN candidate, now is the time to create the permissions */
1089
if (ice_st->comp[0]->turn_sock) {
1092
for (i=0; i<ice_st->comp_cnt; ++i) {
1093
pj_ice_strans_comp *comp = ice_st->comp[i];
1094
pj_sockaddr addrs[PJ_ICE_ST_MAX_CAND];
1095
unsigned j, count=0;
1097
/* Gather remote addresses for this component */
1098
for (j=0; j<rem_cand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) {
1099
if (rem_cand[j].comp_id==i+1) {
1100
pj_memcpy(&addrs[count++], &rem_cand[j].addr,
1101
pj_sockaddr_get_len(&rem_cand[j].addr));
1106
status = pj_turn_sock_set_perm(comp->turn_sock, count,
1108
if (status != PJ_SUCCESS) {
1109
pj_ice_strans_stop_ice(ice_st);
1116
/* Start ICE negotiation! */
1117
status = pj_ice_sess_start_check(ice_st->ice);
1118
if (status != PJ_SUCCESS) {
1119
pj_ice_strans_stop_ice(ice_st);
1123
ice_st->state = PJ_ICE_STRANS_STATE_NEGO;
1130
PJ_DEF(const pj_ice_sess_check*)
1131
pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
1134
PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt,
1137
if (ice_st->ice == NULL)
1140
return ice_st->ice->comp[comp_id-1].valid_check;
1146
PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
1149
pj_ice_sess_destroy(ice_st->ice);
1153
ice_st->state = PJ_ICE_STRANS_STATE_INIT;
1158
* Application wants to send outgoing packet.
1160
PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
1164
const pj_sockaddr_t *dst_addr,
1167
pj_ssize_t pkt_size;
1168
pj_ice_strans_comp *comp;
1172
PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1173
dst_addr && dst_addr_len, PJ_EINVAL);
1175
comp = ice_st->comp[comp_id-1];
1177
/* Check that default candidate for the component exists */
1178
def_cand = comp->default_cand;
1179
if (def_cand >= comp->cand_cnt)
1180
return PJ_EINVALIDOP;
1182
/* If ICE is available, send data with ICE, otherwise send with the
1183
* default candidate selected during initialization.
1185
* https://trac.pjsip.org/repos/ticket/1416:
1186
* Once ICE has failed, also send data with the default candidate.
1188
if (ice_st->ice && ice_st->state < PJ_ICE_STRANS_STATE_FAILED) {
1189
if (comp->turn_sock) {
1190
pj_turn_sock_lock(comp->turn_sock);
1192
status = pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len);
1193
if (comp->turn_sock) {
1194
pj_turn_sock_unlock(comp->turn_sock);
1198
} else if (comp->cand_list[def_cand].status == PJ_SUCCESS) {
1200
if (comp->cand_list[def_cand].type == PJ_ICE_CAND_TYPE_RELAYED) {
1203
msg_disable_ind = 0xFFFF &
1204
~(PJ_STUN_SESS_LOG_TX_IND|
1205
PJ_STUN_SESS_LOG_RX_IND)
1208
/* https://trac.pjsip.org/repos/ticket/1316 */
1209
if (comp->turn_sock == NULL) {
1210
/* TURN socket error */
1211
return PJ_EINVALIDOP;
1214
if (!comp->turn_log_off) {
1215
/* Disable logging for Send/Data indications */
1216
PJ_LOG(5,(ice_st->obj_name,
1217
"Disabling STUN Indication logging for "
1218
"component %d", comp->comp_id));
1219
pj_turn_sock_set_log(comp->turn_sock, msg_disable_ind);
1220
comp->turn_log_off = PJ_TRUE;
1223
status = pj_turn_sock_sendto(comp->turn_sock, (const pj_uint8_t*)data, data_len,
1224
dst_addr, dst_addr_len);
1225
return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
1226
PJ_SUCCESS : status;
1228
pkt_size = data_len;
1229
status = pj_stun_sock_sendto(comp->stun_sock, NULL, data,
1230
data_len, 0, dst_addr, dst_addr_len);
1231
return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
1232
PJ_SUCCESS : status;
1236
return PJ_EINVALIDOP;
1240
* Callback called by ICE session when ICE processing is complete, either
1241
* successfully or with failure.
1243
static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
1245
pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1249
sess_add_ref(ice_st);
1251
pj_gettimeofday(&t);
1252
PJ_TIME_VAL_SUB(t, ice_st->start_time);
1253
msec = PJ_TIME_VAL_MSEC(t);
1255
if (ice_st->cb.on_ice_complete) {
1256
if (status != PJ_SUCCESS) {
1257
char errmsg[PJ_ERR_MSG_SIZE];
1258
pj_strerror(status, errmsg, sizeof(errmsg));
1259
PJ_LOG(4,(ice_st->obj_name,
1260
"ICE negotiation failed after %ds:%03d: %s",
1261
msec/1000, msec%1000, errmsg));
1265
msg_disable_ind = 0xFFFF &
1266
~(PJ_STUN_SESS_LOG_TX_IND|
1267
PJ_STUN_SESS_LOG_RX_IND)
1270
PJ_LOG(4,(ice_st->obj_name,
1271
"ICE negotiation success after %ds:%03d",
1272
msec/1000, msec%1000));
1274
for (i=0; i<ice_st->comp_cnt; ++i) {
1275
const pj_ice_sess_check *check;
1277
check = pj_ice_strans_get_valid_pair(ice_st, i+1);
1279
char lip[PJ_INET6_ADDRSTRLEN+10];
1280
char rip[PJ_INET6_ADDRSTRLEN+10];
1282
pj_sockaddr_print(&check->lcand->addr, lip,
1284
pj_sockaddr_print(&check->rcand->addr, rip,
1287
if (check->lcand->transport_id == TP_TURN) {
1288
/* Activate channel binding for the remote address
1289
* for more efficient data transfer using TURN.
1291
status = pj_turn_sock_bind_channel(
1292
ice_st->comp[i]->turn_sock,
1293
&check->rcand->addr,
1294
sizeof(check->rcand->addr));
1296
/* Disable logging for Send/Data indications */
1297
PJ_LOG(5,(ice_st->obj_name,
1298
"Disabling STUN Indication logging for "
1299
"component %d", i+1));
1300
pj_turn_sock_set_log(ice_st->comp[i]->turn_sock,
1302
ice_st->comp[i]->turn_log_off = PJ_TRUE;
1305
PJ_LOG(4,(ice_st->obj_name, " Comp %d: "
1306
"sending from %s candidate %s to "
1309
pj_ice_get_cand_type_name(check->lcand->type),
1311
pj_ice_get_cand_type_name(check->rcand->type),
1315
PJ_LOG(4,(ice_st->obj_name,
1316
"Comp %d: disabled", i+1));
1321
ice_st->state = (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING :
1322
PJ_ICE_STRANS_STATE_FAILED;
1324
pj_log_push_indent();
1325
(*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION,
1327
pj_log_pop_indent();
1331
sess_dec_ref(ice_st);
1335
* Callback called by ICE session when it wants to send outgoing packet.
1337
static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
1339
unsigned transport_id,
1340
const void *pkt, pj_size_t size,
1341
const pj_sockaddr_t *dst_addr,
1342
unsigned dst_addr_len)
1344
pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1345
pj_ice_strans_comp *comp;
1348
PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL);
1350
comp = ice_st->comp[comp_id-1];
1352
TRACE_PKT((comp->ice_st->obj_name,
1353
"Component %d TX packet to %s:%d with transport %d",
1355
pj_inet_ntoa(((pj_sockaddr_in*)dst_addr)->sin_addr),
1356
(int)pj_ntohs(((pj_sockaddr_in*)dst_addr)->sin_port),
1359
if (transport_id == TP_TURN) {
1360
if (comp->turn_sock) {
1361
status = pj_turn_sock_sendto(comp->turn_sock,
1362
(const pj_uint8_t*)pkt, size,
1363
dst_addr, dst_addr_len);
1365
status = PJ_EINVALIDOP;
1367
} else if (transport_id == TP_STUN) {
1368
status = pj_stun_sock_sendto(comp->stun_sock, NULL,
1370
dst_addr, dst_addr_len);
1372
pj_assert(!"Invalid transport ID");
1373
status = PJ_EINVALIDOP;
1376
return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status;
1380
* Callback called by ICE session when it receives application data.
1382
static void ice_rx_data(pj_ice_sess *ice,
1384
unsigned transport_id,
1385
void *pkt, pj_size_t size,
1386
const pj_sockaddr_t *src_addr,
1387
unsigned src_addr_len)
1389
pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1391
PJ_UNUSED_ARG(transport_id);
1393
if (ice_st->cb.on_rx_data) {
1394
(*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size,
1395
src_addr, src_addr_len);
1399
/* Notification when incoming packet has been received from
1402
static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
1405
const pj_sockaddr_t *src_addr,
1408
pj_ice_strans_comp *comp;
1409
pj_ice_strans *ice_st;
1412
comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
1414
/* We have disassociated ourselves from the STUN socket */
1418
ice_st = comp->ice_st;
1420
sess_add_ref(ice_st);
1422
if (ice_st->ice == NULL) {
1423
/* The ICE session is gone, but we're still receiving packets.
1424
* This could also happen if remote doesn't do ICE. So just
1425
* report this to application.
1427
if (ice_st->cb.on_rx_data) {
1428
(*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, pkt, pkt_len,
1429
src_addr, addr_len);
1434
/* Hand over the packet to ICE session */
1435
status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
1436
TP_STUN, pkt, pkt_len,
1437
src_addr, addr_len);
1439
if (status != PJ_SUCCESS) {
1440
ice_st_perror(comp->ice_st, "Error processing packet",
1445
return sess_dec_ref(ice_st);
1448
/* Notifification when asynchronous send operation to the STUN socket
1451
static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
1452
pj_ioqueue_op_key_t *send_key,
1455
PJ_UNUSED_ARG(stun_sock);
1456
PJ_UNUSED_ARG(send_key);
1457
PJ_UNUSED_ARG(sent);
1461
/* Notification when the status of the STUN transport has changed. */
1462
static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
1466
pj_ice_strans_comp *comp;
1467
pj_ice_strans *ice_st;
1468
pj_ice_sess_cand *cand = NULL;
1471
pj_assert(status != PJ_EPENDING);
1473
comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
1474
ice_st = comp->ice_st;
1476
sess_add_ref(ice_st);
1478
/* Wait until initialization completes */
1479
pj_lock_acquire(ice_st->init_lock);
1481
/* Find the srflx cancidate */
1482
for (i=0; i<comp->cand_cnt; ++i) {
1483
if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
1484
cand = &comp->cand_list[i];
1489
pj_lock_release(ice_st->init_lock);
1491
/* It is possible that we don't have srflx candidate even though this
1492
* callback is called. This could happen when we cancel adding srflx
1493
* candidate due to initialization error.
1496
return sess_dec_ref(ice_st);
1500
case PJ_STUN_SOCK_DNS_OP:
1501
if (status != PJ_SUCCESS) {
1502
/* May not have cand, e.g. when error during init */
1504
cand->status = status;
1505
if (!ice_st->cfg.stun.ignore_stun_error) {
1506
sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1507
"DNS resolution failed", status);
1509
PJ_LOG(4,(ice_st->obj_name,
1510
"STUN error is ignored for comp %d",
1515
case PJ_STUN_SOCK_BINDING_OP:
1516
case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
1517
if (status == PJ_SUCCESS) {
1518
pj_stun_sock_info info;
1520
status = pj_stun_sock_get_info(stun_sock, &info);
1521
if (status == PJ_SUCCESS) {
1522
char ipaddr[PJ_INET6_ADDRSTRLEN+10];
1523
const char *op_name = (op==PJ_STUN_SOCK_BINDING_OP) ?
1524
"Binding discovery complete" :
1525
"srflx address changed";
1526
pj_bool_t dup = PJ_FALSE;
1528
/* Eliminate the srflx candidate if the address is
1529
* equal to other (host) candidates.
1531
for (i=0; i<comp->cand_cnt; ++i) {
1532
if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_HOST &&
1533
pj_sockaddr_cmp(&comp->cand_list[i].addr,
1534
&info.mapped_addr) == 0)
1542
/* Duplicate found, remove the srflx candidate */
1543
unsigned idx = cand - comp->cand_list;
1545
/* Update default candidate index */
1546
if (comp->default_cand > idx) {
1547
--comp->default_cand;
1548
} else if (comp->default_cand == idx) {
1549
comp->default_cand = !idx;
1552
/* Remove srflx candidate */
1553
pj_array_erase(comp->cand_list, sizeof(comp->cand_list[0]),
1554
comp->cand_cnt, idx);
1557
/* Otherwise update the address */
1558
pj_sockaddr_cp(&cand->addr, &info.mapped_addr);
1559
cand->status = PJ_SUCCESS;
1562
PJ_LOG(4,(comp->ice_st->obj_name,
1564
"srflx address is %s",
1565
comp->comp_id, op_name,
1566
pj_sockaddr_print(&info.mapped_addr, ipaddr,
1567
sizeof(ipaddr), 3)));
1569
sess_init_update(ice_st);
1573
if (status != PJ_SUCCESS) {
1574
/* May not have cand, e.g. when error during init */
1576
cand->status = status;
1577
if (!ice_st->cfg.stun.ignore_stun_error) {
1578
sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1579
"STUN binding request failed", status);
1581
PJ_LOG(4,(ice_st->obj_name,
1582
"STUN error is ignored for comp %d",
1586
unsigned idx = cand - comp->cand_list;
1588
/* Update default candidate index */
1589
if (comp->default_cand == idx) {
1590
comp->default_cand = !idx;
1594
sess_init_update(ice_st);
1598
case PJ_STUN_SOCK_KEEP_ALIVE_OP:
1599
if (status != PJ_SUCCESS) {
1600
pj_assert(cand != NULL);
1601
cand->status = status;
1602
if (!ice_st->cfg.stun.ignore_stun_error) {
1603
sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1604
"STUN keep-alive failed", status);
1606
PJ_LOG(4,(ice_st->obj_name, "STUN error is ignored"));
1612
return sess_dec_ref(ice_st);
1615
/* Callback when TURN socket has received a packet */
1616
static void turn_on_rx_data(pj_turn_sock *turn_sock,
1619
const pj_sockaddr_t *peer_addr,
1622
pj_ice_strans_comp *comp;
1625
comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
1627
/* We have disassociated ourselves from the TURN socket */
1631
sess_add_ref(comp->ice_st);
1633
if (comp->ice_st->ice == NULL) {
1634
/* The ICE session is gone, but we're still receiving packets.
1635
* This could also happen if remote doesn't do ICE and application
1636
* specifies TURN as the default address in SDP.
1637
* So in this case just give the packet to application.
1639
if (comp->ice_st->cb.on_rx_data) {
1640
(*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt,
1641
pkt_len, peer_addr, addr_len);
1646
/* Hand over the packet to ICE */
1647
status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
1648
TP_TURN, pkt, pkt_len,
1649
peer_addr, addr_len);
1651
if (status != PJ_SUCCESS) {
1652
ice_st_perror(comp->ice_st,
1653
"Error processing packet from TURN relay",
1658
sess_dec_ref(comp->ice_st);
1662
/* Callback when TURN client state has changed */
1663
static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
1664
pj_turn_state_t new_state)
1666
pj_ice_strans_comp *comp;
1668
comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
1670
/* Not interested in further state notification once the relay is
1676
PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s",
1677
pj_turn_state_name(old_state), pj_turn_state_name(new_state)));
1678
pj_log_push_indent();
1680
sess_add_ref(comp->ice_st);
1682
if (new_state == PJ_TURN_STATE_READY) {
1683
pj_turn_session_info rel_info;
1684
char ipaddr[PJ_INET6_ADDRSTRLEN+8];
1685
pj_ice_sess_cand *cand = NULL;
1688
comp->turn_err_cnt = 0;
1690
/* Get allocation info */
1691
pj_turn_sock_get_info(turn_sock, &rel_info);
1693
/* Wait until initialization completes */
1694
pj_lock_acquire(comp->ice_st->init_lock);
1696
/* Find relayed candidate in the component */
1697
for (i=0; i<comp->cand_cnt; ++i) {
1698
if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) {
1699
cand = &comp->cand_list[i];
1703
pj_assert(cand != NULL);
1705
pj_lock_release(comp->ice_st->init_lock);
1707
/* Update candidate */
1708
pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr);
1709
pj_sockaddr_cp(&cand->base_addr, &rel_info.relay_addr);
1710
pj_sockaddr_cp(&cand->rel_addr, &rel_info.mapped_addr);
1711
pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation,
1712
PJ_ICE_CAND_TYPE_RELAYED,
1713
&rel_info.relay_addr);
1714
cand->status = PJ_SUCCESS;
1716
/* Set default candidate to relay */
1717
comp->default_cand = cand - comp->cand_list;
1719
PJ_LOG(4,(comp->ice_st->obj_name,
1720
"Comp %d: TURN allocation complete, relay address is %s",
1722
pj_sockaddr_print(&rel_info.relay_addr, ipaddr,
1723
sizeof(ipaddr), 3)));
1725
sess_init_update(comp->ice_st);
1727
} else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
1728
pj_turn_session_info info;
1730
++comp->turn_err_cnt;
1732
pj_turn_sock_get_info(turn_sock, &info);
1734
/* Unregister ourself from the TURN relay */
1735
pj_turn_sock_set_user_data(turn_sock, NULL);
1736
comp->turn_sock = NULL;
1738
/* Set session to fail if we're still initializing */
1739
if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
1740
sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
1741
"TURN allocation failed", info.last_status);
1742
} else if (comp->turn_err_cnt > 1) {
1743
sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE,
1744
"TURN refresh failed", info.last_status);
1746
PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status,
1747
"Comp %d: TURN allocation failed, retrying",
1749
add_update_turn(comp->ice_st, comp);
1753
sess_dec_ref(comp->ice_st);
1755
pj_log_pop_indent();