1
/* $Id: ice_session.c 3999 2012-03-30 07:10:13Z 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_session.h>
21
#include <pj/addr_resolv.h>
23
#include <pj/assert.h>
30
#include <pj/string.h>
32
/* String names for candidate types */
33
static const char *cand_type_names[] =
42
/* String names for pj_ice_sess_check_state */
43
#if PJ_LOG_MAX_LEVEL >= 4
44
static const char *check_state_name[] =
53
static const char *clist_state_name[] =
59
#endif /* PJ_LOG_MAX_LEVEL >= 4 */
61
static const char *role_names[] =
70
TIMER_NONE, /**< Timer not active */
71
TIMER_COMPLETION_CALLBACK, /**< Call on_ice_complete() callback */
72
TIMER_CONTROLLED_WAIT_NOM, /**< Controlled agent is waiting for
73
controlling agent to send connectivity
74
check with nominated flag after it has
75
valid check for every components. */
76
TIMER_START_NOMINATED_CHECK,/**< Controlling agent start connectivity
77
checks with USE-CANDIDATE flag. */
78
TIMER_KEEP_ALIVE /**< ICE keep-alive timer. */
82
/* Candidate type preference */
83
static pj_uint8_t cand_type_prefs[4] =
85
#if PJ_ICE_CAND_TYPE_PREF_BITS < 8
86
/* Keep it to 2 bits */
87
3, /**< PJ_ICE_HOST_PREF */
88
1, /**< PJ_ICE_SRFLX_PREF. */
89
2, /**< PJ_ICE_PRFLX_PREF */
90
0 /**< PJ_ICE_RELAYED_PREF */
92
/* Default ICE session preferences, according to draft-ice */
93
126, /**< PJ_ICE_HOST_PREF */
94
100, /**< PJ_ICE_SRFLX_PREF. */
95
110, /**< PJ_ICE_PRFLX_PREF */
96
0 /**< PJ_ICE_RELAYED_PREF */
100
#define CHECK_NAME_LEN 128
101
#define LOG4(expr) PJ_LOG(4,expr)
102
#define LOG5(expr) PJ_LOG(4,expr)
103
#define GET_LCAND_ID(cand) (cand - ice->lcand)
104
#define GET_CHECK_ID(cl, chk) (chk - (cl)->checks)
107
/* The data that will be attached to the STUN session on each
110
typedef struct stun_data
114
pj_ice_sess_comp *comp;
118
/* The data that will be attached to the timer to perform
121
typedef struct timer_data
124
pj_ice_sess_checklist *clist;
128
/* This is the data that will be attached as token to outgoing
133
/* Forward declarations */
134
static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te);
135
static void on_ice_complete(pj_ice_sess *ice, pj_status_t status);
136
static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now);
137
static void destroy_ice(pj_ice_sess *ice,
139
static pj_status_t start_periodic_check(pj_timer_heap_t *th,
141
static void start_nominated_check(pj_ice_sess *ice);
142
static void periodic_timer(pj_timer_heap_t *th,
144
static void handle_incoming_check(pj_ice_sess *ice,
145
const pj_ice_rx_check *rcheck);
147
/* These are the callbacks registered to the STUN sessions */
148
static pj_status_t on_stun_send_msg(pj_stun_session *sess,
152
const pj_sockaddr_t *dst_addr,
154
static pj_status_t on_stun_rx_request(pj_stun_session *sess,
155
const pj_uint8_t *pkt,
157
const pj_stun_rx_data *rdata,
159
const pj_sockaddr_t *src_addr,
160
unsigned src_addr_len);
161
static void on_stun_request_complete(pj_stun_session *stun_sess,
164
pj_stun_tx_data *tdata,
165
const pj_stun_msg *response,
166
const pj_sockaddr_t *src_addr,
167
unsigned src_addr_len);
168
static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
169
const pj_uint8_t *pkt,
171
const pj_stun_msg *msg,
173
const pj_sockaddr_t *src_addr,
174
unsigned src_addr_len);
176
/* These are the callbacks for performing STUN authentication */
177
static pj_status_t stun_auth_get_auth(void *user_data,
181
static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg,
187
pj_stun_passwd_type *data_type,
189
static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
191
const pj_str_t *realm,
192
const pj_str_t *username,
194
pj_stun_passwd_type *data_type,
198
PJ_DEF(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type)
200
PJ_ASSERT_RETURN(type <= PJ_ICE_CAND_TYPE_RELAYED, "???");
201
return cand_type_names[type];
205
PJ_DEF(const char*) pj_ice_sess_role_name(pj_ice_sess_role role)
208
case PJ_ICE_SESS_ROLE_UNKNOWN:
210
case PJ_ICE_SESS_ROLE_CONTROLLED:
212
case PJ_ICE_SESS_ROLE_CONTROLLING:
213
return "Controlling";
220
/* Get the prefix for the foundation */
221
static int get_type_prefix(pj_ice_cand_type type)
224
case PJ_ICE_CAND_TYPE_HOST: return 'H';
225
case PJ_ICE_CAND_TYPE_SRFLX: return 'S';
226
case PJ_ICE_CAND_TYPE_PRFLX: return 'P';
227
case PJ_ICE_CAND_TYPE_RELAYED: return 'R';
229
pj_assert(!"Invalid type");
234
/* Calculate foundation:
235
* Two candidates have the same foundation when they are "similar" - of
236
* the same type and obtained from the same host candidate and STUN
237
* server using the same protocol. Otherwise, their foundation is
240
PJ_DEF(void) pj_ice_calc_foundation(pj_pool_t *pool,
241
pj_str_t *foundation,
242
pj_ice_cand_type type,
243
const pj_sockaddr *base_addr)
245
#if PJNATH_ICE_PRIO_STD
249
if (base_addr->addr.sa_family == pj_AF_INET()) {
250
val = pj_ntohl(base_addr->ipv4.sin_addr.s_addr);
252
val = pj_hash_calc(0, pj_sockaddr_get_addr(base_addr),
253
pj_sockaddr_get_addr_len(base_addr));
255
pj_ansi_snprintf(buf, sizeof(buf), "%c%x",
256
get_type_prefix(type), val);
257
pj_strdup2(pool, foundation, buf);
259
/* Much shorter version, valid for candidates added by
262
foundation->ptr = (char*) pj_pool_alloc(pool, 1);
263
*foundation->ptr = (char)get_type_prefix(type);
264
foundation->slen = 1;
266
PJ_UNUSED_ARG(base_addr);
272
static pj_status_t init_comp(pj_ice_sess *ice,
274
pj_ice_sess_comp *comp)
276
pj_stun_session_cb sess_cb;
277
pj_stun_auth_cred auth_cred;
281
/* Init STUN callbacks */
282
pj_bzero(&sess_cb, sizeof(sess_cb));
283
sess_cb.on_request_complete = &on_stun_request_complete;
284
sess_cb.on_rx_indication = &on_stun_rx_indication;
285
sess_cb.on_rx_request = &on_stun_rx_request;
286
sess_cb.on_send_msg = &on_stun_send_msg;
288
/* Create STUN session for this candidate */
289
status = pj_stun_session_create(&ice->stun_cfg, NULL,
292
if (status != PJ_SUCCESS)
295
/* Associate data with this STUN session */
296
sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data);
298
sd->comp_id = comp_id;
300
pj_stun_session_set_user_data(comp->stun_sess, sd);
302
/* Init STUN authentication credential */
303
pj_bzero(&auth_cred, sizeof(auth_cred));
304
auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
305
auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth;
306
auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred;
307
auth_cred.data.dyn_cred.get_password = &stun_auth_get_password;
308
auth_cred.data.dyn_cred.user_data = comp->stun_sess;
309
pj_stun_session_set_credential(comp->stun_sess, PJ_STUN_AUTH_SHORT_TERM,
316
/* Init options with default values */
317
PJ_DEF(void) pj_ice_sess_options_default(pj_ice_sess_options *opt)
319
opt->aggressive = PJ_TRUE;
320
opt->nominated_check_delay = PJ_ICE_NOMINATED_CHECK_DELAY;
321
opt->controlled_agent_want_nom_timeout =
322
ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT;
326
* Create ICE session.
328
PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
330
pj_ice_sess_role role,
332
const pj_ice_sess_cb *cb,
333
const pj_str_t *local_ufrag,
334
const pj_str_t *local_passwd,
342
PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
347
pool = pj_pool_create(stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_SESS,
348
PJNATH_POOL_INC_ICE_SESS, NULL);
349
ice = PJ_POOL_ZALLOC_T(pool, pj_ice_sess);
352
ice->tie_breaker.u32.hi = pj_rand();
353
ice->tie_breaker.u32.lo = pj_rand();
354
ice->prefs = cand_type_prefs;
355
pj_ice_sess_options_default(&ice->opt);
357
pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer);
359
pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
362
status = pj_mutex_create_recursive(pool, ice->obj_name,
364
if (status != PJ_SUCCESS) {
365
destroy_ice(ice, status);
369
pj_memcpy(&ice->cb, cb, sizeof(*cb));
370
pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg));
372
ice->comp_cnt = comp_cnt;
373
for (i=0; i<comp_cnt; ++i) {
374
pj_ice_sess_comp *comp;
375
comp = &ice->comp[i];
376
comp->valid_check = NULL;
377
comp->nominated_check = NULL;
379
status = init_comp(ice, i+1, comp);
380
if (status != PJ_SUCCESS) {
381
destroy_ice(ice, status);
386
/* Initialize transport datas */
387
for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
388
ice->tp_data[i].transport_id = i;
389
ice->tp_data[i].has_req_data = PJ_FALSE;
392
if (local_ufrag == NULL) {
393
ice->rx_ufrag.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
394
pj_create_random_string(ice->rx_ufrag.ptr, PJ_ICE_UFRAG_LEN);
395
ice->rx_ufrag.slen = PJ_ICE_UFRAG_LEN;
397
pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
400
if (local_passwd == NULL) {
401
ice->rx_pass.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
402
pj_create_random_string(ice->rx_pass.ptr, PJ_ICE_UFRAG_LEN);
403
ice->rx_pass.slen = PJ_ICE_UFRAG_LEN;
405
pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
408
pj_list_init(&ice->early_check);
414
"ICE session created, comp_cnt=%d, role is %s agent",
415
comp_cnt, role_names[ice->role]));
422
* Get the value of various options of the ICE session.
424
PJ_DEF(pj_status_t) pj_ice_sess_get_options(pj_ice_sess *ice,
425
pj_ice_sess_options *opt)
427
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
428
pj_memcpy(opt, &ice->opt, sizeof(*opt));
433
* Specify various options for this ICE session.
435
PJ_DEF(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice,
436
const pj_ice_sess_options *opt)
438
PJ_ASSERT_RETURN(ice && opt, PJ_EINVAL);
439
pj_memcpy(&ice->opt, opt, sizeof(*opt));
440
LOG5((ice->obj_name, "ICE nomination type set to %s",
441
(ice->opt.aggressive ? "aggressive" : "regular")));
449
static void destroy_ice(pj_ice_sess *ice,
454
if (reason == PJ_SUCCESS) {
455
LOG4((ice->obj_name, "Destroying ICE session"));
458
/* Let other callbacks finish */
460
pj_mutex_lock(ice->mutex);
461
pj_mutex_unlock(ice->mutex);
465
pj_timer_heap_cancel(ice->stun_cfg.timer_heap,
467
ice->timer.id = PJ_FALSE;
470
for (i=0; i<ice->comp_cnt; ++i) {
471
if (ice->comp[i].stun_sess) {
472
pj_stun_session_destroy(ice->comp[i].stun_sess);
473
ice->comp[i].stun_sess = NULL;
477
if (ice->clist.timer.id) {
478
pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer);
479
ice->clist.timer.id = PJ_FALSE;
483
pj_mutex_destroy(ice->mutex);
488
pj_pool_t *pool = ice->pool;
490
pj_pool_release(pool);
498
PJ_DEF(pj_status_t) pj_ice_sess_destroy(pj_ice_sess *ice)
500
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
501
destroy_ice(ice, PJ_SUCCESS);
507
* Change session role.
509
PJ_DEF(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
510
pj_ice_sess_role new_role)
512
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
514
if (new_role != ice->role) {
515
ice->role = new_role;
516
LOG4((ice->obj_name, "Role changed to %s", role_names[new_role]));
524
* Change type preference
526
PJ_DEF(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
527
const pj_uint8_t prefs[4])
530
PJ_ASSERT_RETURN(ice && prefs, PJ_EINVAL);
531
ice->prefs = (pj_uint8_t*) pj_pool_calloc(ice->pool, PJ_ARRAY_SIZE(prefs),
533
for (i=0; i<4; ++i) {
534
#if PJ_ICE_CAND_TYPE_PREF_BITS < 8
535
pj_assert(prefs[i] < (2 << PJ_ICE_CAND_TYPE_PREF_BITS));
537
ice->prefs[i] = prefs[i];
543
/* Find component by ID */
544
static pj_ice_sess_comp *find_comp(const pj_ice_sess *ice, unsigned comp_id)
546
pj_assert(comp_id > 0 && comp_id <= ice->comp_cnt);
547
return (pj_ice_sess_comp*) &ice->comp[comp_id-1];
551
/* Callback by STUN authentication when it needs to send 401 */
552
static pj_status_t stun_auth_get_auth(void *user_data,
557
PJ_UNUSED_ARG(user_data);
567
/* Get credential to be sent with outgoing message */
568
static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg,
574
pj_stun_passwd_type *data_type,
577
pj_stun_session *sess = (pj_stun_session *)user_data;
578
stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
579
pj_ice_sess *ice = sd->ice;
582
realm->slen = nonce->slen = 0;
584
if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
585
/* Outgoing responses need to have the same credential as
588
*username = ice->rx_uname;
589
*data_type = PJ_STUN_PASSWD_PLAIN;
590
*data = ice->rx_pass;
593
*username = ice->tx_uname;
594
*data_type = PJ_STUN_PASSWD_PLAIN;
595
*data = ice->tx_pass;
601
/* Get password to be used to authenticate incoming message */
602
static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
604
const pj_str_t *realm,
605
const pj_str_t *username,
607
pj_stun_passwd_type *data_type,
610
pj_stun_session *sess = (pj_stun_session *)user_data;
611
stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
612
pj_ice_sess *ice = sd->ice;
614
PJ_UNUSED_ARG(realm);
617
if (PJ_STUN_IS_SUCCESS_RESPONSE(msg->hdr.type) ||
618
PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
620
/* Incoming response is authenticated with TX credential */
621
/* Verify username */
622
if (pj_strcmp(username, &ice->tx_uname) != 0)
623
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
624
*data_type = PJ_STUN_PASSWD_PLAIN;
625
*data = ice->tx_pass;
628
/* Incoming request is authenticated with RX credential */
629
/* The agent MUST accept a credential if the username consists
630
* of two values separated by a colon, where the first value is
631
* equal to the username fragment generated by the agent in an offer
632
* or answer for a session in-progress, and the MESSAGE-INTEGRITY
633
* is the output of a hash of the password and the STUN packet's
639
pos = (const char*)pj_memchr(username->ptr, ':', username->slen);
641
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
643
ufrag.ptr = (char*)username->ptr;
644
ufrag.slen = (pos - username->ptr);
646
if (pj_strcmp(&ufrag, &ice->rx_ufrag) != 0)
647
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
649
*data_type = PJ_STUN_PASSWD_PLAIN;
650
*data = ice->rx_pass;
658
static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice,
659
pj_ice_cand_type type,
660
pj_uint32_t local_pref,
663
#if PJNATH_ICE_PRIO_STD
664
return ((ice->prefs[type] & 0xFF) << 24) +
665
((local_pref & 0xFFFF) << 8) +
666
(((256 - comp_id) & 0xFF) << 0);
669
type_mask = ((2 << PJ_ICE_CAND_TYPE_PREF_BITS) - 1),
670
local_mask = ((2 << PJ_ICE_LOCAL_PREF_BITS) - 1),
671
comp_mask = ((2 << PJ_ICE_COMP_BITS) - 1),
674
local_shift = (PJ_ICE_COMP_BITS),
675
type_shift = (comp_shift + local_shift),
677
max_comp = (2<<PJ_ICE_COMP_BITS),
680
return ((ice->prefs[type] & type_mask) << type_shift) +
681
((local_pref & local_mask) << local_shift) +
682
(((max_comp - comp_id) & comp_mask) << comp_shift);
690
PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
692
unsigned transport_id,
693
pj_ice_cand_type type,
694
pj_uint16_t local_pref,
695
const pj_str_t *foundation,
696
const pj_sockaddr_t *addr,
697
const pj_sockaddr_t *base_addr,
698
const pj_sockaddr_t *rel_addr,
702
pj_ice_sess_cand *lcand;
703
pj_status_t status = PJ_SUCCESS;
705
PJ_ASSERT_RETURN(ice && comp_id &&
706
foundation && addr && base_addr && addr_len,
708
PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
710
pj_mutex_lock(ice->mutex);
712
if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) {
713
status = PJ_ETOOMANY;
717
lcand = &ice->lcand[ice->lcand_cnt];
718
lcand->comp_id = (pj_uint8_t)comp_id;
719
lcand->transport_id = (pj_uint8_t)transport_id;
721
pj_strdup(ice->pool, &lcand->foundation, foundation);
722
lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
723
pj_memcpy(&lcand->addr, addr, addr_len);
724
pj_memcpy(&lcand->base_addr, base_addr, addr_len);
725
if (rel_addr == NULL)
726
rel_addr = base_addr;
727
pj_memcpy(&lcand->rel_addr, rel_addr, addr_len);
729
pj_ansi_strcpy(ice->tmp.txt, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
731
"Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, "
732
"addr=%s:%d, base=%s:%d, prio=0x%x (%u)",
735
cand_type_names[lcand->type],
736
(int)lcand->foundation.slen,
737
lcand->foundation.ptr,
739
(int)pj_ntohs(lcand->addr.ipv4.sin_port),
740
pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr),
741
(int)pj_htons(lcand->base_addr.ipv4.sin_port),
742
lcand->prio, lcand->prio));
745
*p_cand_id = ice->lcand_cnt;
750
pj_mutex_unlock(ice->mutex);
755
/* Find default candidate ID for the component */
756
PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
762
PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL);
763
PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
767
pj_mutex_lock(ice->mutex);
769
/* First find in valid list if we have nominated pair */
770
for (i=0; i<ice->valid_list.count; ++i) {
771
pj_ice_sess_check *check = &ice->valid_list.checks[i];
773
if (check->lcand->comp_id == comp_id) {
774
*cand_id = GET_LCAND_ID(check->lcand);
775
pj_mutex_unlock(ice->mutex);
780
/* If there's no nominated pair, find relayed candidate */
781
for (i=0; i<ice->lcand_cnt; ++i) {
782
pj_ice_sess_cand *lcand = &ice->lcand[i];
783
if (lcand->comp_id==comp_id &&
784
lcand->type == PJ_ICE_CAND_TYPE_RELAYED)
786
*cand_id = GET_LCAND_ID(lcand);
787
pj_mutex_unlock(ice->mutex);
792
/* If there's no relayed candidate, find reflexive candidate */
793
for (i=0; i<ice->lcand_cnt; ++i) {
794
pj_ice_sess_cand *lcand = &ice->lcand[i];
795
if (lcand->comp_id==comp_id &&
796
(lcand->type == PJ_ICE_CAND_TYPE_SRFLX ||
797
lcand->type == PJ_ICE_CAND_TYPE_PRFLX))
799
*cand_id = GET_LCAND_ID(lcand);
800
pj_mutex_unlock(ice->mutex);
805
/* Otherwise return host candidate */
806
for (i=0; i<ice->lcand_cnt; ++i) {
807
pj_ice_sess_cand *lcand = &ice->lcand[i];
808
if (lcand->comp_id==comp_id &&
809
lcand->type == PJ_ICE_CAND_TYPE_HOST)
811
*cand_id = GET_LCAND_ID(lcand);
812
pj_mutex_unlock(ice->mutex);
817
/* Still no candidate is found! :( */
818
pj_mutex_unlock(ice->mutex);
820
pj_assert(!"Should have a candidate by now");
826
# define MIN(a,b) (a < b ? a : b)
830
# define MAX(a,b) (a > b ? a : b)
833
static pj_timestamp CALC_CHECK_PRIO(const pj_ice_sess *ice,
834
const pj_ice_sess_cand *lcand,
835
const pj_ice_sess_cand *rcand)
841
* pair priority = 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0)
844
if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
853
return ((pj_uint64_t)1 << 32) * MIN(O, A) +
854
(pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0);
857
prio.u32.hi = MIN(O,A);
858
prio.u32.lo = (MAX(O, A) << 1) + (O>A ? 1 : 0);
864
PJ_INLINE(int) CMP_CHECK_PRIO(const pj_ice_sess_check *c1,
865
const pj_ice_sess_check *c2)
867
return pj_cmp_timestamp(&c1->prio, &c2->prio);
871
#if PJ_LOG_MAX_LEVEL >= 4
872
static const char *dump_check(char *buffer, unsigned bufsize,
873
const pj_ice_sess_checklist *clist,
874
const pj_ice_sess_check *check)
876
const pj_ice_sess_cand *lcand = check->lcand;
877
const pj_ice_sess_cand *rcand = check->rcand;
878
char laddr[PJ_INET6_ADDRSTRLEN];
883
pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
885
if (lcand->addr.addr.sa_family == pj_AF_INET()) {
886
len = pj_ansi_snprintf(buffer, bufsize,
887
"%d: [%d] %s:%d-->%s:%d",
888
(int)GET_CHECK_ID(clist, check),
889
check->lcand->comp_id,
890
laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port),
891
pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
892
(int)pj_ntohs(rcand->addr.ipv4.sin_port));
894
len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6");
900
else if (len >= (int)bufsize)
907
static void dump_checklist(const char *title, pj_ice_sess *ice,
908
const pj_ice_sess_checklist *clist)
912
LOG4((ice->obj_name, "%s", title));
913
for (i=0; i<clist->count; ++i) {
914
const pj_ice_sess_check *c = &clist->checks[i];
915
LOG4((ice->obj_name, " %s (%s, state=%s)",
916
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, c),
917
(c->nominated ? "nominated" : "not nominated"),
918
check_state_name[c->state]));
923
#define dump_checklist(title, ice, clist)
926
static void check_set_state(pj_ice_sess *ice, pj_ice_sess_check *check,
927
pj_ice_sess_check_state st,
928
pj_status_t err_code)
930
pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
932
LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
933
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), &ice->clist, check),
934
check_state_name[check->state],
935
check_state_name[st]));
937
check->err_code = err_code;
940
static void clist_set_state(pj_ice_sess *ice, pj_ice_sess_checklist *clist,
941
pj_ice_sess_checklist_state st)
943
if (clist->state != st) {
944
LOG5((ice->obj_name, "Checklist: state changed from %s to %s",
945
clist_state_name[clist->state],
946
clist_state_name[st]));
951
/* Sort checklist based on priority */
952
static void sort_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist)
955
pj_ice_sess_check **check_ptr[PJ_ICE_MAX_COMP*2];
956
unsigned check_ptr_cnt = 0;
958
for (i=0; i<ice->comp_cnt; ++i) {
959
if (ice->comp[i].valid_check) {
960
check_ptr[check_ptr_cnt++] = &ice->comp[i].valid_check;
962
if (ice->comp[i].nominated_check) {
963
check_ptr[check_ptr_cnt++] = &ice->comp[i].nominated_check;
967
for (i=0; i<clist->count-1; ++i) {
968
unsigned j, highest = i;
970
for (j=i+1; j<clist->count; ++j) {
971
if (CMP_CHECK_PRIO(&clist->checks[j], &clist->checks[highest]) > 0) {
977
pj_ice_sess_check tmp;
980
pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_sess_check));
981
pj_memcpy(&clist->checks[i], &clist->checks[highest],
982
sizeof(pj_ice_sess_check));
983
pj_memcpy(&clist->checks[highest], &tmp,
984
sizeof(pj_ice_sess_check));
986
/* Update valid and nominated check pointers, since we're moving
989
for (k=0; k<check_ptr_cnt; ++k) {
990
if (*check_ptr[k] == &clist->checks[highest])
991
*check_ptr[k] = &clist->checks[i];
992
else if (*check_ptr[k] == &clist->checks[i])
993
*check_ptr[k] = &clist->checks[highest];
1002
SOCKADDR_NOT_EQUAL = 1
1005
/* Utility: compare sockaddr.
1006
* Returns 0 if equal.
1008
static int sockaddr_cmp(const pj_sockaddr *a1, const pj_sockaddr *a2)
1010
if (a1->addr.sa_family != a2->addr.sa_family)
1011
return SOCKADDR_NOT_EQUAL;
1013
if (a1->addr.sa_family == pj_AF_INET()) {
1014
return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr &&
1015
a1->ipv4.sin_port == a2->ipv4.sin_port);
1016
} else if (a1->addr.sa_family == pj_AF_INET6()) {
1017
return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6));
1019
pj_assert(!"Invalid address family!");
1020
return SOCKADDR_NOT_EQUAL;
1025
/* Prune checklist, this must have been done after the checklist
1028
static pj_status_t prune_checklist(pj_ice_sess *ice,
1029
pj_ice_sess_checklist *clist)
1033
/* Since an agent cannot send requests directly from a reflexive
1034
* candidate, but only from its base, the agent next goes through the
1035
* sorted list of candidate pairs. For each pair where the local
1036
* candidate is server reflexive, the server reflexive candidate MUST be
1037
* replaced by its base. Once this has been done, the agent MUST prune
1038
* the list. This is done by removing a pair if its local and remote
1039
* candidates are identical to the local and remote candidates of a pair
1040
* higher up on the priority list. The result is a sequence of ordered
1041
* candidate pairs, called the check list for that media stream.
1043
/* First replace SRFLX candidates with their base */
1044
for (i=0; i<clist->count; ++i) {
1045
pj_ice_sess_cand *srflx = clist->checks[i].lcand;
1047
if (clist->checks[i].lcand->type == PJ_ICE_CAND_TYPE_SRFLX) {
1048
/* Find the base for this candidate */
1050
for (j=0; j<ice->lcand_cnt; ++j) {
1051
pj_ice_sess_cand *host = &ice->lcand[j];
1053
if (host->type != PJ_ICE_CAND_TYPE_HOST)
1056
if (sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) {
1057
/* Replace this SRFLX with its BASE */
1058
clist->checks[i].lcand = host;
1063
if (j==ice->lcand_cnt) {
1064
/* Host candidate not found this this srflx! */
1065
LOG4((ice->obj_name,
1066
"Base candidate %s:%d not found for srflx candidate %d",
1067
pj_inet_ntoa(srflx->base_addr.ipv4.sin_addr),
1068
pj_ntohs(srflx->base_addr.ipv4.sin_port),
1069
GET_LCAND_ID(clist->checks[i].lcand)));
1070
return PJNATH_EICENOHOSTCAND;
1075
/* Next remove a pair if its local and remote candidates are identical
1076
* to the local and remote candidates of a pair higher up on the priority
1081
* Remove host candidates if their base are the the same!
1083
for (i=0; i<clist->count; ++i) {
1084
pj_ice_sess_cand *licand = clist->checks[i].lcand;
1085
pj_ice_sess_cand *ricand = clist->checks[i].rcand;
1088
for (j=i+1; j<clist->count;) {
1089
pj_ice_sess_cand *ljcand = clist->checks[j].lcand;
1090
pj_ice_sess_cand *rjcand = clist->checks[j].rcand;
1091
const char *reason = NULL;
1093
if ((licand == ljcand) && (ricand == rjcand)) {
1094
reason = "duplicate found";
1095
} else if ((rjcand == ricand) &&
1096
(sockaddr_cmp(&ljcand->base_addr,
1097
&licand->base_addr)==0))
1099
reason = "equal base";
1102
if (reason != NULL) {
1103
/* Found duplicate, remove it */
1104
LOG5((ice->obj_name, "Check %s pruned (%s)",
1105
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1106
&ice->clist, &clist->checks[j]),
1109
pj_array_erase(clist->checks, sizeof(clist->checks[0]),
1122
/* Timer callback */
1123
static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te)
1125
pj_ice_sess *ice = (pj_ice_sess*) te->user_data;
1126
enum timer_type type = (enum timer_type)te->id;
1127
pj_bool_t has_mutex = PJ_TRUE;
1131
pj_mutex_lock(ice->mutex);
1133
te->id = TIMER_NONE;
1136
case TIMER_CONTROLLED_WAIT_NOM:
1137
LOG4((ice->obj_name,
1138
"Controlled agent timed-out in waiting for the controlling "
1139
"agent to send nominated check. Setting state to fail now.."));
1140
on_ice_complete(ice, PJNATH_EICENOMTIMEOUT);
1142
case TIMER_COMPLETION_CALLBACK:
1144
void (*on_ice_complete)(pj_ice_sess *ice, pj_status_t status);
1145
pj_status_t ice_status;
1147
/* Start keep-alive timer but don't send any packets yet.
1148
* Need to do it here just in case app destroy the session
1151
if (ice->ice_status == PJ_SUCCESS)
1152
ice_keep_alive(ice, PJ_FALSE);
1154
/* Release mutex in case app destroy us in the callback */
1155
ice_status = ice->ice_status;
1156
on_ice_complete = ice->cb.on_ice_complete;
1157
has_mutex = PJ_FALSE;
1158
pj_mutex_unlock(ice->mutex);
1160
/* Notify app about ICE completion*/
1161
if (on_ice_complete)
1162
(*on_ice_complete)(ice, ice_status);
1165
case TIMER_START_NOMINATED_CHECK:
1166
start_nominated_check(ice);
1168
case TIMER_KEEP_ALIVE:
1169
ice_keep_alive(ice, PJ_TRUE);
1172
/* Nothing to do, just to get rid of gcc warning */
1177
pj_mutex_unlock(ice->mutex);
1180
/* Send keep-alive */
1181
static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now)
1184
/* Send Binding Indication for the component */
1185
pj_ice_sess_comp *comp = &ice->comp[ice->comp_ka];
1186
pj_stun_tx_data *tdata;
1187
pj_ice_sess_check *the_check;
1188
pj_ice_msg_data *msg_data;
1193
/* Must have nominated check by now */
1194
pj_assert(comp->nominated_check != NULL);
1195
the_check = comp->nominated_check;
1197
/* Create the Binding Indication */
1198
status = pj_stun_session_create_ind(comp->stun_sess,
1199
PJ_STUN_BINDING_INDICATION,
1201
if (status != PJ_SUCCESS)
1204
/* Need the transport_id */
1205
msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
1206
msg_data->transport_id = the_check->lcand->transport_id;
1208
/* Temporarily disable FINGERPRINT. The Binding Indication
1209
* SHOULD NOT contain any attributes.
1211
saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_FALSE);
1213
/* Send to session */
1214
addr_len = pj_sockaddr_get_len(&the_check->rcand->addr);
1215
status = pj_stun_session_send_msg(comp->stun_sess, msg_data,
1217
&the_check->rcand->addr,
1220
/* Restore FINGERPRINT usage */
1221
pj_stun_session_use_fingerprint(comp->stun_sess, saved);
1224
ice->comp_ka = (ice->comp_ka + 1) % ice->comp_cnt;
1227
if (ice->timer.id == TIMER_NONE) {
1228
pj_time_val delay = { 0, 0 };
1230
delay.msec = (PJ_ICE_SESS_KEEP_ALIVE_MIN +
1231
(pj_rand() % PJ_ICE_SESS_KEEP_ALIVE_MAX_RAND)) * 1000 /
1233
pj_time_val_normalize(&delay);
1235
ice->timer.id = TIMER_KEEP_ALIVE;
1236
pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay);
1239
pj_assert(!"Not expected any timer active");
1243
/* This function is called when ICE processing completes */
1244
static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
1246
if (!ice->is_complete) {
1247
ice->is_complete = PJ_TRUE;
1248
ice->ice_status = status;
1250
if (ice->timer.id != TIMER_NONE) {
1251
pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
1252
ice->timer.id = TIMER_NONE;
1256
LOG4((ice->obj_name, "ICE process complete, status=%s",
1257
pj_strerror(status, ice->tmp.errmsg,
1258
sizeof(ice->tmp.errmsg)).ptr));
1260
dump_checklist("Valid list", ice, &ice->valid_list);
1263
if (ice->cb.on_ice_complete) {
1264
pj_time_val delay = {0, 0};
1266
ice->timer.id = TIMER_COMPLETION_CALLBACK;
1267
pj_timer_heap_schedule(ice->stun_cfg.timer_heap,
1268
&ice->timer, &delay);
1273
/* Update valid check and nominated check for the candidate */
1274
static void update_comp_check(pj_ice_sess *ice, unsigned comp_id,
1275
pj_ice_sess_check *check)
1277
pj_ice_sess_comp *comp;
1279
comp = find_comp(ice, comp_id);
1280
if (comp->valid_check == NULL) {
1281
comp->valid_check = check;
1283
if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
1284
comp->valid_check = check;
1287
if (check->nominated) {
1288
/* Update the nominated check for the component */
1289
if (comp->nominated_check == NULL) {
1290
comp->nominated_check = check;
1292
if (CMP_CHECK_PRIO(comp->nominated_check, check) < 0)
1293
comp->nominated_check = check;
1298
/* This function is called when one check completes */
1299
static pj_bool_t on_check_complete(pj_ice_sess *ice,
1300
pj_ice_sess_check *check)
1302
pj_ice_sess_comp *comp;
1305
pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
1307
comp = find_comp(ice, check->lcand->comp_id);
1309
/* 7.1.2.2.2. Updating Pair States
1311
* The agent sets the state of the pair that generated the check to
1312
* Succeeded. The success of this check might also cause the state of
1313
* other checks to change as well. The agent MUST perform the following
1316
* 1. The agent changes the states for all other Frozen pairs for the
1317
* same media stream and same foundation to Waiting. Typically
1318
* these other pairs will have different component IDs but not
1321
if (check->err_code==PJ_SUCCESS) {
1323
for (i=0; i<ice->clist.count; ++i) {
1324
pj_ice_sess_check *c = &ice->clist.checks[i];
1325
if (pj_strcmp(&c->lcand->foundation, &check->lcand->foundation)==0
1326
&& c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN)
1328
check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
1332
LOG5((ice->obj_name, "Check %d is successful%s",
1333
GET_CHECK_ID(&ice->clist, check),
1334
(check->nominated ? " and nominated" : "")));
1338
/* 8.2. Updating States
1340
* For both controlling and controlled agents, the state of ICE
1341
* processing depends on the presence of nominated candidate pairs in
1342
* the valid list and on the state of the check list:
1344
* o If there are no nominated pairs in the valid list for a media
1345
* stream and the state of the check list is Running, ICE processing
1348
* o If there is at least one nominated pair in the valid list:
1350
* - The agent MUST remove all Waiting and Frozen pairs in the check
1351
* list for the same component as the nominated pairs for that
1354
* - If an In-Progress pair in the check list is for the same
1355
* component as a nominated pair, the agent SHOULD cease
1356
* retransmissions for its check if its pair priority is lower
1357
* than the lowest priority nominated pair for that component
1359
if (check->err_code==PJ_SUCCESS && check->nominated) {
1361
for (i=0; i<ice->clist.count; ++i) {
1363
pj_ice_sess_check *c = &ice->clist.checks[i];
1365
if (c->lcand->comp_id == check->lcand->comp_id) {
1367
if (c->state < PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
1369
/* Just fail Frozen/Waiting check */
1370
LOG5((ice->obj_name,
1371
"Check %s to be failed because state is %s",
1372
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1374
check_state_name[c->state]));
1375
check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
1378
} else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS
1379
&& (PJ_ICE_CANCEL_ALL ||
1380
CMP_CHECK_PRIO(c, check) < 0)) {
1382
/* State is IN_PROGRESS, cancel transaction */
1384
LOG5((ice->obj_name,
1385
"Cancelling check %s (In Progress)",
1386
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1388
pj_stun_session_cancel_req(comp->stun_sess,
1389
c->tdata, PJ_FALSE, 0);
1391
check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
1400
/* Still in 8.2. Updating States
1402
* o Once there is at least one nominated pair in the valid list for
1403
* every component of at least one media stream and the state of the
1404
* check list is Running:
1406
* * The agent MUST change the state of processing for its check
1407
* list for that media stream to Completed.
1409
* * The agent MUST continue to respond to any checks it may still
1410
* receive for that media stream, and MUST perform triggered
1411
* checks if required by the processing of Section 7.2.
1413
* * The agent MAY begin transmitting media for this media stream as
1414
* described in Section 11.1
1417
/* See if all components have nominated pair. If they do, then mark
1418
* ICE processing as success, otherwise wait.
1420
for (i=0; i<ice->comp_cnt; ++i) {
1421
if (ice->comp[i].nominated_check == NULL)
1424
if (i == ice->comp_cnt) {
1425
/* All components have nominated pair */
1426
on_ice_complete(ice, PJ_SUCCESS);
1430
/* Note: this is the stuffs that we don't do in 7.1.2.2.2, since our
1431
* ICE session only supports one media stream for now:
1433
* 7.1.2.2.2. Updating Pair States
1435
* 2. If there is a pair in the valid list for every component of this
1436
* media stream (where this is the actual number of components being
1437
* used, in cases where the number of components signaled in the SDP
1438
* differs from offerer to answerer), the success of this check may
1439
* unfreeze checks for other media streams.
1442
/* 7.1.2.3. Check List and Timer State Updates
1443
* Regardless of whether the check was successful or failed, the
1444
* completion of the transaction may require updating of check list and
1447
* If all of the pairs in the check list are now either in the Failed or
1448
* Succeeded state, and there is not a pair in the valid list for each
1449
* component of the media stream, the state of the check list is set to
1454
* See if all checks in the checklist have completed. If we do,
1455
* then mark ICE processing as failed.
1457
for (i=0; i<ice->clist.count; ++i) {
1458
pj_ice_sess_check *c = &ice->clist.checks[i];
1459
if (c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
1464
if (i == ice->clist.count) {
1465
/* All checks have completed, but we don't have nominated pair.
1466
* If agent's role is controlled, check if all components have
1467
* valid pair. If it does, this means the controlled agent has
1468
* finished the check list and it's waiting for controlling
1469
* agent to send checks with USE-CANDIDATE flag set.
1471
if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED) {
1472
for (i=0; i < ice->comp_cnt; ++i) {
1473
if (ice->comp[i].valid_check == NULL)
1477
if (i < ice->comp_cnt) {
1478
/* This component ID doesn't have valid pair.
1479
* Mark ICE as failed.
1481
on_ice_complete(ice, PJNATH_EICEFAILED);
1484
/* All components have a valid pair.
1485
* We should wait until we receive nominated checks.
1487
if (ice->timer.id == TIMER_NONE &&
1488
ice->opt.controlled_agent_want_nom_timeout >= 0)
1493
delay.msec = ice->opt.controlled_agent_want_nom_timeout;
1494
pj_time_val_normalize(&delay);
1496
ice->timer.id = TIMER_CONTROLLED_WAIT_NOM;
1497
pj_timer_heap_schedule(ice->stun_cfg.timer_heap,
1501
LOG5((ice->obj_name,
1502
"All checks have completed. Controlled agent now "
1503
"waits for nomination from controlling agent "
1504
"(timeout=%d msec)",
1505
ice->opt.controlled_agent_want_nom_timeout));
1512
} else if (ice->is_nominating) {
1513
/* We are controlling agent and all checks have completed but
1514
* there's at least one component without nominated pair (or
1515
* more likely we don't have any nominated pairs at all).
1517
on_ice_complete(ice, PJNATH_EICEFAILED);
1521
/* We are controlling agent and all checks have completed. If
1522
* we have valid list for every component, then move on to
1523
* sending nominated check, otherwise we have failed.
1525
for (i=0; i<ice->comp_cnt; ++i) {
1526
if (ice->comp[i].valid_check == NULL)
1530
if (i < ice->comp_cnt) {
1531
/* At least one component doesn't have a valid check. Mark
1534
on_ice_complete(ice, PJNATH_EICEFAILED);
1538
/* Now it's time to send connectivity check with nomination
1541
LOG4((ice->obj_name,
1542
"All checks have completed, starting nominated checks now"));
1543
start_nominated_check(ice);
1548
/* If this connectivity check has been successful, scan all components
1549
* and see if they have a valid pair, if we are controlling and we haven't
1550
* started our nominated check yet.
1552
if (check->err_code == PJ_SUCCESS &&
1553
ice->role==PJ_ICE_SESS_ROLE_CONTROLLING &&
1554
!ice->is_nominating &&
1555
ice->timer.id == TIMER_NONE)
1559
for (i=0; i<ice->comp_cnt; ++i) {
1560
if (ice->comp[i].valid_check == NULL)
1564
if (i < ice->comp_cnt) {
1565
/* Some components still don't have valid pair, continue
1571
LOG4((ice->obj_name,
1572
"Scheduling nominated check in %d ms",
1573
ice->opt.nominated_check_delay));
1575
if (ice->timer.id != TIMER_NONE) {
1576
pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
1577
ice->timer.id = TIMER_NONE;
1580
/* All components have valid pair. Let connectivity checks run for
1581
* a little bit more time, then start our nominated check.
1584
delay.msec = ice->opt.nominated_check_delay;
1585
pj_time_val_normalize(&delay);
1587
ice->timer.id = TIMER_START_NOMINATED_CHECK;
1588
pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay);
1592
/* We still have checks to perform */
1597
/* Create checklist by pairing local candidates with remote candidates */
1598
PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
1600
const pj_str_t *rem_ufrag,
1601
const pj_str_t *rem_passwd,
1603
const pj_ice_sess_cand rcand[])
1605
pj_ice_sess_checklist *clist;
1610
unsigned highest_comp = 0;
1613
PJ_ASSERT_RETURN(ice && rem_ufrag && rem_passwd && rcand_cnt && rcand,
1615
PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND,
1618
pj_mutex_lock(ice->mutex);
1620
/* Save credentials */
1623
pj_strcpy(&username, rem_ufrag);
1624
pj_strcat2(&username, ":");
1625
pj_strcat(&username, &ice->rx_ufrag);
1627
pj_strdup(ice->pool, &ice->tx_uname, &username);
1628
pj_strdup(ice->pool, &ice->tx_ufrag, rem_ufrag);
1629
pj_strdup(ice->pool, &ice->tx_pass, rem_passwd);
1631
pj_strcpy(&username, &ice->rx_ufrag);
1632
pj_strcat2(&username, ":");
1633
pj_strcat(&username, rem_ufrag);
1635
pj_strdup(ice->pool, &ice->rx_uname, &username);
1638
/* Save remote candidates */
1640
for (i=0; i<rcand_cnt; ++i) {
1641
pj_ice_sess_cand *cn = &ice->rcand[ice->rcand_cnt];
1643
/* Ignore candidate which has no matching component ID */
1644
if (rcand[i].comp_id==0 || rcand[i].comp_id > ice->comp_cnt) {
1648
if (rcand[i].comp_id > highest_comp)
1649
highest_comp = rcand[i].comp_id;
1651
pj_memcpy(cn, &rcand[i], sizeof(pj_ice_sess_cand));
1652
pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation);
1656
/* Generate checklist */
1657
clist = &ice->clist;
1658
for (i=0; i<ice->lcand_cnt; ++i) {
1659
for (j=0; j<ice->rcand_cnt; ++j) {
1661
pj_ice_sess_cand *lcand = &ice->lcand[i];
1662
pj_ice_sess_cand *rcand = &ice->rcand[j];
1663
pj_ice_sess_check *chk = &clist->checks[clist->count];
1665
if (clist->count >= PJ_ICE_MAX_CHECKS) {
1666
pj_mutex_unlock(ice->mutex);
1670
/* A local candidate is paired with a remote candidate if
1671
* and only if the two candidates have the same component ID
1672
* and have the same IP address version.
1674
if ((lcand->comp_id != rcand->comp_id) ||
1675
(lcand->addr.addr.sa_family != rcand->addr.addr.sa_family))
1683
chk->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
1685
chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
1691
/* Sort checklist based on priority */
1692
sort_checklist(ice, clist);
1694
/* Prune the checklist */
1695
status = prune_checklist(ice, clist);
1696
if (status != PJ_SUCCESS) {
1697
pj_mutex_unlock(ice->mutex);
1701
/* Disable our components which don't have matching component */
1702
for (i=highest_comp; i<ice->comp_cnt; ++i) {
1703
if (ice->comp[i].stun_sess) {
1704
pj_stun_session_destroy(ice->comp[i].stun_sess);
1705
pj_bzero(&ice->comp[i], sizeof(ice->comp[i]));
1708
ice->comp_cnt = highest_comp;
1710
/* Init timer entry in the checklist. Initially the timer ID is FALSE
1711
* because timer is not running.
1713
clist->timer.id = PJ_FALSE;
1714
td = PJ_POOL_ZALLOC_T(ice->pool, timer_data);
1717
clist->timer.user_data = (void*)td;
1718
clist->timer.cb = &periodic_timer;
1722
dump_checklist("Checklist created:", ice, clist);
1724
pj_mutex_unlock(ice->mutex);
1729
/* Perform check on the specified candidate pair. */
1730
static pj_status_t perform_check(pj_ice_sess *ice,
1731
pj_ice_sess_checklist *clist,
1735
pj_ice_sess_comp *comp;
1736
pj_ice_msg_data *msg_data;
1737
pj_ice_sess_check *check;
1738
const pj_ice_sess_cand *lcand;
1739
const pj_ice_sess_cand *rcand;
1743
check = &clist->checks[check_id];
1744
lcand = check->lcand;
1745
rcand = check->rcand;
1746
comp = find_comp(ice, lcand->comp_id);
1748
LOG5((ice->obj_name,
1749
"Sending connectivity check for check %s",
1750
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, check)));
1751
pj_log_push_indent();
1753
/* Create request */
1754
status = pj_stun_session_create_req(comp->stun_sess,
1755
PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC,
1756
NULL, &check->tdata);
1757
if (status != PJ_SUCCESS) {
1758
pjnath_perror(ice->obj_name, "Error creating STUN request", status);
1759
pj_log_pop_indent();
1763
/* Attach data to be retrieved later when STUN request transaction
1764
* completes and on_stun_request_complete() callback is called.
1766
msg_data = PJ_POOL_ZALLOC_T(check->tdata->pool, pj_ice_msg_data);
1767
msg_data->transport_id = lcand->transport_id;
1768
msg_data->has_req_data = PJ_TRUE;
1769
msg_data->data.req.ice = ice;
1770
msg_data->data.req.clist = clist;
1771
msg_data->data.req.ckid = check_id;
1774
#if PJNATH_ICE_PRIO_STD
1775
prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535,
1778
prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 0,
1781
pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg,
1782
PJ_STUN_ATTR_PRIORITY, prio);
1784
/* Add USE-CANDIDATE and set this check to nominated.
1785
* Also add ICE-CONTROLLING or ICE-CONTROLLED
1787
if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
1789
pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg,
1790
PJ_STUN_ATTR_USE_CANDIDATE);
1791
check->nominated = PJ_TRUE;
1794
pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,
1795
PJ_STUN_ATTR_ICE_CONTROLLING,
1799
pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,
1800
PJ_STUN_ATTR_ICE_CONTROLLED,
1805
/* Note that USERNAME and MESSAGE-INTEGRITY will be added by the
1809
/* Initiate STUN transaction to send the request */
1810
status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE,
1811
PJ_TRUE, &rcand->addr,
1812
sizeof(pj_sockaddr_in), check->tdata);
1813
if (status != PJ_SUCCESS) {
1814
check->tdata = NULL;
1815
pjnath_perror(ice->obj_name, "Error sending STUN request", status);
1816
pj_log_pop_indent();
1820
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS,
1822
pj_log_pop_indent();
1827
/* Start periodic check for the specified checklist.
1828
* This callback is called by timer on every Ta (20msec by default)
1830
static pj_status_t start_periodic_check(pj_timer_heap_t *th,
1835
pj_ice_sess_checklist *clist;
1836
unsigned i, start_count=0;
1839
td = (struct timer_data*) te->user_data;
1843
pj_mutex_lock(ice->mutex);
1845
/* Set timer ID to FALSE first */
1848
/* Set checklist state to Running */
1849
clist_set_state(ice, clist, PJ_ICE_SESS_CHECKLIST_ST_RUNNING);
1851
LOG5((ice->obj_name, "Starting checklist periodic check"));
1852
pj_log_push_indent();
1854
/* Send STUN Binding request for check with highest priority on
1857
for (i=0; i<clist->count; ++i) {
1858
pj_ice_sess_check *check = &clist->checks[i];
1860
if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
1861
status = perform_check(ice, clist, i, ice->is_nominating);
1862
if (status != PJ_SUCCESS) {
1863
pj_mutex_unlock(ice->mutex);
1864
pj_log_pop_indent();
1873
/* If we don't have anything in Waiting state, perform check to
1874
* highest priority pair that is in Frozen state.
1876
if (start_count==0) {
1877
for (i=0; i<clist->count; ++i) {
1878
pj_ice_sess_check *check = &clist->checks[i];
1880
if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
1881
status = perform_check(ice, clist, i, ice->is_nominating);
1882
if (status != PJ_SUCCESS) {
1883
pj_mutex_unlock(ice->mutex);
1884
pj_log_pop_indent();
1894
/* Cannot start check because there's no suitable candidate pair.
1896
if (start_count!=0) {
1897
/* Schedule for next timer */
1898
pj_time_val timeout = {0, PJ_ICE_TA_VAL};
1901
pj_time_val_normalize(&timeout);
1902
pj_timer_heap_schedule(th, te, &timeout);
1905
pj_mutex_unlock(ice->mutex);
1906
pj_log_pop_indent();
1911
/* Start sending connectivity check with USE-CANDIDATE */
1912
static void start_nominated_check(pj_ice_sess *ice)
1918
LOG4((ice->obj_name, "Starting nominated check.."));
1919
pj_log_push_indent();
1921
pj_assert(ice->is_nominating == PJ_FALSE);
1923
/* Stop our timer if it's active */
1924
if (ice->timer.id == TIMER_START_NOMINATED_CHECK) {
1925
pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
1926
ice->timer.id = TIMER_NONE;
1929
/* For each component, set the check state of valid check with
1930
* highest priority to Waiting (it should have Success state now).
1932
for (i=0; i<ice->comp_cnt; ++i) {
1934
const pj_ice_sess_check *vc = ice->comp[i].valid_check;
1936
pj_assert(ice->comp[i].nominated_check == NULL);
1937
pj_assert(vc->err_code == PJ_SUCCESS);
1939
for (j=0; j<ice->clist.count; ++j) {
1940
pj_ice_sess_check *c = &ice->clist.checks[j];
1941
if (c->lcand->transport_id == vc->lcand->transport_id &&
1942
c->rcand == vc->rcand)
1944
pj_assert(c->err_code == PJ_SUCCESS);
1945
c->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
1946
check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING,
1953
/* And (re)start the periodic check */
1954
if (ice->clist.timer.id) {
1955
pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer);
1956
ice->clist.timer.id = PJ_FALSE;
1959
ice->clist.timer.id = PJ_TRUE;
1960
delay.sec = delay.msec = 0;
1961
status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap,
1962
&ice->clist.timer, &delay);
1963
if (status != PJ_SUCCESS) {
1964
ice->clist.timer.id = PJ_FALSE;
1966
LOG5((ice->obj_name, "Periodic timer rescheduled.."));
1969
ice->is_nominating = PJ_TRUE;
1970
pj_log_pop_indent();
1973
/* Timer callback to perform periodic check */
1974
static void periodic_timer(pj_timer_heap_t *th,
1977
start_periodic_check(th, te);
1981
/* Utility: find string in string array */
1982
const pj_str_t *find_str(const pj_str_t *strlist[], unsigned count,
1983
const pj_str_t *str)
1986
for (i=0; i<count; ++i) {
1987
if (pj_strcmp(strlist[i], str)==0)
1995
* Start ICE periodic check. This function will return immediately, and
1996
* application will be notified about the connectivity check status in
1997
* #pj_ice_sess_cb callback.
1999
PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice)
2001
pj_ice_sess_checklist *clist;
2002
const pj_ice_sess_cand *cand0;
2003
const pj_str_t *flist[PJ_ICE_MAX_CAND]; // XXX
2004
pj_ice_rx_check *rcheck;
2005
unsigned i, flist_cnt = 0;
2009
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
2011
/* Checklist must have been created */
2012
PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
2015
pj_mutex_lock(ice->mutex);
2017
LOG4((ice->obj_name, "Starting ICE check.."));
2018
pj_log_push_indent();
2020
/* If we are using aggressive nomination, set the is_nominating state */
2021
if (ice->opt.aggressive)
2022
ice->is_nominating = PJ_TRUE;
2024
/* The agent examines the check list for the first media stream (a
2025
* media stream is the first media stream when it is described by
2026
* the first m-line in the SDP offer and answer). For that media
2029
* - Groups together all of the pairs with the same foundation,
2031
* - For each group, sets the state of the pair with the lowest
2032
* component ID to Waiting. If there is more than one such pair,
2033
* the one with the highest priority is used.
2036
clist = &ice->clist;
2038
/* Pickup the first pair for component 1. */
2039
for (i=0; i<clist->count; ++i) {
2040
if (clist->checks[i].lcand->comp_id == 1)
2043
if (i == clist->count) {
2044
pj_assert(!"Unable to find checklist for component 1");
2045
pj_mutex_unlock(ice->mutex);
2046
pj_log_pop_indent();
2047
return PJNATH_EICEINCOMPID;
2050
/* Set this check to WAITING only if state is frozen. It may be possible
2051
* that this check has already been started by a trigger check
2053
if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
2054
check_set_state(ice, &clist->checks[i],
2055
PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
2058
cand0 = clist->checks[i].lcand;
2059
flist[flist_cnt++] = &clist->checks[i].lcand->foundation;
2061
/* Find all of the other pairs in that check list with the same
2062
* component ID, but different foundations, and sets all of their
2063
* states to Waiting as well.
2065
for (++i; i<clist->count; ++i) {
2066
const pj_ice_sess_cand *cand1;
2068
cand1 = clist->checks[i].lcand;
2070
if (cand1->comp_id==cand0->comp_id &&
2071
find_str(flist, flist_cnt, &cand1->foundation)==NULL)
2073
if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
2074
check_set_state(ice, &clist->checks[i],
2075
PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
2077
flist[flist_cnt++] = &cand1->foundation;
2081
/* First, perform all pending triggered checks, simultaneously. */
2082
rcheck = ice->early_check.next;
2083
while (rcheck != &ice->early_check) {
2084
LOG4((ice->obj_name,
2085
"Performing delayed triggerred check for component %d",
2087
pj_log_push_indent();
2088
handle_incoming_check(ice, rcheck);
2089
rcheck = rcheck->next;
2090
pj_log_pop_indent();
2092
pj_list_init(&ice->early_check);
2094
/* Start periodic check */
2095
/* We could start it immediately like below, but lets schedule timer
2096
* instead to reduce stack usage:
2097
* return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer);
2099
clist->timer.id = PJ_TRUE;
2100
delay.sec = delay.msec = 0;
2101
status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap,
2102
&clist->timer, &delay);
2103
if (status != PJ_SUCCESS) {
2104
clist->timer.id = PJ_FALSE;
2107
pj_mutex_unlock(ice->mutex);
2108
pj_log_pop_indent();
2113
//////////////////////////////////////////////////////////////////////////////
2115
/* Callback called by STUN session to send the STUN message.
2116
* STUN session also doesn't have a transport, remember?!
2118
static pj_status_t on_stun_send_msg(pj_stun_session *sess,
2122
const pj_sockaddr_t *dst_addr,
2125
stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
2126
pj_ice_sess *ice = sd->ice;
2127
pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
2129
return (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id,
2130
pkt, pkt_size, dst_addr, addr_len);
2134
/* This callback is called when outgoing STUN request completed */
2135
static void on_stun_request_complete(pj_stun_session *stun_sess,
2138
pj_stun_tx_data *tdata,
2139
const pj_stun_msg *response,
2140
const pj_sockaddr_t *src_addr,
2141
unsigned src_addr_len)
2143
pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
2145
pj_ice_sess_check *check, *new_check;
2146
pj_ice_sess_cand *lcand;
2147
pj_ice_sess_checklist *clist;
2148
pj_stun_xor_mapped_addr_attr *xaddr;
2151
PJ_UNUSED_ARG(stun_sess);
2152
PJ_UNUSED_ARG(src_addr_len);
2154
pj_assert(msg_data->has_req_data);
2156
ice = msg_data->data.req.ice;
2157
clist = msg_data->data.req.clist;
2158
check = &clist->checks[msg_data->data.req.ckid];
2161
/* Mark STUN transaction as complete */
2162
pj_assert(tdata == check->tdata);
2163
check->tdata = NULL;
2165
pj_mutex_lock(ice->mutex);
2167
/* Init lcand to NULL. lcand will be found from the mapped address
2168
* found in the response.
2172
if (status != PJ_SUCCESS) {
2173
char errmsg[PJ_ERR_MSG_SIZE];
2175
if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ROLE_CONFLICT)) {
2177
/* Role conclict response.
2179
* 7.1.2.1. Failure Cases:
2181
* If the request had contained the ICE-CONTROLLED attribute,
2182
* the agent MUST switch to the controlling role if it has not
2183
* already done so. If the request had contained the
2184
* ICE-CONTROLLING attribute, the agent MUST switch to the
2185
* controlled role if it has not already done so. Once it has
2186
* switched, the agent MUST immediately retry the request with
2187
* the ICE-CONTROLLING or ICE-CONTROLLED attribute reflecting
2190
pj_ice_sess_role new_role = PJ_ICE_SESS_ROLE_UNKNOWN;
2191
pj_stun_msg *req = tdata->msg;
2193
if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLING, 0)) {
2194
new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
2195
} else if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLED,
2197
new_role = PJ_ICE_SESS_ROLE_CONTROLLING;
2199
pj_assert(!"We should have put CONTROLLING/CONTROLLED attr!");
2200
new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
2203
if (new_role != ice->role) {
2204
LOG4((ice->obj_name,
2205
"Changing role because of role conflict response"));
2206
pj_ice_sess_change_role(ice, new_role);
2209
/* Resend request */
2210
LOG4((ice->obj_name, "Resending check because of role conflict"));
2211
pj_log_push_indent();
2212
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
2213
perform_check(ice, clist, msg_data->data.req.ckid,
2214
check->nominated || ice->is_nominating);
2215
pj_log_pop_indent();
2216
pj_mutex_unlock(ice->mutex);
2220
pj_strerror(status, errmsg, sizeof(errmsg));
2221
LOG4((ice->obj_name,
2222
"Check %s%s: connectivity check FAILED: %s",
2223
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2224
&ice->clist, check),
2225
(check->nominated ? " (nominated)" : " (not nominated)"),
2227
pj_log_push_indent();
2228
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
2229
on_check_complete(ice, check);
2230
pj_log_pop_indent();
2231
pj_mutex_unlock(ice->mutex);
2236
/* 7.1.2.1. Failure Cases
2238
* The agent MUST check that the source IP address and port of the
2239
* response equals the destination IP address and port that the Binding
2240
* Request was sent to, and that the destination IP address and port of
2241
* the response match the source IP address and port that the Binding
2242
* Request was sent from.
2244
if (sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr) != 0) {
2245
status = PJNATH_EICEINSRCADDR;
2246
LOG4((ice->obj_name,
2247
"Check %s%s: connectivity check FAILED: source address mismatch",
2248
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2249
&ice->clist, check),
2250
(check->nominated ? " (nominated)" : " (not nominated)")));
2251
pj_log_push_indent();
2252
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
2253
on_check_complete(ice, check);
2254
pj_log_pop_indent();
2255
pj_mutex_unlock(ice->mutex);
2259
/* 7.1.2.2. Success Cases
2261
* A check is considered to be a success if all of the following are
2264
* o the STUN transaction generated a success response
2266
* o the source IP address and port of the response equals the
2267
* destination IP address and port that the Binding Request was sent
2270
* o the destination IP address and port of the response match the
2271
* source IP address and port that the Binding Request was sent from
2275
LOG4((ice->obj_name,
2276
"Check %s%s: connectivity check SUCCESS",
2277
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2278
&ice->clist, check),
2279
(check->nominated ? " (nominated)" : " (not nominated)")));
2281
/* Get the STUN XOR-MAPPED-ADDRESS attribute. */
2282
xaddr = (pj_stun_xor_mapped_addr_attr*)
2283
pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0);
2285
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
2286
PJNATH_ESTUNNOMAPPEDADDR);
2287
on_check_complete(ice, check);
2288
pj_mutex_unlock(ice->mutex);
2292
/* Find local candidate that matches the XOR-MAPPED-ADDRESS */
2293
pj_assert(lcand == NULL);
2294
for (i=0; i<ice->lcand_cnt; ++i) {
2295
if (sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) {
2297
lcand = &ice->lcand[i];
2302
/* 7.1.2.2.1. Discovering Peer Reflexive Candidates
2303
* If the transport address returned in XOR-MAPPED-ADDRESS does not match
2304
* any of the local candidates that the agent knows about, the mapped
2305
* address represents a new candidate - a peer reflexive candidate.
2307
if (lcand == NULL) {
2309
pj_str_t foundation;
2311
pj_ice_calc_foundation(ice->pool, &foundation, PJ_ICE_CAND_TYPE_PRFLX,
2312
&check->lcand->base_addr);
2314
/* Still in 7.1.2.2.1. Discovering Peer Reflexive Candidates
2315
* Its priority is set equal to the value of the PRIORITY attribute
2316
* in the Binding Request.
2318
* I think the priority calculated by add_cand() should be the same
2319
* as the one calculated in perform_check(), so there's no need to
2320
* get the priority from the PRIORITY attribute.
2323
/* Add new peer reflexive candidate */
2324
status = pj_ice_sess_add_cand(ice, check->lcand->comp_id,
2325
msg_data->transport_id,
2326
PJ_ICE_CAND_TYPE_PRFLX,
2329
&check->lcand->base_addr,
2330
&check->lcand->base_addr,
2331
sizeof(pj_sockaddr_in), &cand_id);
2332
if (status != PJ_SUCCESS) {
2333
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
2335
on_check_complete(ice, check);
2336
pj_mutex_unlock(ice->mutex);
2340
/* Update local candidate */
2341
lcand = &ice->lcand[cand_id];
2345
/* 7.1.2.2.3. Constructing a Valid Pair
2346
* Next, the agent constructs a candidate pair whose local candidate
2347
* equals the mapped address of the response, and whose remote candidate
2348
* equals the destination address to which the request was sent.
2351
/* Add pair to valid list, if it's not there, otherwise just update
2354
for (i=0; i<ice->valid_list.count; ++i) {
2355
if (ice->valid_list.checks[i].lcand == lcand &&
2356
ice->valid_list.checks[i].rcand == check->rcand)
2360
if (i==ice->valid_list.count) {
2361
pj_assert(ice->valid_list.count < PJ_ICE_MAX_CHECKS);
2362
new_check = &ice->valid_list.checks[ice->valid_list.count++];
2363
new_check->lcand = lcand;
2364
new_check->rcand = check->rcand;
2365
new_check->prio = CALC_CHECK_PRIO(ice, lcand, check->rcand);
2366
new_check->state = PJ_ICE_SESS_CHECK_STATE_SUCCEEDED;
2367
new_check->nominated = check->nominated;
2368
new_check->err_code = PJ_SUCCESS;
2370
new_check = &ice->valid_list.checks[i];
2371
ice->valid_list.checks[i].nominated = check->nominated;
2374
/* Update valid check and nominated check for the component */
2375
update_comp_check(ice, new_check->lcand->comp_id, new_check);
2377
/* Sort valid_list (must do so after update_comp_check(), otherwise
2378
* new_check will point to something else (#953)
2380
sort_checklist(ice, &ice->valid_list);
2382
/* 7.1.2.2.2. Updating Pair States
2384
* The agent sets the state of the pair that generated the check to
2385
* Succeeded. The success of this check might also cause the state of
2386
* other checks to change as well.
2388
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_SUCCEEDED,
2391
/* Perform 7.1.2.2.2. Updating Pair States.
2392
* This may terminate ICE processing.
2394
if (on_check_complete(ice, check)) {
2396
pj_mutex_unlock(ice->mutex);
2400
pj_mutex_unlock(ice->mutex);
2404
/* This callback is called by the STUN session associated with a candidate
2405
* when it receives incoming request.
2407
static pj_status_t on_stun_rx_request(pj_stun_session *sess,
2408
const pj_uint8_t *pkt,
2410
const pj_stun_rx_data *rdata,
2412
const pj_sockaddr_t *src_addr,
2413
unsigned src_addr_len)
2416
const pj_stun_msg *msg = rdata->msg;
2417
pj_ice_msg_data *msg_data;
2419
pj_stun_priority_attr *prio_attr;
2420
pj_stun_use_candidate_attr *uc_attr;
2421
pj_stun_uint64_attr *role_attr;
2422
pj_stun_tx_data *tdata;
2423
pj_ice_rx_check *rcheck, tmp_rcheck;
2427
PJ_UNUSED_ARG(pkt_len);
2429
/* Reject any requests except Binding request */
2430
if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
2431
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
2432
NULL, token, PJ_TRUE,
2433
src_addr, src_addr_len);
2438
sd = (stun_data*) pj_stun_session_get_user_data(sess);
2441
pj_mutex_lock(ice->mutex);
2445
* Be aware that when STUN request is received, we might not get
2446
* SDP answer yet, so we might not have remote candidates and
2447
* checklist yet. This case will be handled after we send
2451
/* Get PRIORITY attribute */
2452
prio_attr = (pj_stun_priority_attr*)
2453
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0);
2454
if (prio_attr == NULL) {
2455
LOG5((ice->obj_name, "Received Binding request with no PRIORITY"));
2456
pj_mutex_unlock(ice->mutex);
2460
/* Get USE-CANDIDATE attribute */
2461
uc_attr = (pj_stun_use_candidate_attr*)
2462
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0);
2465
/* Get ICE-CONTROLLING or ICE-CONTROLLED */
2466
role_attr = (pj_stun_uint64_attr*)
2467
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLING, 0);
2468
if (role_attr == NULL) {
2469
role_attr = (pj_stun_uint64_attr*)
2470
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLED, 0);
2473
/* Handle the case when request comes before answer is received.
2474
* We need to put credential in the response, and since we haven't
2475
* got the response, copy the username from the request.
2477
if (ice->rcand_cnt == 0) {
2478
pj_stun_string_attr *uname_attr;
2480
uname_attr = (pj_stun_string_attr*)
2481
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
2482
pj_assert(uname_attr != NULL);
2483
pj_strdup(ice->pool, &ice->rx_uname, &uname_attr->value);
2486
/* 7.2.1.1. Detecting and Repairing Role Conflicts
2488
if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING &&
2489
role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLING)
2491
if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
2492
/* Switch role to controlled */
2493
LOG4((ice->obj_name,
2494
"Changing role because of ICE-CONTROLLING attribute"));
2495
pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLED);
2497
/* Generate 487 response */
2498
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
2499
NULL, token, PJ_TRUE,
2500
src_addr, src_addr_len);
2501
pj_mutex_unlock(ice->mutex);
2505
} else if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED &&
2506
role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLED)
2508
if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
2509
/* Generate 487 response */
2510
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
2511
NULL, token, PJ_TRUE,
2512
src_addr, src_addr_len);
2513
pj_mutex_unlock(ice->mutex);
2516
/* Switch role to controlled */
2517
LOG4((ice->obj_name,
2518
"Changing role because of ICE-CONTROLLED attribute"));
2519
pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLING);
2524
* First send response to this request
2526
status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata);
2527
if (status != PJ_SUCCESS) {
2528
pj_mutex_unlock(ice->mutex);
2532
/* Add XOR-MAPPED-ADDRESS attribute */
2533
status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
2534
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
2535
PJ_TRUE, src_addr, src_addr_len);
2537
/* Create a msg_data to be associated with this response */
2538
msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
2539
msg_data->transport_id = ((pj_ice_msg_data*)token)->transport_id;
2540
msg_data->has_req_data = PJ_FALSE;
2542
/* Send the response */
2543
status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
2544
src_addr, src_addr_len, tdata);
2548
* Handling early check.
2550
* It's possible that we receive this request before we receive SDP
2551
* answer. In this case, we can't perform trigger check since we
2552
* don't have checklist yet, so just save this check in a pending
2553
* triggered check array to be acted upon later.
2555
if (ice->rcand_cnt == 0) {
2556
rcheck = PJ_POOL_ZALLOC_T(ice->pool, pj_ice_rx_check);
2558
rcheck = &tmp_rcheck;
2562
rcheck->comp_id = sd->comp_id;
2563
rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
2564
rcheck->src_addr_len = src_addr_len;
2565
pj_memcpy(&rcheck->src_addr, src_addr, src_addr_len);
2566
rcheck->use_candidate = (uc_attr != NULL);
2567
rcheck->priority = prio_attr->value;
2568
rcheck->role_attr = role_attr;
2570
if (ice->rcand_cnt == 0) {
2571
/* We don't have answer yet, so keep this request for later */
2572
LOG4((ice->obj_name, "Received an early check for comp %d",
2574
pj_list_push_back(&ice->early_check, rcheck);
2576
/* Handle this check */
2577
handle_incoming_check(ice, rcheck);
2580
pj_mutex_unlock(ice->mutex);
2585
/* Handle incoming Binding request and perform triggered check.
2586
* This function may be called by on_stun_rx_request(), or when
2587
* SDP answer is received and we have received early checks.
2589
static void handle_incoming_check(pj_ice_sess *ice,
2590
const pj_ice_rx_check *rcheck)
2592
pj_ice_sess_comp *comp;
2593
pj_ice_sess_cand *lcand = NULL;
2594
pj_ice_sess_cand *rcand;
2597
comp = find_comp(ice, rcheck->comp_id);
2599
/* Find remote candidate based on the source transport address of
2602
for (i=0; i<ice->rcand_cnt; ++i) {
2603
if (sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0)
2607
/* 7.2.1.3. Learning Peer Reflexive Candidates
2608
* If the source transport address of the request does not match any
2609
* existing remote candidates, it represents a new peer reflexive remote
2612
if (i == ice->rcand_cnt) {
2613
if (ice->rcand_cnt >= PJ_ICE_MAX_CAND) {
2614
LOG4((ice->obj_name,
2615
"Unable to add new peer reflexive candidate: too many "
2616
"candidates already (%d)", PJ_ICE_MAX_CAND));
2620
rcand = &ice->rcand[ice->rcand_cnt++];
2621
rcand->comp_id = (pj_uint8_t)rcheck->comp_id;
2622
rcand->type = PJ_ICE_CAND_TYPE_PRFLX;
2623
rcand->prio = rcheck->priority;
2624
pj_memcpy(&rcand->addr, &rcheck->src_addr, rcheck->src_addr_len);
2626
/* Foundation is random, unique from other foundation */
2627
rcand->foundation.ptr = (char*) pj_pool_alloc(ice->pool, 36);
2628
rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 36,
2630
rcand->foundation.ptr);
2632
LOG4((ice->obj_name,
2633
"Added new remote candidate from the request: %s:%d",
2634
pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
2635
(int)pj_ntohs(rcand->addr.ipv4.sin_port)));
2638
/* Remote candidate found */
2639
rcand = &ice->rcand[i];
2643
/* Find again the local candidate by matching the base address
2644
* with the local candidates in the checklist. Checks may have
2645
* been pruned before, so it's possible that if we use the lcand
2646
* as it is, we wouldn't be able to find the check in the checklist
2647
* and we will end up creating a new check unnecessarily.
2649
for (i=0; i<ice->clist.count; ++i) {
2650
pj_ice_sess_check *c = &ice->clist.checks[i];
2651
if (/*c->lcand == lcand ||*/
2652
sockaddr_cmp(&c->lcand->base_addr, &lcand->base_addr)==0)
2659
/* Just get candidate with the highest priority and same transport ID
2660
* for the specified component ID in the checklist.
2662
for (i=0; i<ice->clist.count; ++i) {
2663
pj_ice_sess_check *c = &ice->clist.checks[i];
2664
if (c->lcand->comp_id == rcheck->comp_id &&
2665
c->lcand->transport_id == rcheck->transport_id)
2671
if (lcand == NULL) {
2672
/* Should not happen, but just in case remote is sending a
2673
* Binding request for a component which it doesn't have.
2675
LOG4((ice->obj_name,
2676
"Received Binding request but no local candidate is found!"));
2682
* Create candidate pair for this request.
2686
* 7.2.1.4. Triggered Checks
2688
* Now that we have local and remote candidate, check if we already
2689
* have this pair in our checklist.
2691
for (i=0; i<ice->clist.count; ++i) {
2692
pj_ice_sess_check *c = &ice->clist.checks[i];
2693
if (c->lcand == lcand && c->rcand == rcand)
2697
/* If the pair is already on the check list:
2698
* - If the state of that pair is Waiting or Frozen, its state is
2699
* changed to In-Progress and a check for that pair is performed
2700
* immediately. This is called a triggered check.
2702
* - If the state of that pair is In-Progress, the agent SHOULD
2703
* generate an immediate retransmit of the Binding Request for the
2704
* check in progress. This is to facilitate rapid completion of
2705
* ICE when both agents are behind NAT.
2707
* - If the state of that pair is Failed or Succeeded, no triggered
2710
if (i != ice->clist.count) {
2711
pj_ice_sess_check *c = &ice->clist.checks[i];
2713
/* If USE-CANDIDATE is present, set nominated flag
2714
* Note: DO NOT overwrite nominated flag if one is already set.
2716
c->nominated = ((rcheck->use_candidate) || c->nominated);
2718
if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN ||
2719
c->state == PJ_ICE_SESS_CHECK_STATE_WAITING)
2721
/* See if we shall nominate this check */
2722
pj_bool_t nominate = (c->nominated || ice->is_nominating);
2724
LOG5((ice->obj_name, "Performing triggered check for check %d",i));
2725
pj_log_push_indent();
2726
perform_check(ice, &ice->clist, i, nominate);
2727
pj_log_pop_indent();
2729
} else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
2730
/* Should retransmit immediately
2732
LOG5((ice->obj_name, "Triggered check for check %d not performed "
2733
"because it's in progress. Retransmitting", i));
2734
pj_log_push_indent();
2735
pj_stun_session_retransmit_req(comp->stun_sess, c->tdata);
2736
pj_log_pop_indent();
2738
} else if (c->state == PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
2739
/* Check complete for this component.
2740
* Note this may end ICE process.
2745
/* If this check is nominated, scan the valid_list for the
2746
* same check and update the nominated flag. A controlled
2747
* agent might have finished the check earlier.
2749
if (rcheck->use_candidate) {
2750
for (j=0; j<ice->valid_list.count; ++j) {
2751
pj_ice_sess_check *vc = &ice->valid_list.checks[j];
2752
if (vc->lcand->transport_id == c->lcand->transport_id &&
2753
vc->rcand == c->rcand)
2755
/* Set nominated flag */
2756
vc->nominated = PJ_TRUE;
2758
/* Update valid check and nominated check for the component */
2759
update_comp_check(ice, vc->lcand->comp_id, vc);
2761
LOG5((ice->obj_name, "Valid check %s is nominated",
2762
dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2763
&ice->valid_list, vc)));
2768
LOG5((ice->obj_name, "Triggered check for check %d not performed "
2769
"because it's completed", i));
2770
pj_log_push_indent();
2771
complete = on_check_complete(ice, c);
2772
pj_log_pop_indent();
2779
/* If the pair is not already on the check list:
2780
* - The pair is inserted into the check list based on its priority.
2781
* - Its state is set to In-Progress
2782
* - A triggered check for that pair is performed immediately.
2784
/* Note: only do this if we don't have too many checks in checklist */
2785
else if (ice->clist.count < PJ_ICE_MAX_CHECKS) {
2787
pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count];
2792
c->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
2793
c->state = PJ_ICE_SESS_CHECK_STATE_WAITING;
2794
c->nominated = rcheck->use_candidate;
2795
c->err_code = PJ_SUCCESS;
2797
nominate = (c->nominated || ice->is_nominating);
2799
LOG4((ice->obj_name, "New triggered check added: %d",
2801
pj_log_push_indent();
2802
perform_check(ice, &ice->clist, ice->clist.count++, nominate);
2803
pj_log_pop_indent();
2806
LOG4((ice->obj_name, "Error: unable to perform triggered check: "
2807
"TOO MANY CHECKS IN CHECKLIST!"));
2812
static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
2813
const pj_uint8_t *pkt,
2815
const pj_stun_msg *msg,
2817
const pj_sockaddr_t *src_addr,
2818
unsigned src_addr_len)
2820
struct stun_data *sd;
2822
PJ_UNUSED_ARG(sess);
2824
PJ_UNUSED_ARG(pkt_len);
2826
PJ_UNUSED_ARG(token);
2827
PJ_UNUSED_ARG(src_addr);
2828
PJ_UNUSED_ARG(src_addr_len);
2830
sd = (struct stun_data*) pj_stun_session_get_user_data(sess);
2832
pj_log_push_indent();
2834
if (msg->hdr.type == PJ_STUN_BINDING_INDICATION) {
2835
LOG5((sd->ice->obj_name, "Received Binding Indication keep-alive "
2836
"for component %d", sd->comp_id));
2838
LOG4((sd->ice->obj_name, "Received unexpected %s indication "
2839
"for component %d", pj_stun_get_method_name(msg->hdr.type),
2843
pj_log_pop_indent();
2849
PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
2854
pj_status_t status = PJ_SUCCESS;
2855
pj_ice_sess_comp *comp;
2856
pj_ice_sess_cand *cand;
2857
pj_uint8_t transport_id;
2860
PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
2862
/* It is possible that comp_cnt is less than comp_id, when remote
2863
* doesn't support all the components that we have.
2865
if (comp_id > ice->comp_cnt) {
2866
return PJNATH_EICEINCOMPID;
2869
pj_mutex_lock(ice->mutex);
2871
comp = find_comp(ice, comp_id);
2873
status = PJNATH_EICEINCOMPID;
2874
pj_mutex_unlock(ice->mutex);
2878
if (comp->valid_check == NULL) {
2879
status = PJNATH_EICEINPROGRESS;
2880
pj_mutex_unlock(ice->mutex);
2884
cand = comp->valid_check->lcand;
2885
transport_id = cand->transport_id;
2886
pj_sockaddr_cp(&addr, &comp->valid_check->rcand->addr);
2888
/* Release the mutex now to avoid deadlock (see ticket #1451). */
2889
pj_mutex_unlock(ice->mutex);
2891
status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id,
2894
sizeof(pj_sockaddr_in));
2901
PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
2903
unsigned transport_id,
2906
const pj_sockaddr_t *src_addr,
2909
pj_status_t status = PJ_SUCCESS;
2910
pj_ice_sess_comp *comp;
2911
pj_ice_msg_data *msg_data = NULL;
2914
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
2916
pj_mutex_lock(ice->mutex);
2918
comp = find_comp(ice, comp_id);
2920
pj_mutex_unlock(ice->mutex);
2921
return PJNATH_EICEINCOMPID;
2924
/* Find transport */
2925
for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
2926
if (ice->tp_data[i].transport_id == transport_id) {
2927
msg_data = &ice->tp_data[i];
2931
if (msg_data == NULL) {
2932
pj_assert(!"Invalid transport ID");
2933
pj_mutex_unlock(ice->mutex);
2937
/* Don't check fingerprint. We only need to distinguish STUN and non-STUN
2938
* packets. We don't need to verify the STUN packet too rigorously, that
2939
* will be done by the user.
2941
status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size,
2942
PJ_STUN_IS_DATAGRAM |
2943
PJ_STUN_NO_FINGERPRINT_CHECK);
2944
if (status == PJ_SUCCESS) {
2945
status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
2946
PJ_STUN_IS_DATAGRAM, msg_data,
2947
NULL, src_addr, src_addr_len);
2948
if (status != PJ_SUCCESS) {
2949
pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg));
2950
LOG4((ice->obj_name, "Error processing incoming message: %s",
2953
pj_mutex_unlock(ice->mutex);
2955
/* Not a STUN packet. Call application's callback instead, but release
2956
* the mutex now or otherwise we may get deadlock.
2958
pj_mutex_unlock(ice->mutex);
2960
(*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size,
2961
src_addr, src_addr_len);
2962
status = PJ_SUCCESS;