blob: 6eca28530fe69fa41f83697a0a10ce703bfe6d31 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjnath/ice_session.h>
21#include <pj/addr_resolv.h>
22#include <pj/array.h>
23#include <pj/assert.h>
24#include <pj/guid.h>
25#include <pj/hash.h>
26#include <pj/log.h>
27#include <pj/os.h>
28#include <pj/pool.h>
29#include <pj/rand.h>
30#include <pj/string.h>
31
32/* String names for candidate types */
33static const char *cand_type_names[] =
34{
35 "host",
36 "srflx",
37 "prflx",
38 "relay"
39
40};
41
42/* String names for pj_ice_sess_check_state */
43#if PJ_LOG_MAX_LEVEL >= 4
44static const char *check_state_name[] =
45{
46 "Frozen",
47 "Waiting",
48 "In Progress",
49 "Succeeded",
50 "Failed"
51};
52
53static const char *clist_state_name[] =
54{
55 "Idle",
56 "Running",
57 "Completed"
58};
59#endif /* PJ_LOG_MAX_LEVEL >= 4 */
60
61static const char *role_names[] =
62{
63 "Unknown",
64 "Controlled",
65 "Controlling"
66};
67
68enum timer_type
69{
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. */
79
80};
81
82/* Candidate type preference */
83static pj_uint8_t cand_type_prefs[4] =
84{
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 */
91#else
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 */
97#endif
98};
99
100#define THIS_FILE "ice_session.c"
101#define CHECK_NAME_LEN 128
102#define LOG4(expr) PJ_LOG(4,expr)
103#define LOG5(expr) PJ_LOG(4,expr)
104#define GET_LCAND_ID(cand) (unsigned)(cand - ice->lcand)
105#define GET_CHECK_ID(cl, chk) (chk - (cl)->checks)
106
107
108/* The data that will be attached to the STUN session on each
109 * component.
110 */
111typedef struct stun_data
112{
113 pj_ice_sess *ice;
114 unsigned comp_id;
115 pj_ice_sess_comp *comp;
116} stun_data;
117
118
119/* The data that will be attached to the timer to perform
120 * periodic check.
121 */
122typedef struct timer_data
123{
124 pj_ice_sess *ice;
125 pj_ice_sess_checklist *clist;
126} timer_data;
127
128
129/* This is the data that will be attached as token to outgoing
130 * STUN messages.
131 */
132
133
134/* Forward declarations */
135static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te);
136static void on_ice_complete(pj_ice_sess *ice, pj_status_t status);
137static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now);
138static void ice_on_destroy(void *obj);
139static void destroy_ice(pj_ice_sess *ice,
140 pj_status_t reason);
141static pj_status_t start_periodic_check(pj_timer_heap_t *th,
142 pj_timer_entry *te);
143static void start_nominated_check(pj_ice_sess *ice);
144static void periodic_timer(pj_timer_heap_t *th,
145 pj_timer_entry *te);
146static void handle_incoming_check(pj_ice_sess *ice,
147 const pj_ice_rx_check *rcheck);
148
149/* These are the callbacks registered to the STUN sessions */
150static pj_status_t on_stun_send_msg(pj_stun_session *sess,
151 void *token,
152 const void *pkt,
153 pj_size_t pkt_size,
154 const pj_sockaddr_t *dst_addr,
155 unsigned addr_len);
156static pj_status_t on_stun_rx_request(pj_stun_session *sess,
157 const pj_uint8_t *pkt,
158 unsigned pkt_len,
159 const pj_stun_rx_data *rdata,
160 void *token,
161 const pj_sockaddr_t *src_addr,
162 unsigned src_addr_len);
163static void on_stun_request_complete(pj_stun_session *stun_sess,
164 pj_status_t status,
165 void *token,
166 pj_stun_tx_data *tdata,
167 const pj_stun_msg *response,
168 const pj_sockaddr_t *src_addr,
169 unsigned src_addr_len);
170static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
171 const pj_uint8_t *pkt,
172 unsigned pkt_len,
173 const pj_stun_msg *msg,
174 void *token,
175 const pj_sockaddr_t *src_addr,
176 unsigned src_addr_len);
177
178/* These are the callbacks for performing STUN authentication */
179static pj_status_t stun_auth_get_auth(void *user_data,
180 pj_pool_t *pool,
181 pj_str_t *realm,
182 pj_str_t *nonce);
183static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg,
184 void *user_data,
185 pj_pool_t *pool,
186 pj_str_t *realm,
187 pj_str_t *username,
188 pj_str_t *nonce,
189 pj_stun_passwd_type *data_type,
190 pj_str_t *data);
191static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
192 void *user_data,
193 const pj_str_t *realm,
194 const pj_str_t *username,
195 pj_pool_t *pool,
196 pj_stun_passwd_type *data_type,
197 pj_str_t *data);
198
199
200PJ_DEF(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type)
201{
202 PJ_ASSERT_RETURN(type <= PJ_ICE_CAND_TYPE_RELAYED, "???");
203 return cand_type_names[type];
204}
205
206
207PJ_DEF(const char*) pj_ice_sess_role_name(pj_ice_sess_role role)
208{
209 switch (role) {
210 case PJ_ICE_SESS_ROLE_UNKNOWN:
211 return "Unknown";
212 case PJ_ICE_SESS_ROLE_CONTROLLED:
213 return "Controlled";
214 case PJ_ICE_SESS_ROLE_CONTROLLING:
215 return "Controlling";
216 default:
217 return "??";
218 }
219}
220
221
222/* Get the prefix for the foundation */
223static int get_type_prefix(pj_ice_cand_type type)
224{
225 switch (type) {
226 case PJ_ICE_CAND_TYPE_HOST: return 'H';
227 case PJ_ICE_CAND_TYPE_SRFLX: return 'S';
228 case PJ_ICE_CAND_TYPE_PRFLX: return 'P';
229 case PJ_ICE_CAND_TYPE_RELAYED: return 'R';
230 default:
231 pj_assert(!"Invalid type");
232 return 'U';
233 }
234}
235
236/* Calculate foundation:
237 * Two candidates have the same foundation when they are "similar" - of
238 * the same type and obtained from the same host candidate and STUN
239 * server using the same protocol. Otherwise, their foundation is
240 * different.
241 */
242PJ_DEF(void) pj_ice_calc_foundation(pj_pool_t *pool,
243 pj_str_t *foundation,
244 pj_ice_cand_type type,
245 const pj_sockaddr *base_addr)
246{
247#if PJNATH_ICE_PRIO_STD
248 char buf[64];
249 pj_uint32_t val;
250
251 if (base_addr->addr.sa_family == pj_AF_INET()) {
252 val = pj_ntohl(base_addr->ipv4.sin_addr.s_addr);
253 } else {
254 val = pj_hash_calc(0, pj_sockaddr_get_addr(base_addr),
255 pj_sockaddr_get_addr_len(base_addr));
256 }
257 pj_ansi_snprintf(buf, sizeof(buf), "%c%x",
258 get_type_prefix(type), val);
259 pj_strdup2(pool, foundation, buf);
260#else
261 /* Much shorter version, valid for candidates added by
262 * pj_ice_strans.
263 */
264 foundation->ptr = (char*) pj_pool_alloc(pool, 1);
265 *foundation->ptr = (char)get_type_prefix(type);
266 foundation->slen = 1;
267
268 PJ_UNUSED_ARG(base_addr);
269#endif
270}
271
272
273/* Init component */
274static pj_status_t init_comp(pj_ice_sess *ice,
275 unsigned comp_id,
276 pj_ice_sess_comp *comp)
277{
278 pj_stun_session_cb sess_cb;
279 pj_stun_auth_cred auth_cred;
280 stun_data *sd;
281 pj_status_t status;
282
283 /* Init STUN callbacks */
284 pj_bzero(&sess_cb, sizeof(sess_cb));
285 sess_cb.on_request_complete = &on_stun_request_complete;
286 sess_cb.on_rx_indication = &on_stun_rx_indication;
287 sess_cb.on_rx_request = &on_stun_rx_request;
288 sess_cb.on_send_msg = &on_stun_send_msg;
289
290 /* Create STUN session for this candidate */
291 status = pj_stun_session_create(&ice->stun_cfg, NULL,
292 &sess_cb, PJ_TRUE,
293 ice->grp_lock,
294 &comp->stun_sess);
295 if (status != PJ_SUCCESS)
296 return status;
297
298 /* Associate data with this STUN session */
299 sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data);
300 sd->ice = ice;
301 sd->comp_id = comp_id;
302 sd->comp = comp;
303 pj_stun_session_set_user_data(comp->stun_sess, sd);
304
305 /* Init STUN authentication credential */
306 pj_bzero(&auth_cred, sizeof(auth_cred));
307 auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
308 auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth;
309 auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred;
310 auth_cred.data.dyn_cred.get_password = &stun_auth_get_password;
311 auth_cred.data.dyn_cred.user_data = comp->stun_sess;
312 pj_stun_session_set_credential(comp->stun_sess, PJ_STUN_AUTH_SHORT_TERM,
313 &auth_cred);
314
315 return PJ_SUCCESS;
316}
317
318
319/* Init options with default values */
320PJ_DEF(void) pj_ice_sess_options_default(pj_ice_sess_options *opt)
321{
322 opt->aggressive = PJ_TRUE;
323 opt->nominated_check_delay = PJ_ICE_NOMINATED_CHECK_DELAY;
324 opt->controlled_agent_want_nom_timeout =
325 ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT;
326}
327
328/*
329 * Create ICE session.
330 */
331PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
332 const char *name,
333 pj_ice_sess_role role,
334 unsigned comp_cnt,
335 const pj_ice_sess_cb *cb,
336 const pj_str_t *local_ufrag,
337 const pj_str_t *local_passwd,
338 pj_grp_lock_t *grp_lock,
339 pj_ice_sess **p_ice)
340{
341 pj_pool_t *pool;
342 pj_ice_sess *ice;
343 unsigned i;
344 pj_status_t status;
345
346 PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
347
348 if (name == NULL)
349 name = "icess%p";
350
351 pool = pj_pool_create(stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_SESS,
352 PJNATH_POOL_INC_ICE_SESS, NULL);
353 ice = PJ_POOL_ZALLOC_T(pool, pj_ice_sess);
354 ice->pool = pool;
355 ice->role = role;
356 ice->tie_breaker.u32.hi = pj_rand();
357 ice->tie_breaker.u32.lo = pj_rand();
358 ice->prefs = cand_type_prefs;
359 pj_ice_sess_options_default(&ice->opt);
360
361 pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer);
362
363 pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
364 name, ice);
365
366 if (grp_lock) {
367 ice->grp_lock = grp_lock;
368 } else {
369 status = pj_grp_lock_create(pool, NULL, &ice->grp_lock);
370 if (status != PJ_SUCCESS) {
371 pj_pool_release(pool);
372 return status;
373 }
374 }
375
376 pj_grp_lock_add_ref(ice->grp_lock);
377 pj_grp_lock_add_handler(ice->grp_lock, pool, ice,
378 &ice_on_destroy);
379
380 pj_memcpy(&ice->cb, cb, sizeof(*cb));
381 pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg));
382
383 ice->comp_cnt = comp_cnt;
384 for (i=0; i<comp_cnt; ++i) {
385 pj_ice_sess_comp *comp;
386 comp = &ice->comp[i];
387 comp->valid_check = NULL;
388 comp->nominated_check = NULL;
389
390 status = init_comp(ice, i+1, comp);
391 if (status != PJ_SUCCESS) {
392 destroy_ice(ice, status);
393 return status;
394 }
395 }
396
397 /* Initialize transport datas */
398 for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
399 ice->tp_data[i].transport_id = i;
400 ice->tp_data[i].has_req_data = PJ_FALSE;
401 }
402
403 if (local_ufrag == NULL) {
404 ice->rx_ufrag.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
405 pj_create_random_string(ice->rx_ufrag.ptr, PJ_ICE_UFRAG_LEN);
406 ice->rx_ufrag.slen = PJ_ICE_UFRAG_LEN;
407 } else {
408 pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
409 }
410
411 if (local_passwd == NULL) {
412 ice->rx_pass.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
413 pj_create_random_string(ice->rx_pass.ptr, PJ_ICE_UFRAG_LEN);
414 ice->rx_pass.slen = PJ_ICE_UFRAG_LEN;
415 } else {
416 pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
417 }
418
419 pj_list_init(&ice->early_check);
420
421 /* Done */
422 *p_ice = ice;
423
424 LOG4((ice->obj_name,
425 "ICE session created, comp_cnt=%d, role is %s agent",
426 comp_cnt, role_names[ice->role]));
427
428 return PJ_SUCCESS;
429}
430
431
432/*
433 * Get the value of various options of the ICE session.
434 */
435PJ_DEF(pj_status_t) pj_ice_sess_get_options(pj_ice_sess *ice,
436 pj_ice_sess_options *opt)
437{
438 PJ_ASSERT_RETURN(ice, PJ_EINVAL);
439 pj_memcpy(opt, &ice->opt, sizeof(*opt));
440 return PJ_SUCCESS;
441}
442
443/*
444 * Specify various options for this ICE session.
445 */
446PJ_DEF(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice,
447 const pj_ice_sess_options *opt)
448{
449 PJ_ASSERT_RETURN(ice && opt, PJ_EINVAL);
450 pj_memcpy(&ice->opt, opt, sizeof(*opt));
451 LOG5((ice->obj_name, "ICE nomination type set to %s",
452 (ice->opt.aggressive ? "aggressive" : "regular")));
453 return PJ_SUCCESS;
454}
455
456
457/*
458 * Callback to really destroy the session
459 */
460static void ice_on_destroy(void *obj)
461{
462 pj_ice_sess *ice = (pj_ice_sess*) obj;
463
464 if (ice->pool) {
465 pj_pool_t *pool = ice->pool;
466 ice->pool = NULL;
467 pj_pool_release(pool);
468 }
469 LOG4((THIS_FILE, "ICE session %p destroyed", ice));
470}
471
472/*
473 * Destroy
474 */
475static void destroy_ice(pj_ice_sess *ice,
476 pj_status_t reason)
477{
478 unsigned i;
479
480 if (reason == PJ_SUCCESS) {
481 LOG4((ice->obj_name, "Destroying ICE session %p", ice));
482 }
483
484 pj_grp_lock_acquire(ice->grp_lock);
485
486 if (ice->is_destroying) {
487 pj_grp_lock_release(ice->grp_lock);
488 return;
489 }
490
491 ice->is_destroying = PJ_TRUE;
492
493 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,
494 &ice->timer, PJ_FALSE);
495
496 for (i=0; i<ice->comp_cnt; ++i) {
497 if (ice->comp[i].stun_sess) {
498 pj_stun_session_destroy(ice->comp[i].stun_sess);
499 ice->comp[i].stun_sess = NULL;
500 }
501 }
502
503 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,
504 &ice->clist.timer,
505 PJ_FALSE);
506
507 pj_grp_lock_dec_ref(ice->grp_lock);
508 pj_grp_lock_release(ice->grp_lock);
509}
510
511
512/*
513 * Destroy
514 */
515PJ_DEF(pj_status_t) pj_ice_sess_destroy(pj_ice_sess *ice)
516{
517 PJ_ASSERT_RETURN(ice, PJ_EINVAL);
518 destroy_ice(ice, PJ_SUCCESS);
519 return PJ_SUCCESS;
520}
521
522
523/*
524 * Change session role.
525 */
526PJ_DEF(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
527 pj_ice_sess_role new_role)
528{
529 PJ_ASSERT_RETURN(ice, PJ_EINVAL);
530
531 if (new_role != ice->role) {
532 ice->role = new_role;
533 LOG4((ice->obj_name, "Role changed to %s", role_names[new_role]));
534 }
535
536 return PJ_SUCCESS;
537}
538
539
540/*
541 * Change type preference
542 */
543PJ_DEF(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
544 const pj_uint8_t prefs[4])
545{
546 unsigned i;
547 PJ_ASSERT_RETURN(ice && prefs, PJ_EINVAL);
548 ice->prefs = (pj_uint8_t*) pj_pool_calloc(ice->pool, PJ_ARRAY_SIZE(prefs),
549 sizeof(pj_uint8_t));
550 for (i=0; i<4; ++i) {
551#if PJ_ICE_CAND_TYPE_PREF_BITS < 8
552 pj_assert(prefs[i] < (2 << PJ_ICE_CAND_TYPE_PREF_BITS));
553#endif
554 ice->prefs[i] = prefs[i];
555 }
556 return PJ_SUCCESS;
557}
558
559
560/* Find component by ID */
561static pj_ice_sess_comp *find_comp(const pj_ice_sess *ice, unsigned comp_id)
562{
563 pj_assert(comp_id > 0 && comp_id <= ice->comp_cnt);
564 return (pj_ice_sess_comp*) &ice->comp[comp_id-1];
565}
566
567
568/* Callback by STUN authentication when it needs to send 401 */
569static pj_status_t stun_auth_get_auth(void *user_data,
570 pj_pool_t *pool,
571 pj_str_t *realm,
572 pj_str_t *nonce)
573{
574 PJ_UNUSED_ARG(user_data);
575 PJ_UNUSED_ARG(pool);
576
577 realm->slen = 0;
578 nonce->slen = 0;
579
580 return PJ_SUCCESS;
581}
582
583
584/* Get credential to be sent with outgoing message */
585static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg,
586 void *user_data,
587 pj_pool_t *pool,
588 pj_str_t *realm,
589 pj_str_t *username,
590 pj_str_t *nonce,
591 pj_stun_passwd_type *data_type,
592 pj_str_t *data)
593{
594 pj_stun_session *sess = (pj_stun_session *)user_data;
595 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
596 pj_ice_sess *ice = sd->ice;
597
598 PJ_UNUSED_ARG(pool);
599 realm->slen = nonce->slen = 0;
600
601 if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
602 /* Outgoing responses need to have the same credential as
603 * incoming requests.
604 */
605 *username = ice->rx_uname;
606 *data_type = PJ_STUN_PASSWD_PLAIN;
607 *data = ice->rx_pass;
608 }
609 else {
610 *username = ice->tx_uname;
611 *data_type = PJ_STUN_PASSWD_PLAIN;
612 *data = ice->tx_pass;
613 }
614
615 return PJ_SUCCESS;
616}
617
618/* Get password to be used to authenticate incoming message */
619static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
620 void *user_data,
621 const pj_str_t *realm,
622 const pj_str_t *username,
623 pj_pool_t *pool,
624 pj_stun_passwd_type *data_type,
625 pj_str_t *data)
626{
627 pj_stun_session *sess = (pj_stun_session *)user_data;
628 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
629 pj_ice_sess *ice = sd->ice;
630
631 PJ_UNUSED_ARG(realm);
632 PJ_UNUSED_ARG(pool);
633
634 if (PJ_STUN_IS_SUCCESS_RESPONSE(msg->hdr.type) ||
635 PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
636 {
637 /* Incoming response is authenticated with TX credential */
638 /* Verify username */
639 if (pj_strcmp(username, &ice->tx_uname) != 0)
640 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
641 *data_type = PJ_STUN_PASSWD_PLAIN;
642 *data = ice->tx_pass;
643
644 } else {
645 /* Incoming request is authenticated with RX credential */
646 /* The agent MUST accept a credential if the username consists
647 * of two values separated by a colon, where the first value is
648 * equal to the username fragment generated by the agent in an offer
649 * or answer for a session in-progress, and the MESSAGE-INTEGRITY
650 * is the output of a hash of the password and the STUN packet's
651 * contents.
652 */
653 const char *pos;
654 pj_str_t ufrag;
655
656 pos = (const char*)pj_memchr(username->ptr, ':', username->slen);
657 if (pos == NULL)
658 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
659
660 ufrag.ptr = (char*)username->ptr;
661 ufrag.slen = (pos - username->ptr);
662
663 if (pj_strcmp(&ufrag, &ice->rx_ufrag) != 0)
664 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
665
666 *data_type = PJ_STUN_PASSWD_PLAIN;
667 *data = ice->rx_pass;
668
669 }
670
671 return PJ_SUCCESS;
672}
673
674
675static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice,
676 pj_ice_cand_type type,
677 pj_uint32_t local_pref,
678 pj_uint32_t comp_id)
679{
680#if PJNATH_ICE_PRIO_STD
681 return ((ice->prefs[type] & 0xFF) << 24) +
682 ((local_pref & 0xFFFF) << 8) +
683 (((256 - comp_id) & 0xFF) << 0);
684#else
685 enum {
686 type_mask = ((2 << PJ_ICE_CAND_TYPE_PREF_BITS) - 1),
687 local_mask = ((2 << PJ_ICE_LOCAL_PREF_BITS) - 1),
688 comp_mask = ((2 << PJ_ICE_COMP_BITS) - 1),
689
690 comp_shift = 0,
691 local_shift = (PJ_ICE_COMP_BITS),
692 type_shift = (comp_shift + local_shift),
693
694 max_comp = (2<<PJ_ICE_COMP_BITS),
695 };
696
697 return ((ice->prefs[type] & type_mask) << type_shift) +
698 ((local_pref & local_mask) << local_shift) +
699 (((max_comp - comp_id) & comp_mask) << comp_shift);
700#endif
701}
702
703
704/*
705 * Add ICE candidate
706 */
707PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
708 unsigned comp_id,
709 unsigned transport_id,
710 pj_ice_cand_type type,
711 pj_uint16_t local_pref,
712 const pj_str_t *foundation,
713 const pj_sockaddr_t *addr,
714 const pj_sockaddr_t *base_addr,
715 const pj_sockaddr_t *rel_addr,
716 int addr_len,
717 unsigned *p_cand_id)
718{
719 pj_ice_sess_cand *lcand;
720 pj_status_t status = PJ_SUCCESS;
721 char address[PJ_INET6_ADDRSTRLEN];
722
723 PJ_ASSERT_RETURN(ice && comp_id &&
724 foundation && addr && base_addr && addr_len,
725 PJ_EINVAL);
726 PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
727
728 pj_grp_lock_acquire(ice->grp_lock);
729
730 if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) {
731 status = PJ_ETOOMANY;
732 goto on_error;
733 }
734
735 lcand = &ice->lcand[ice->lcand_cnt];
736 lcand->comp_id = (pj_uint8_t)comp_id;
737 lcand->transport_id = (pj_uint8_t)transport_id;
738 lcand->type = type;
739 pj_strdup(ice->pool, &lcand->foundation, foundation);
740 lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
741 pj_sockaddr_cp(&lcand->addr, addr);
742 pj_sockaddr_cp(&lcand->base_addr, base_addr);
743 if (rel_addr == NULL)
744 rel_addr = base_addr;
745 pj_memcpy(&lcand->rel_addr, rel_addr, addr_len);
746
747 pj_ansi_strcpy(ice->tmp.txt, pj_sockaddr_print(&lcand->addr, address,
748 sizeof(address), 0));
749 LOG4((ice->obj_name,
750 "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, "
751 "addr=%s:%d, base=%s:%d, prio=0x%x (%u)",
752 ice->lcand_cnt,
753 lcand->comp_id,
754 cand_type_names[lcand->type],
755 (int)lcand->foundation.slen,
756 lcand->foundation.ptr,
757 ice->tmp.txt,
758 pj_sockaddr_get_port(&lcand->addr),
759 pj_sockaddr_print(&lcand->base_addr, address, sizeof(address), 0),
760 pj_sockaddr_get_port(&lcand->base_addr),
761 lcand->prio, lcand->prio));
762
763 if (p_cand_id)
764 *p_cand_id = ice->lcand_cnt;
765
766 ++ice->lcand_cnt;
767
768on_error:
769 pj_grp_lock_release(ice->grp_lock);
770 return status;
771}
772
773
774/* Find default candidate ID for the component */
775PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
776 unsigned comp_id,
777 int *cand_id)
778{
779 unsigned i;
780
781 PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL);
782 PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
783
784 *cand_id = -1;
785
786 pj_grp_lock_acquire(ice->grp_lock);
787
788 /* First find in valid list if we have nominated pair */
789 for (i=0; i<ice->valid_list.count; ++i) {
790 pj_ice_sess_check *check = &ice->valid_list.checks[i];
791
792 if (check->lcand->comp_id == comp_id) {
793 *cand_id = GET_LCAND_ID(check->lcand);
794 pj_grp_lock_release(ice->grp_lock);
795 return PJ_SUCCESS;
796 }
797 }
798
799 /* If there's no nominated pair, find relayed candidate */
800 for (i=0; i<ice->lcand_cnt; ++i) {
801 pj_ice_sess_cand *lcand = &ice->lcand[i];
802 if (lcand->comp_id==comp_id &&
803 lcand->type == PJ_ICE_CAND_TYPE_RELAYED)
804 {
805 *cand_id = GET_LCAND_ID(lcand);
806 pj_grp_lock_release(ice->grp_lock);
807 return PJ_SUCCESS;
808 }
809 }
810
811 /* If there's no relayed candidate, find reflexive candidate */
812 for (i=0; i<ice->lcand_cnt; ++i) {
813 pj_ice_sess_cand *lcand = &ice->lcand[i];
814 if (lcand->comp_id==comp_id &&
815 (lcand->type == PJ_ICE_CAND_TYPE_SRFLX ||
816 lcand->type == PJ_ICE_CAND_TYPE_PRFLX))
817 {
818 *cand_id = GET_LCAND_ID(lcand);
819 pj_grp_lock_release(ice->grp_lock);
820 return PJ_SUCCESS;
821 }
822 }
823
824 /* Otherwise return host candidate */
825 for (i=0; i<ice->lcand_cnt; ++i) {
826 pj_ice_sess_cand *lcand = &ice->lcand[i];
827 if (lcand->comp_id==comp_id &&
828 lcand->type == PJ_ICE_CAND_TYPE_HOST)
829 {
830 *cand_id = GET_LCAND_ID(lcand);
831 pj_grp_lock_release(ice->grp_lock);
832 return PJ_SUCCESS;
833 }
834 }
835
836 /* Still no candidate is found! :( */
837 pj_grp_lock_release(ice->grp_lock);
838
839 pj_assert(!"Should have a candidate by now");
840 return PJ_EBUG;
841}
842
843
844#ifndef MIN
845# define MIN(a,b) (a < b ? a : b)
846#endif
847
848#ifndef MAX
849# define MAX(a,b) (a > b ? a : b)
850#endif
851
852static pj_timestamp CALC_CHECK_PRIO(const pj_ice_sess *ice,
853 const pj_ice_sess_cand *lcand,
854 const pj_ice_sess_cand *rcand)
855{
856 pj_uint32_t O, A;
857 pj_timestamp prio;
858
859 /* Original formula:
860 * pair priority = 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0)
861 */
862
863 if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
864 O = lcand->prio;
865 A = rcand->prio;
866 } else {
867 O = rcand->prio;
868 A = lcand->prio;
869 }
870
871 /*
872 return ((pj_uint64_t)1 << 32) * MIN(O, A) +
873 (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0);
874 */
875
876 prio.u32.hi = MIN(O,A);
877 prio.u32.lo = (MAX(O, A) << 1) + (O>A ? 1 : 0);
878
879 return prio;
880}
881
882
883PJ_INLINE(int) CMP_CHECK_PRIO(const pj_ice_sess_check *c1,
884 const pj_ice_sess_check *c2)
885{
886 return pj_cmp_timestamp(&c1->prio, &c2->prio);
887}
888
889
890#if PJ_LOG_MAX_LEVEL >= 4
891static const char *dump_check(char *buffer, unsigned bufsize,
892 const pj_ice_sess_checklist *clist,
893 const pj_ice_sess_check *check)
894{
895 const pj_ice_sess_cand *lcand = check->lcand;
896 const pj_ice_sess_cand *rcand = check->rcand;
897 char laddr[PJ_INET6_ADDRSTRLEN], raddr[PJ_INET6_ADDRSTRLEN];
898 int len;
899
900 PJ_CHECK_STACK();
901
902 pj_ansi_strcpy(laddr, pj_sockaddr_print(&lcand->addr, laddr,
903 sizeof(laddr), 0));
904
905 len = pj_ansi_snprintf(buffer, bufsize,
906 "%d: [%d] %s:%d-->%s:%d",
907 (int)GET_CHECK_ID(clist, check),
908 check->lcand->comp_id,
909 pj_sockaddr_print(&lcand->addr, laddr,
910 sizeof(laddr), 0),
911 pj_sockaddr_get_port(&lcand->addr),
912 pj_sockaddr_print(&rcand->addr, raddr,
913 sizeof(raddr), 0),
914 pj_sockaddr_get_port(&rcand->addr));
915
916 if (len < 0)
917 len = 0;
918 else if (len >= (int)bufsize)
919 len = bufsize - 1;
920
921 buffer[len] = '\0';
922 return buffer;
923}
924
925static void dump_checklist(const char *title, pj_ice_sess *ice,
926 const pj_ice_sess_checklist *clist)
927{
928 unsigned i;
929
930 LOG4((ice->obj_name, "%s", title));
931 for (i=0; i<clist->count; ++i) {
932 const pj_ice_sess_check *c = &clist->checks[i];
933 LOG4((ice->obj_name, " %s (%s, state=%s)",
934 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, c),
935 (c->nominated ? "nominated" : "not nominated"),
936 check_state_name[c->state]));
937 }
938}
939
940#else
941#define dump_checklist(title, ice, clist)
942#endif
943
944static void check_set_state(pj_ice_sess *ice, pj_ice_sess_check *check,
945 pj_ice_sess_check_state st,
946 pj_status_t err_code)
947{
948 pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
949
950 LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
951 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), &ice->clist, check),
952 check_state_name[check->state],
953 check_state_name[st]));
954 check->state = st;
955 check->err_code = err_code;
956}
957
958static void clist_set_state(pj_ice_sess *ice, pj_ice_sess_checklist *clist,
959 pj_ice_sess_checklist_state st)
960{
961 if (clist->state != st) {
962 LOG5((ice->obj_name, "Checklist: state changed from %s to %s",
963 clist_state_name[clist->state],
964 clist_state_name[st]));
965 clist->state = st;
966 }
967}
968
969/* Sort checklist based on priority */
970static void sort_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist)
971{
972 unsigned i;
973 pj_ice_sess_check **check_ptr[PJ_ICE_MAX_COMP*2];
974 unsigned check_ptr_cnt = 0;
975
976 for (i=0; i<ice->comp_cnt; ++i) {
977 if (ice->comp[i].valid_check) {
978 check_ptr[check_ptr_cnt++] = &ice->comp[i].valid_check;
979 }
980 if (ice->comp[i].nominated_check) {
981 check_ptr[check_ptr_cnt++] = &ice->comp[i].nominated_check;
982 }
983 }
984
985 pj_assert(clist->count > 0);
986 for (i=0; i<clist->count-1; ++i) {
987 unsigned j, highest = i;
988
989 for (j=i+1; j<clist->count; ++j) {
990 if (CMP_CHECK_PRIO(&clist->checks[j], &clist->checks[highest]) > 0) {
991 highest = j;
992 }
993 }
994
995 if (highest != i) {
996 pj_ice_sess_check tmp;
997 unsigned k;
998
999 pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_sess_check));
1000 pj_memcpy(&clist->checks[i], &clist->checks[highest],
1001 sizeof(pj_ice_sess_check));
1002 pj_memcpy(&clist->checks[highest], &tmp,
1003 sizeof(pj_ice_sess_check));
1004
1005 /* Update valid and nominated check pointers, since we're moving
1006 * around checks
1007 */
1008 for (k=0; k<check_ptr_cnt; ++k) {
1009 if (*check_ptr[k] == &clist->checks[highest])
1010 *check_ptr[k] = &clist->checks[i];
1011 else if (*check_ptr[k] == &clist->checks[i])
1012 *check_ptr[k] = &clist->checks[highest];
1013 }
1014 }
1015 }
1016}
1017
1018/* Prune checklist, this must have been done after the checklist
1019 * is sorted.
1020 */
1021static pj_status_t prune_checklist(pj_ice_sess *ice,
1022 pj_ice_sess_checklist *clist)
1023{
1024 unsigned i;
1025
1026 /* Since an agent cannot send requests directly from a reflexive
1027 * candidate, but only from its base, the agent next goes through the
1028 * sorted list of candidate pairs. For each pair where the local
1029 * candidate is server reflexive, the server reflexive candidate MUST be
1030 * replaced by its base. Once this has been done, the agent MUST prune
1031 * the list. This is done by removing a pair if its local and remote
1032 * candidates are identical to the local and remote candidates of a pair
1033 * higher up on the priority list. The result is a sequence of ordered
1034 * candidate pairs, called the check list for that media stream.
1035 */
1036 /* First replace SRFLX candidates with their base */
1037 for (i=0; i<clist->count; ++i) {
1038 pj_ice_sess_cand *srflx = clist->checks[i].lcand;
1039
1040 if (clist->checks[i].lcand->type == PJ_ICE_CAND_TYPE_SRFLX) {
1041 /* Find the base for this candidate */
1042 unsigned j;
1043 for (j=0; j<ice->lcand_cnt; ++j) {
1044 pj_ice_sess_cand *host = &ice->lcand[j];
1045
1046 if (host->type != PJ_ICE_CAND_TYPE_HOST)
1047 continue;
1048
1049 if (pj_sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) {
1050 /* Replace this SRFLX with its BASE */
1051 clist->checks[i].lcand = host;
1052 break;
1053 }
1054 }
1055
1056 if (j==ice->lcand_cnt) {
1057 char baddr[PJ_INET6_ADDRSTRLEN];
1058 /* Host candidate not found this this srflx! */
1059 LOG4((ice->obj_name,
1060 "Base candidate %s:%d not found for srflx candidate %d",
1061 pj_sockaddr_print(&srflx->base_addr, baddr,
1062 sizeof(baddr), 0),
1063 pj_sockaddr_get_port(&srflx->base_addr),
1064 GET_LCAND_ID(clist->checks[i].lcand)));
1065 return PJNATH_EICENOHOSTCAND;
1066 }
1067 }
1068 }
1069
1070 /* Next remove a pair if its local and remote candidates are identical
1071 * to the local and remote candidates of a pair higher up on the priority
1072 * list
1073 */
1074 /*
1075 * Not in ICE!
1076 * Remove host candidates if their base are the the same!
1077 */
1078 for (i=0; i<clist->count; ++i) {
1079 pj_ice_sess_cand *licand = clist->checks[i].lcand;
1080 pj_ice_sess_cand *ricand = clist->checks[i].rcand;
1081 unsigned j;
1082
1083 for (j=i+1; j<clist->count;) {
1084 pj_ice_sess_cand *ljcand = clist->checks[j].lcand;
1085 pj_ice_sess_cand *rjcand = clist->checks[j].rcand;
1086 const char *reason = NULL;
1087
1088 if ((licand == ljcand) && (ricand == rjcand)) {
1089 reason = "duplicate found";
1090 } else if ((rjcand == ricand) &&
1091 (pj_sockaddr_cmp(&ljcand->base_addr,
1092 &licand->base_addr)==0))
1093 {
1094 reason = "equal base";
1095 }
1096
1097 if (reason != NULL) {
1098 /* Found duplicate, remove it */
1099 LOG5((ice->obj_name, "Check %s pruned (%s)",
1100 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1101 &ice->clist, &clist->checks[j]),
1102 reason));
1103
1104 pj_array_erase(clist->checks, sizeof(clist->checks[0]),
1105 clist->count, j);
1106 --clist->count;
1107
1108 } else {
1109 ++j;
1110 }
1111 }
1112 }
1113
1114 return PJ_SUCCESS;
1115}
1116
1117/* Timer callback */
1118static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te)
1119{
1120 pj_ice_sess *ice = (pj_ice_sess*) te->user_data;
1121 enum timer_type type = (enum timer_type)te->id;
1122
1123 PJ_UNUSED_ARG(th);
1124
1125 pj_grp_lock_acquire(ice->grp_lock);
1126
1127 te->id = TIMER_NONE;
1128
1129 if (ice->is_destroying) {
1130 /* Stray timer, could happen when destroy is invoked while callback
1131 * is pending. */
1132 pj_grp_lock_release(ice->grp_lock);
1133 return;
1134 }
1135
1136 switch (type) {
1137 case TIMER_CONTROLLED_WAIT_NOM:
1138 LOG4((ice->obj_name,
1139 "Controlled agent timed-out in waiting for the controlling "
1140 "agent to send nominated check. Setting state to fail now.."));
1141 on_ice_complete(ice, PJNATH_EICENOMTIMEOUT);
1142 break;
1143 case TIMER_COMPLETION_CALLBACK:
1144 {
1145 void (*on_ice_complete)(pj_ice_sess *ice, pj_status_t status);
1146 pj_status_t ice_status;
1147
1148 /* Start keep-alive timer but don't send any packets yet.
1149 * Need to do it here just in case app destroy the session
1150 * in the callback.
1151 */
1152 if (ice->ice_status == PJ_SUCCESS)
1153 ice_keep_alive(ice, PJ_FALSE);
1154
1155 /* Release mutex in case app destroy us in the callback */
1156 ice_status = ice->ice_status;
1157 on_ice_complete = ice->cb.on_ice_complete;
1158
1159 /* Notify app about ICE completion*/
1160 if (on_ice_complete)
1161 (*on_ice_complete)(ice, ice_status);
1162 }
1163 break;
1164 case TIMER_START_NOMINATED_CHECK:
1165 start_nominated_check(ice);
1166 break;
1167 case TIMER_KEEP_ALIVE:
1168 ice_keep_alive(ice, PJ_TRUE);
1169 break;
1170 case TIMER_NONE:
1171 /* Nothing to do, just to get rid of gcc warning */
1172 break;
1173 }
1174
1175 pj_grp_lock_release(ice->grp_lock);
1176}
1177
1178/* Send keep-alive */
1179static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now)
1180{
1181 if (send_now) {
1182 /* Send Binding Indication for the component */
1183 pj_ice_sess_comp *comp = &ice->comp[ice->comp_ka];
1184 pj_stun_tx_data *tdata;
1185 pj_ice_sess_check *the_check;
1186 pj_ice_msg_data *msg_data;
1187 int addr_len;
1188 pj_bool_t saved;
1189 pj_status_t status;
1190
1191 /* Must have nominated check by now */
1192 pj_assert(comp->nominated_check != NULL);
1193 the_check = comp->nominated_check;
1194
1195 /* Create the Binding Indication */
1196 status = pj_stun_session_create_ind(comp->stun_sess,
1197 PJ_STUN_BINDING_INDICATION,
1198 &tdata);
1199 if (status != PJ_SUCCESS)
1200 goto done;
1201
1202 /* Need the transport_id */
1203 msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
1204 msg_data->transport_id = the_check->lcand->transport_id;
1205
1206 /* Temporarily disable FINGERPRINT. The Binding Indication
1207 * SHOULD NOT contain any attributes.
1208 */
1209 saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_FALSE);
1210
1211 /* Send to session */
1212 addr_len = pj_sockaddr_get_len(&the_check->rcand->addr);
1213 status = pj_stun_session_send_msg(comp->stun_sess, msg_data,
1214 PJ_FALSE, PJ_FALSE,
1215 &the_check->rcand->addr,
1216 addr_len, tdata);
1217
1218 /* Restore FINGERPRINT usage */
1219 pj_stun_session_use_fingerprint(comp->stun_sess, saved);
1220
1221done:
1222 ice->comp_ka = (ice->comp_ka + 1) % ice->comp_cnt;
1223 }
1224
1225 if (ice->timer.id == TIMER_NONE) {
1226 pj_time_val delay = { 0, 0 };
1227
1228 delay.msec = (PJ_ICE_SESS_KEEP_ALIVE_MIN +
1229 (pj_rand() % PJ_ICE_SESS_KEEP_ALIVE_MAX_RAND)) * 1000 /
1230 ice->comp_cnt;
1231 pj_time_val_normalize(&delay);
1232
1233 pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1234 &ice->timer, &delay,
1235 TIMER_KEEP_ALIVE,
1236 ice->grp_lock);
1237
1238 } else {
1239 pj_assert(!"Not expected any timer active");
1240 }
1241}
1242
1243/* This function is called when ICE processing completes */
1244static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
1245{
1246 if (!ice->is_complete) {
1247 ice->is_complete = PJ_TRUE;
1248 ice->ice_status = status;
1249
1250 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer,
1251 TIMER_NONE);
1252
1253 /* Log message */
1254 LOG4((ice->obj_name, "ICE process complete, status=%s",
1255 pj_strerror(status, ice->tmp.errmsg,
1256 sizeof(ice->tmp.errmsg)).ptr));
1257
1258 dump_checklist("Valid list", ice, &ice->valid_list);
1259
1260 /* Call callback */
1261 if (ice->cb.on_ice_complete) {
1262 pj_time_val delay = {0, 0};
1263
1264 pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1265 &ice->timer, &delay,
1266 TIMER_COMPLETION_CALLBACK,
1267 ice->grp_lock);
1268 }
1269 }
1270}
1271
1272/* Update valid check and nominated check for the candidate */
1273static void update_comp_check(pj_ice_sess *ice, unsigned comp_id,
1274 pj_ice_sess_check *check)
1275{
1276 pj_ice_sess_comp *comp;
1277
1278 comp = find_comp(ice, comp_id);
1279 if (comp->valid_check == NULL) {
1280 comp->valid_check = check;
1281 } else {
1282 if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
1283 comp->valid_check = check;
1284 }
1285
1286 if (check->nominated) {
1287 /* Update the nominated check for the component */
1288 if (comp->nominated_check == NULL) {
1289 comp->nominated_check = check;
1290 } else {
1291 if (CMP_CHECK_PRIO(comp->nominated_check, check) < 0)
1292 comp->nominated_check = check;
1293 }
1294 }
1295}
1296
1297/* This function is called when one check completes */
1298static pj_bool_t on_check_complete(pj_ice_sess *ice,
1299 pj_ice_sess_check *check)
1300{
1301 pj_ice_sess_comp *comp;
1302 unsigned i;
1303
1304 pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
1305
1306 comp = find_comp(ice, check->lcand->comp_id);
1307
1308 /* 7.1.2.2.2. Updating Pair States
1309 *
1310 * The agent sets the state of the pair that generated the check to
1311 * Succeeded. The success of this check might also cause the state of
1312 * other checks to change as well. The agent MUST perform the following
1313 * two steps:
1314 *
1315 * 1. The agent changes the states for all other Frozen pairs for the
1316 * same media stream and same foundation to Waiting. Typically
1317 * these other pairs will have different component IDs but not
1318 * always.
1319 */
1320 if (check->err_code==PJ_SUCCESS) {
1321
1322 for (i=0; i<ice->clist.count; ++i) {
1323 pj_ice_sess_check *c = &ice->clist.checks[i];
1324 if (pj_strcmp(&c->lcand->foundation, &check->lcand->foundation)==0
1325 && c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN)
1326 {
1327 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
1328 }
1329 }
1330
1331 LOG5((ice->obj_name, "Check %d is successful%s",
1332 GET_CHECK_ID(&ice->clist, check),
1333 (check->nominated ? " and nominated" : "")));
1334
1335 }
1336
1337 /* 8.2. Updating States
1338 *
1339 * For both controlling and controlled agents, the state of ICE
1340 * processing depends on the presence of nominated candidate pairs in
1341 * the valid list and on the state of the check list:
1342 *
1343 * o If there are no nominated pairs in the valid list for a media
1344 * stream and the state of the check list is Running, ICE processing
1345 * continues.
1346 *
1347 * o If there is at least one nominated pair in the valid list:
1348 *
1349 * - The agent MUST remove all Waiting and Frozen pairs in the check
1350 * list for the same component as the nominated pairs for that
1351 * media stream
1352 *
1353 * - If an In-Progress pair in the check list is for the same
1354 * component as a nominated pair, the agent SHOULD cease
1355 * retransmissions for its check if its pair priority is lower
1356 * than the lowest priority nominated pair for that component
1357 */
1358 if (check->err_code==PJ_SUCCESS && check->nominated) {
1359
1360 for (i=0; i<ice->clist.count; ++i) {
1361
1362 pj_ice_sess_check *c = &ice->clist.checks[i];
1363
1364 if (c->lcand->comp_id == check->lcand->comp_id) {
1365
1366 if (c->state < PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
1367
1368 /* Just fail Frozen/Waiting check */
1369 LOG5((ice->obj_name,
1370 "Check %s to be failed because state is %s",
1371 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1372 &ice->clist, c),
1373 check_state_name[c->state]));
1374 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
1375 PJ_ECANCELLED);
1376
1377 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS
1378 && (PJ_ICE_CANCEL_ALL ||
1379 CMP_CHECK_PRIO(c, check) < 0)) {
1380
1381 /* State is IN_PROGRESS, cancel transaction */
1382 if (c->tdata) {
1383 LOG5((ice->obj_name,
1384 "Cancelling check %s (In Progress)",
1385 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1386 &ice->clist, c)));
1387 pj_stun_session_cancel_req(comp->stun_sess,
1388 c->tdata, PJ_FALSE, 0);
1389 c->tdata = NULL;
1390 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
1391 PJ_ECANCELLED);
1392 }
1393 }
1394 }
1395 }
1396 }
1397
1398
1399 /* Still in 8.2. Updating States
1400 *
1401 * o Once there is at least one nominated pair in the valid list for
1402 * every component of at least one media stream and the state of the
1403 * check list is Running:
1404 *
1405 * * The agent MUST change the state of processing for its check
1406 * list for that media stream to Completed.
1407 *
1408 * * The agent MUST continue to respond to any checks it may still
1409 * receive for that media stream, and MUST perform triggered
1410 * checks if required by the processing of Section 7.2.
1411 *
1412 * * The agent MAY begin transmitting media for this media stream as
1413 * described in Section 11.1
1414 */
1415
1416 /* See if all components have nominated pair. If they do, then mark
1417 * ICE processing as success, otherwise wait.
1418 */
1419 for (i=0; i<ice->comp_cnt; ++i) {
1420 if (ice->comp[i].nominated_check == NULL)
1421 break;
1422 }
1423 if (i == ice->comp_cnt) {
1424 /* All components have nominated pair */
1425 on_ice_complete(ice, PJ_SUCCESS);
1426 return PJ_TRUE;
1427 }
1428
1429 /* Note: this is the stuffs that we don't do in 7.1.2.2.2, since our
1430 * ICE session only supports one media stream for now:
1431 *
1432 * 7.1.2.2.2. Updating Pair States
1433 *
1434 * 2. If there is a pair in the valid list for every component of this
1435 * media stream (where this is the actual number of components being
1436 * used, in cases where the number of components signaled in the SDP
1437 * differs from offerer to answerer), the success of this check may
1438 * unfreeze checks for other media streams.
1439 */
1440
1441 /* 7.1.2.3. Check List and Timer State Updates
1442 * Regardless of whether the check was successful or failed, the
1443 * completion of the transaction may require updating of check list and
1444 * timer states.
1445 *
1446 * If all of the pairs in the check list are now either in the Failed or
1447 * Succeeded state, and there is not a pair in the valid list for each
1448 * component of the media stream, the state of the check list is set to
1449 * Failed.
1450 */
1451
1452 /*
1453 * See if all checks in the checklist have completed. If we do,
1454 * then mark ICE processing as failed.
1455 */
1456 for (i=0; i<ice->clist.count; ++i) {
1457 pj_ice_sess_check *c = &ice->clist.checks[i];
1458 if (c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
1459 break;
1460 }
1461 }
1462
1463 if (i == ice->clist.count) {
1464 /* All checks have completed, but we don't have nominated pair.
1465 * If agent's role is controlled, check if all components have
1466 * valid pair. If it does, this means the controlled agent has
1467 * finished the check list and it's waiting for controlling
1468 * agent to send checks with USE-CANDIDATE flag set.
1469 */
1470 if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED) {
1471 for (i=0; i < ice->comp_cnt; ++i) {
1472 if (ice->comp[i].valid_check == NULL)
1473 break;
1474 }
1475
1476 if (i < ice->comp_cnt) {
1477 /* This component ID doesn't have valid pair.
1478 * Mark ICE as failed.
1479 */
1480 on_ice_complete(ice, PJNATH_EICEFAILED);
1481 return PJ_TRUE;
1482 } else {
1483 /* All components have a valid pair.
1484 * We should wait until we receive nominated checks.
1485 */
1486 if (ice->timer.id == TIMER_NONE &&
1487 ice->opt.controlled_agent_want_nom_timeout >= 0)
1488 {
1489 pj_time_val delay;
1490
1491 delay.sec = 0;
1492 delay.msec = ice->opt.controlled_agent_want_nom_timeout;
1493 pj_time_val_normalize(&delay);
1494
1495 pj_timer_heap_schedule_w_grp_lock(
1496 ice->stun_cfg.timer_heap,
1497 &ice->timer, &delay,
1498 TIMER_CONTROLLED_WAIT_NOM,
1499 ice->grp_lock);
1500
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));
1506 }
1507 return PJ_FALSE;
1508 }
1509
1510 /* Unreached */
1511
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).
1516 */
1517 on_ice_complete(ice, PJNATH_EICEFAILED);
1518 return PJ_TRUE;
1519
1520 } else {
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.
1524 */
1525 for (i=0; i<ice->comp_cnt; ++i) {
1526 if (ice->comp[i].valid_check == NULL)
1527 break;
1528 }
1529
1530 if (i < ice->comp_cnt) {
1531 /* At least one component doesn't have a valid check. Mark
1532 * ICE as failed.
1533 */
1534 on_ice_complete(ice, PJNATH_EICEFAILED);
1535 return PJ_TRUE;
1536 }
1537
1538 /* Now it's time to send connectivity check with nomination
1539 * flag set.
1540 */
1541 LOG4((ice->obj_name,
1542 "All checks have completed, starting nominated checks now"));
1543 start_nominated_check(ice);
1544 return PJ_FALSE;
1545 }
1546 }
1547
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.
1551 */
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)
1556 {
1557 pj_time_val delay;
1558
1559 for (i=0; i<ice->comp_cnt; ++i) {
1560 if (ice->comp[i].valid_check == NULL)
1561 break;
1562 }
1563
1564 if (i < ice->comp_cnt) {
1565 /* Some components still don't have valid pair, continue
1566 * processing.
1567 */
1568 return PJ_FALSE;
1569 }
1570
1571 LOG4((ice->obj_name,
1572 "Scheduling nominated check in %d ms",
1573 ice->opt.nominated_check_delay));
1574
1575 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer,
1576 TIMER_NONE);
1577
1578 /* All components have valid pair. Let connectivity checks run for
1579 * a little bit more time, then start our nominated check.
1580 */
1581 delay.sec = 0;
1582 delay.msec = ice->opt.nominated_check_delay;
1583 pj_time_val_normalize(&delay);
1584
1585 pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1586 &ice->timer, &delay,
1587 TIMER_START_NOMINATED_CHECK,
1588 ice->grp_lock);
1589 return PJ_FALSE;
1590 }
1591
1592 /* We still have checks to perform */
1593 return PJ_FALSE;
1594}
1595
1596
1597/* Create checklist by pairing local candidates with remote candidates */
1598PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
1599 pj_ice_sess *ice,
1600 const pj_str_t *rem_ufrag,
1601 const pj_str_t *rem_passwd,
1602 unsigned rcand_cnt,
1603 const pj_ice_sess_cand rcand[])
1604{
1605 pj_ice_sess_checklist *clist;
1606 char buf[128];
1607 pj_str_t username;
1608 timer_data *td;
1609 unsigned i, j;
1610 unsigned highest_comp = 0;
1611 pj_status_t status;
1612
1613 PJ_ASSERT_RETURN(ice && rem_ufrag && rem_passwd && rcand_cnt && rcand,
1614 PJ_EINVAL);
1615 PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND,
1616 PJ_ETOOMANY);
1617
1618 pj_grp_lock_acquire(ice->grp_lock);
1619
1620 /* Save credentials */
1621 username.ptr = buf;
1622
1623 pj_strcpy(&username, rem_ufrag);
1624 pj_strcat2(&username, ":");
1625 pj_strcat(&username, &ice->rx_ufrag);
1626
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);
1630
1631 pj_strcpy(&username, &ice->rx_ufrag);
1632 pj_strcat2(&username, ":");
1633 pj_strcat(&username, rem_ufrag);
1634
1635 pj_strdup(ice->pool, &ice->rx_uname, &username);
1636
1637
1638 /* Save remote candidates */
1639 ice->rcand_cnt = 0;
1640 for (i=0; i<rcand_cnt; ++i) {
1641 pj_ice_sess_cand *cn = &ice->rcand[ice->rcand_cnt];
1642
1643 /* Ignore candidate which has no matching component ID */
1644 if (rcand[i].comp_id==0 || rcand[i].comp_id > ice->comp_cnt) {
1645 continue;
1646 }
1647
1648 if (rcand[i].comp_id > highest_comp)
1649 highest_comp = rcand[i].comp_id;
1650
1651 pj_memcpy(cn, &rcand[i], sizeof(pj_ice_sess_cand));
1652 pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation);
1653 ice->rcand_cnt++;
1654 }
1655
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) {
1660
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];
1664
1665 if (clist->count >= PJ_ICE_MAX_CHECKS) {
1666 pj_grp_lock_release(ice->grp_lock);
1667 return PJ_ETOOMANY;
1668 }
1669
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.
1673 */
1674 if ((lcand->comp_id != rcand->comp_id) ||
1675 (lcand->addr.addr.sa_family != rcand->addr.addr.sa_family))
1676 {
1677 continue;
1678 }
1679
1680
1681 chk->lcand = lcand;
1682 chk->rcand = rcand;
1683 chk->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
1684
1685 chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
1686
1687 clist->count++;
1688 }
1689 }
1690
1691 /* This could happen if candidates have no matching address families */
1692 if (clist->count == 0) {
1693 LOG4((ice->obj_name, "Error: no checklist can be created"));
1694 pj_grp_lock_release(ice->grp_lock);
1695 return PJ_ENOTFOUND;
1696 }
1697
1698 /* Sort checklist based on priority */
1699 sort_checklist(ice, clist);
1700
1701 /* Prune the checklist */
1702 status = prune_checklist(ice, clist);
1703 if (status != PJ_SUCCESS) {
1704 pj_grp_lock_release(ice->grp_lock);
1705 return status;
1706 }
1707
1708 /* Disable our components which don't have matching component */
1709 for (i=highest_comp; i<ice->comp_cnt; ++i) {
1710 if (ice->comp[i].stun_sess) {
1711 pj_stun_session_destroy(ice->comp[i].stun_sess);
1712 pj_bzero(&ice->comp[i], sizeof(ice->comp[i]));
1713 }
1714 }
1715 ice->comp_cnt = highest_comp;
1716
1717 /* Init timer entry in the checklist. Initially the timer ID is FALSE
1718 * because timer is not running.
1719 */
1720 clist->timer.id = PJ_FALSE;
1721 td = PJ_POOL_ZALLOC_T(ice->pool, timer_data);
1722 td->ice = ice;
1723 td->clist = clist;
1724 clist->timer.user_data = (void*)td;
1725 clist->timer.cb = &periodic_timer;
1726
1727
1728 /* Log checklist */
1729 dump_checklist("Checklist created:", ice, clist);
1730
1731 pj_grp_lock_release(ice->grp_lock);
1732
1733 return PJ_SUCCESS;
1734}
1735
1736/* Perform check on the specified candidate pair. */
1737static pj_status_t perform_check(pj_ice_sess *ice,
1738 pj_ice_sess_checklist *clist,
1739 unsigned check_id,
1740 pj_bool_t nominate)
1741{
1742 pj_ice_sess_comp *comp;
1743 pj_ice_msg_data *msg_data;
1744 pj_ice_sess_check *check;
1745 const pj_ice_sess_cand *lcand;
1746 const pj_ice_sess_cand *rcand;
1747 pj_uint32_t prio;
1748 pj_status_t status;
1749
1750 check = &clist->checks[check_id];
1751 lcand = check->lcand;
1752 rcand = check->rcand;
1753 comp = find_comp(ice, lcand->comp_id);
1754
1755 LOG5((ice->obj_name,
1756 "Sending connectivity check for check %s",
1757 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, check)));
1758 pj_log_push_indent();
1759
1760 /* Create request */
1761 status = pj_stun_session_create_req(comp->stun_sess,
1762 PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC,
1763 NULL, &check->tdata);
1764 if (status != PJ_SUCCESS) {
1765 pjnath_perror(ice->obj_name, "Error creating STUN request", status);
1766 pj_log_pop_indent();
1767 return status;
1768 }
1769
1770 /* Attach data to be retrieved later when STUN request transaction
1771 * completes and on_stun_request_complete() callback is called.
1772 */
1773 msg_data = PJ_POOL_ZALLOC_T(check->tdata->pool, pj_ice_msg_data);
1774 msg_data->transport_id = lcand->transport_id;
1775 msg_data->has_req_data = PJ_TRUE;
1776 msg_data->data.req.ice = ice;
1777 msg_data->data.req.clist = clist;
1778 msg_data->data.req.ckid = check_id;
1779
1780 /* Add PRIORITY */
1781#if PJNATH_ICE_PRIO_STD
1782 prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535,
1783 lcand->comp_id);
1784#else
1785 prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 0,
1786 lcand->comp_id);
1787#endif
1788 pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg,
1789 PJ_STUN_ATTR_PRIORITY, prio);
1790
1791 /* Add USE-CANDIDATE and set this check to nominated.
1792 * Also add ICE-CONTROLLING or ICE-CONTROLLED
1793 */
1794 if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
1795 if (nominate) {
1796 pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg,
1797 PJ_STUN_ATTR_USE_CANDIDATE);
1798 check->nominated = PJ_TRUE;
1799 }
1800
1801 pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,
1802 PJ_STUN_ATTR_ICE_CONTROLLING,
1803 &ice->tie_breaker);
1804
1805 } else {
1806 pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,
1807 PJ_STUN_ATTR_ICE_CONTROLLED,
1808 &ice->tie_breaker);
1809 }
1810
1811
1812 /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the
1813 * STUN session.
1814 */
1815
1816 /* Initiate STUN transaction to send the request */
1817 status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE,
1818 PJ_TRUE, &rcand->addr,
1819 pj_sockaddr_get_len(&rcand->addr),
1820 check->tdata);
1821 if (status != PJ_SUCCESS) {
1822 check->tdata = NULL;
1823 pjnath_perror(ice->obj_name, "Error sending STUN request", status);
1824 pj_log_pop_indent();
1825 return status;
1826 }
1827
1828 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS,
1829 PJ_SUCCESS);
1830 pj_log_pop_indent();
1831 return PJ_SUCCESS;
1832}
1833
1834
1835/* Start periodic check for the specified checklist.
1836 * This callback is called by timer on every Ta (20msec by default)
1837 */
1838static pj_status_t start_periodic_check(pj_timer_heap_t *th,
1839 pj_timer_entry *te)
1840{
1841 timer_data *td;
1842 pj_ice_sess *ice;
1843 pj_ice_sess_checklist *clist;
1844 unsigned i, start_count=0;
1845 pj_status_t status;
1846
1847 td = (struct timer_data*) te->user_data;
1848 ice = td->ice;
1849 clist = td->clist;
1850
1851 pj_grp_lock_acquire(ice->grp_lock);
1852
1853 if (ice->is_destroying) {
1854 pj_grp_lock_release(ice->grp_lock);
1855 return PJ_SUCCESS;
1856 }
1857
1858 /* Set timer ID to FALSE first */
1859 te->id = PJ_FALSE;
1860
1861 /* Set checklist state to Running */
1862 clist_set_state(ice, clist, PJ_ICE_SESS_CHECKLIST_ST_RUNNING);
1863
1864 LOG5((ice->obj_name, "Starting checklist periodic check"));
1865 pj_log_push_indent();
1866
1867 /* Send STUN Binding request for check with highest priority on
1868 * Waiting state.
1869 */
1870 for (i=0; i<clist->count; ++i) {
1871 pj_ice_sess_check *check = &clist->checks[i];
1872
1873 if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
1874 status = perform_check(ice, clist, i, ice->is_nominating);
1875 if (status != PJ_SUCCESS) {
1876 pj_grp_lock_release(ice->grp_lock);
1877 pj_log_pop_indent();
1878 return status;
1879 }
1880
1881 ++start_count;
1882 break;
1883 }
1884 }
1885
1886 /* If we don't have anything in Waiting state, perform check to
1887 * highest priority pair that is in Frozen state.
1888 */
1889 if (start_count==0) {
1890 for (i=0; i<clist->count; ++i) {
1891 pj_ice_sess_check *check = &clist->checks[i];
1892
1893 if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
1894 status = perform_check(ice, clist, i, ice->is_nominating);
1895 if (status != PJ_SUCCESS) {
1896 pj_grp_lock_release(ice->grp_lock);
1897 pj_log_pop_indent();
1898 return status;
1899 }
1900
1901 ++start_count;
1902 break;
1903 }
1904 }
1905 }
1906
1907 /* Cannot start check because there's no suitable candidate pair.
1908 */
1909 if (start_count!=0) {
1910 /* Schedule for next timer */
1911 pj_time_val timeout = {0, PJ_ICE_TA_VAL};
1912
1913 pj_time_val_normalize(&timeout);
1914 pj_timer_heap_schedule_w_grp_lock(th, te, &timeout, PJ_TRUE,
1915 ice->grp_lock);
1916 }
1917
1918 pj_grp_lock_release(ice->grp_lock);
1919 pj_log_pop_indent();
1920 return PJ_SUCCESS;
1921}
1922
1923
1924/* Start sending connectivity check with USE-CANDIDATE */
1925static void start_nominated_check(pj_ice_sess *ice)
1926{
1927 pj_time_val delay;
1928 unsigned i;
1929 pj_status_t status;
1930
1931 LOG4((ice->obj_name, "Starting nominated check.."));
1932 pj_log_push_indent();
1933
1934 pj_assert(ice->is_nominating == PJ_FALSE);
1935
1936 /* Stop our timer if it's active */
1937 if (ice->timer.id == TIMER_START_NOMINATED_CHECK) {
1938 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer,
1939 TIMER_NONE);
1940 }
1941
1942 /* For each component, set the check state of valid check with
1943 * highest priority to Waiting (it should have Success state now).
1944 */
1945 for (i=0; i<ice->comp_cnt; ++i) {
1946 unsigned j;
1947 const pj_ice_sess_check *vc = ice->comp[i].valid_check;
1948
1949 pj_assert(ice->comp[i].nominated_check == NULL);
1950 pj_assert(vc->err_code == PJ_SUCCESS);
1951
1952 for (j=0; j<ice->clist.count; ++j) {
1953 pj_ice_sess_check *c = &ice->clist.checks[j];
1954 if (c->lcand->transport_id == vc->lcand->transport_id &&
1955 c->rcand == vc->rcand)
1956 {
1957 pj_assert(c->err_code == PJ_SUCCESS);
1958 c->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
1959 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING,
1960 PJ_SUCCESS);
1961 break;
1962 }
1963 }
1964 }
1965
1966 /* And (re)start the periodic check */
1967 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,
1968 &ice->clist.timer, PJ_FALSE);
1969
1970 delay.sec = delay.msec = 0;
1971 status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1972 &ice->clist.timer, &delay,
1973 PJ_TRUE,
1974 ice->grp_lock);
1975 if (status == PJ_SUCCESS) {
1976 LOG5((ice->obj_name, "Periodic timer rescheduled.."));
1977 }
1978
1979 ice->is_nominating = PJ_TRUE;
1980 pj_log_pop_indent();
1981}
1982
1983/* Timer callback to perform periodic check */
1984static void periodic_timer(pj_timer_heap_t *th,
1985 pj_timer_entry *te)
1986{
1987 start_periodic_check(th, te);
1988}
1989
1990
1991/* Utility: find string in string array */
1992const pj_str_t *find_str(const pj_str_t *strlist[], unsigned count,
1993 const pj_str_t *str)
1994{
1995 unsigned i;
1996 for (i=0; i<count; ++i) {
1997 if (pj_strcmp(strlist[i], str)==0)
1998 return strlist[i];
1999 }
2000 return NULL;
2001}
2002
2003
2004/*
2005 * Start ICE periodic check. This function will return immediately, and
2006 * application will be notified about the connectivity check status in
2007 * #pj_ice_sess_cb callback.
2008 */
2009PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice)
2010{
2011 pj_ice_sess_checklist *clist;
2012 const pj_ice_sess_cand *cand0;
2013 const pj_str_t *flist[PJ_ICE_MAX_CAND]; // XXX
2014 pj_ice_rx_check *rcheck;
2015 unsigned i, flist_cnt = 0;
2016 pj_time_val delay;
2017 pj_status_t status;
2018
2019 PJ_ASSERT_RETURN(ice, PJ_EINVAL);
2020
2021 /* Checklist must have been created */
2022 PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
2023
2024 /* Lock session */
2025 pj_grp_lock_acquire(ice->grp_lock);
2026
2027 LOG4((ice->obj_name, "Starting ICE check.."));
2028 pj_log_push_indent();
2029
2030 /* If we are using aggressive nomination, set the is_nominating state */
2031 if (ice->opt.aggressive)
2032 ice->is_nominating = PJ_TRUE;
2033
2034 /* The agent examines the check list for the first media stream (a
2035 * media stream is the first media stream when it is described by
2036 * the first m-line in the SDP offer and answer). For that media
2037 * stream, it:
2038 *
2039 * - Groups together all of the pairs with the same foundation,
2040 *
2041 * - For each group, sets the state of the pair with the lowest
2042 * component ID to Waiting. If there is more than one such pair,
2043 * the one with the highest priority is used.
2044 */
2045
2046 clist = &ice->clist;
2047
2048 /* Pickup the first pair for component 1. */
2049 for (i=0; i<clist->count; ++i) {
2050 if (clist->checks[i].lcand->comp_id == 1)
2051 break;
2052 }
2053 if (i == clist->count) {
2054 pj_assert(!"Unable to find checklist for component 1");
2055 pj_grp_lock_release(ice->grp_lock);
2056 pj_log_pop_indent();
2057 return PJNATH_EICEINCOMPID;
2058 }
2059
2060 /* Set this check to WAITING only if state is frozen. It may be possible
2061 * that this check has already been started by a trigger check
2062 */
2063 if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
2064 check_set_state(ice, &clist->checks[i],
2065 PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
2066 }
2067
2068 cand0 = clist->checks[i].lcand;
2069 flist[flist_cnt++] = &clist->checks[i].lcand->foundation;
2070
2071 /* Find all of the other pairs in that check list with the same
2072 * component ID, but different foundations, and sets all of their
2073 * states to Waiting as well.
2074 */
2075 for (++i; i<clist->count; ++i) {
2076 const pj_ice_sess_cand *cand1;
2077
2078 cand1 = clist->checks[i].lcand;
2079
2080 if (cand1->comp_id==cand0->comp_id &&
2081 find_str(flist, flist_cnt, &cand1->foundation)==NULL)
2082 {
2083 if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
2084 check_set_state(ice, &clist->checks[i],
2085 PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
2086 }
2087 flist[flist_cnt++] = &cand1->foundation;
2088 }
2089 }
2090
2091 /* First, perform all pending triggered checks, simultaneously. */
2092 rcheck = ice->early_check.next;
2093 while (rcheck != &ice->early_check) {
2094 LOG4((ice->obj_name,
2095 "Performing delayed triggerred check for component %d",
2096 rcheck->comp_id));
2097 pj_log_push_indent();
2098 handle_incoming_check(ice, rcheck);
2099 rcheck = rcheck->next;
2100 pj_log_pop_indent();
2101 }
2102 pj_list_init(&ice->early_check);
2103
2104 /* Start periodic check */
2105 /* We could start it immediately like below, but lets schedule timer
2106 * instead to reduce stack usage:
2107 * return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer);
2108 */
2109 delay.sec = delay.msec = 0;
2110 status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
2111 &clist->timer, &delay,
2112 PJ_TRUE, ice->grp_lock);
2113 if (status != PJ_SUCCESS) {
2114 clist->timer.id = PJ_FALSE;
2115 }
2116
2117 pj_grp_lock_release(ice->grp_lock);
2118 pj_log_pop_indent();
2119 return status;
2120}
2121
2122
2123//////////////////////////////////////////////////////////////////////////////
2124
2125/* Callback called by STUN session to send the STUN message.
2126 * STUN session also doesn't have a transport, remember?!
2127 */
2128static pj_status_t on_stun_send_msg(pj_stun_session *sess,
2129 void *token,
2130 const void *pkt,
2131 pj_size_t pkt_size,
2132 const pj_sockaddr_t *dst_addr,
2133 unsigned addr_len)
2134{
2135 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
2136 pj_ice_sess *ice = sd->ice;
2137 pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
2138 pj_status_t status;
2139
2140 pj_grp_lock_acquire(ice->grp_lock);
2141
2142 if (ice->is_destroying) {
2143 /* Stray retransmit timer that could happen while
2144 * we're being destroyed */
2145 pj_grp_lock_release(ice->grp_lock);
2146 return PJ_EINVALIDOP;
2147 }
2148
2149 status = (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id,
2150 pkt, pkt_size, dst_addr, addr_len);
2151
2152 pj_grp_lock_release(ice->grp_lock);
2153 return status;
2154}
2155
2156
2157/* This callback is called when outgoing STUN request completed */
2158static void on_stun_request_complete(pj_stun_session *stun_sess,
2159 pj_status_t status,
2160 void *token,
2161 pj_stun_tx_data *tdata,
2162 const pj_stun_msg *response,
2163 const pj_sockaddr_t *src_addr,
2164 unsigned src_addr_len)
2165{
2166 pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
2167 pj_ice_sess *ice;
2168 pj_ice_sess_check *check, *new_check;
2169 pj_ice_sess_cand *lcand;
2170 pj_ice_sess_checklist *clist;
2171 pj_stun_xor_mapped_addr_attr *xaddr;
2172 unsigned i;
2173
2174 PJ_UNUSED_ARG(stun_sess);
2175 PJ_UNUSED_ARG(src_addr_len);
2176
2177 pj_assert(msg_data->has_req_data);
2178
2179 ice = msg_data->data.req.ice;
2180 clist = msg_data->data.req.clist;
2181 check = &clist->checks[msg_data->data.req.ckid];
2182
2183
2184 /* Mark STUN transaction as complete */
2185 pj_assert(tdata == check->tdata);
2186 check->tdata = NULL;
2187
2188 pj_grp_lock_acquire(ice->grp_lock);
2189
2190 if (ice->is_destroying) {
2191 /* Not sure if this is possible but just in case */
2192 pj_grp_lock_release(ice->grp_lock);
2193 return;
2194 }
2195
2196 /* Init lcand to NULL. lcand will be found from the mapped address
2197 * found in the response.
2198 */
2199 lcand = NULL;
2200
2201 if (status != PJ_SUCCESS) {
2202 char errmsg[PJ_ERR_MSG_SIZE];
2203
2204 if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ROLE_CONFLICT)) {
2205
2206 /* Role conclict response.
2207 *
2208 * 7.1.2.1. Failure Cases:
2209 *
2210 * If the request had contained the ICE-CONTROLLED attribute,
2211 * the agent MUST switch to the controlling role if it has not
2212 * already done so. If the request had contained the
2213 * ICE-CONTROLLING attribute, the agent MUST switch to the
2214 * controlled role if it has not already done so. Once it has
2215 * switched, the agent MUST immediately retry the request with
2216 * the ICE-CONTROLLING or ICE-CONTROLLED attribute reflecting
2217 * its new role.
2218 */
2219 pj_ice_sess_role new_role = PJ_ICE_SESS_ROLE_UNKNOWN;
2220 pj_stun_msg *req = tdata->msg;
2221
2222 if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLING, 0)) {
2223 new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
2224 } else if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLED,
2225 0)) {
2226 new_role = PJ_ICE_SESS_ROLE_CONTROLLING;
2227 } else {
2228 pj_assert(!"We should have put CONTROLLING/CONTROLLED attr!");
2229 new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
2230 }
2231
2232 if (new_role != ice->role) {
2233 LOG4((ice->obj_name,
2234 "Changing role because of role conflict response"));
2235 pj_ice_sess_change_role(ice, new_role);
2236 }
2237
2238 /* Resend request */
2239 LOG4((ice->obj_name, "Resending check because of role conflict"));
2240 pj_log_push_indent();
2241 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
2242 perform_check(ice, clist, msg_data->data.req.ckid,
2243 check->nominated || ice->is_nominating);
2244 pj_log_pop_indent();
2245 pj_grp_lock_release(ice->grp_lock);
2246 return;
2247 }
2248
2249 pj_strerror(status, errmsg, sizeof(errmsg));
2250 LOG4((ice->obj_name,
2251 "Check %s%s: connectivity check FAILED: %s",
2252 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2253 &ice->clist, check),
2254 (check->nominated ? " (nominated)" : " (not nominated)"),
2255 errmsg));
2256 pj_log_push_indent();
2257 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
2258 on_check_complete(ice, check);
2259 pj_log_pop_indent();
2260 pj_grp_lock_release(ice->grp_lock);
2261 return;
2262 }
2263
2264
2265 /* 7.1.2.1. Failure Cases
2266 *
2267 * The agent MUST check that the source IP address and port of the
2268 * response equals the destination IP address and port that the Binding
2269 * Request was sent to, and that the destination IP address and port of
2270 * the response match the source IP address and port that the Binding
2271 * Request was sent from.
2272 */
2273 if (pj_sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr)!=0)
2274 {
2275 status = PJNATH_EICEINSRCADDR;
2276 LOG4((ice->obj_name,
2277 "Check %s%s: connectivity check FAILED: source address mismatch",
2278 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2279 &ice->clist, check),
2280 (check->nominated ? " (nominated)" : " (not nominated)")));
2281 pj_log_push_indent();
2282 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
2283 on_check_complete(ice, check);
2284 pj_log_pop_indent();
2285 pj_grp_lock_release(ice->grp_lock);
2286 return;
2287 }
2288
2289 /* 7.1.2.2. Success Cases
2290 *
2291 * A check is considered to be a success if all of the following are
2292 * true:
2293 *
2294 * o the STUN transaction generated a success response
2295 *
2296 * o the source IP address and port of the response equals the
2297 * destination IP address and port that the Binding Request was sent
2298 * to
2299 *
2300 * o the destination IP address and port of the response match the
2301 * source IP address and port that the Binding Request was sent from
2302 */
2303
2304
2305 LOG4((ice->obj_name,
2306 "Check %s%s: connectivity check SUCCESS",
2307 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2308 &ice->clist, check),
2309 (check->nominated ? " (nominated)" : " (not nominated)")));
2310
2311 /* Get the STUN XOR-MAPPED-ADDRESS attribute. */
2312 xaddr = (pj_stun_xor_mapped_addr_attr*)
2313 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0);
2314 if (!xaddr) {
2315 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
2316 PJNATH_ESTUNNOMAPPEDADDR);
2317 on_check_complete(ice, check);
2318 pj_grp_lock_release(ice->grp_lock);
2319 return;
2320 }
2321
2322 /* Find local candidate that matches the XOR-MAPPED-ADDRESS */
2323 pj_assert(lcand == NULL);
2324 for (i=0; i<ice->lcand_cnt; ++i) {
2325 if (pj_sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) {
2326 /* Match */
2327 lcand = &ice->lcand[i];
2328 break;
2329 }
2330 }
2331
2332 /* 7.1.2.2.1. Discovering Peer Reflexive Candidates
2333 * If the transport address returned in XOR-MAPPED-ADDRESS does not match
2334 * any of the local candidates that the agent knows about, the mapped
2335 * address represents a new candidate - a peer reflexive candidate.
2336 */
2337 if (lcand == NULL) {
2338 unsigned cand_id;
2339 pj_str_t foundation;
2340
2341 pj_ice_calc_foundation(ice->pool, &foundation, PJ_ICE_CAND_TYPE_PRFLX,
2342 &check->lcand->base_addr);
2343
2344 /* Still in 7.1.2.2.1. Discovering Peer Reflexive Candidates
2345 * Its priority is set equal to the value of the PRIORITY attribute
2346 * in the Binding Request.
2347 *
2348 * I think the priority calculated by add_cand() should be the same
2349 * as the one calculated in perform_check(), so there's no need to
2350 * get the priority from the PRIORITY attribute.
2351 */
2352
2353 /* Add new peer reflexive candidate */
2354 status = pj_ice_sess_add_cand(ice, check->lcand->comp_id,
2355 msg_data->transport_id,
2356 PJ_ICE_CAND_TYPE_PRFLX,
2357 65535, &foundation,
2358 &xaddr->sockaddr,
2359 &check->lcand->base_addr,
2360 &check->lcand->base_addr,
2361 pj_sockaddr_get_len(&xaddr->sockaddr),
2362 &cand_id);
2363 if (status != PJ_SUCCESS) {
2364 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
2365 status);
2366 on_check_complete(ice, check);
2367 pj_grp_lock_release(ice->grp_lock);
2368 return;
2369 }
2370
2371 /* Update local candidate */
2372 lcand = &ice->lcand[cand_id];
2373
2374 }
2375
2376 /* 7.1.2.2.3. Constructing a Valid Pair
2377 * Next, the agent constructs a candidate pair whose local candidate
2378 * equals the mapped address of the response, and whose remote candidate
2379 * equals the destination address to which the request was sent.
2380 */
2381
2382 /* Add pair to valid list, if it's not there, otherwise just update
2383 * nominated flag
2384 */
2385 for (i=0; i<ice->valid_list.count; ++i) {
2386 if (ice->valid_list.checks[i].lcand == lcand &&
2387 ice->valid_list.checks[i].rcand == check->rcand)
2388 break;
2389 }
2390
2391 if (i==ice->valid_list.count) {
2392 pj_assert(ice->valid_list.count < PJ_ICE_MAX_CHECKS);
2393 new_check = &ice->valid_list.checks[ice->valid_list.count++];
2394 new_check->lcand = lcand;
2395 new_check->rcand = check->rcand;
2396 new_check->prio = CALC_CHECK_PRIO(ice, lcand, check->rcand);
2397 new_check->state = PJ_ICE_SESS_CHECK_STATE_SUCCEEDED;
2398 new_check->nominated = check->nominated;
2399 new_check->err_code = PJ_SUCCESS;
2400 } else {
2401 new_check = &ice->valid_list.checks[i];
2402 ice->valid_list.checks[i].nominated = check->nominated;
2403 }
2404
2405 /* Update valid check and nominated check for the component */
2406 update_comp_check(ice, new_check->lcand->comp_id, new_check);
2407
2408 /* Sort valid_list (must do so after update_comp_check(), otherwise
2409 * new_check will point to something else (#953)
2410 */
2411 sort_checklist(ice, &ice->valid_list);
2412
2413 /* 7.1.2.2.2. Updating Pair States
2414 *
2415 * The agent sets the state of the pair that generated the check to
2416 * Succeeded. The success of this check might also cause the state of
2417 * other checks to change as well.
2418 */
2419 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_SUCCEEDED,
2420 PJ_SUCCESS);
2421
2422 /* Perform 7.1.2.2.2. Updating Pair States.
2423 * This may terminate ICE processing.
2424 */
2425 if (on_check_complete(ice, check)) {
2426 /* ICE complete! */
2427 pj_grp_lock_release(ice->grp_lock);
2428 return;
2429 }
2430
2431 pj_grp_lock_release(ice->grp_lock);
2432}
2433
2434
2435/* This callback is called by the STUN session associated with a candidate
2436 * when it receives incoming request.
2437 */
2438static pj_status_t on_stun_rx_request(pj_stun_session *sess,
2439 const pj_uint8_t *pkt,
2440 unsigned pkt_len,
2441 const pj_stun_rx_data *rdata,
2442 void *token,
2443 const pj_sockaddr_t *src_addr,
2444 unsigned src_addr_len)
2445{
2446 stun_data *sd;
2447 const pj_stun_msg *msg = rdata->msg;
2448 pj_ice_msg_data *msg_data;
2449 pj_ice_sess *ice;
2450 pj_stun_priority_attr *prio_attr;
2451 pj_stun_use_candidate_attr *uc_attr;
2452 pj_stun_uint64_attr *role_attr;
2453 pj_stun_tx_data *tdata;
2454 pj_ice_rx_check *rcheck, tmp_rcheck;
2455 pj_status_t status;
2456
2457 PJ_UNUSED_ARG(pkt);
2458 PJ_UNUSED_ARG(pkt_len);
2459
2460 /* Reject any requests except Binding request */
2461 if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
2462 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
2463 NULL, token, PJ_TRUE,
2464 src_addr, src_addr_len);
2465 return PJ_SUCCESS;
2466 }
2467
2468
2469 sd = (stun_data*) pj_stun_session_get_user_data(sess);
2470 ice = sd->ice;
2471
2472 pj_grp_lock_acquire(ice->grp_lock);
2473
2474 if (ice->is_destroying) {
2475 pj_grp_lock_release(ice->grp_lock);
2476 return PJ_EINVALIDOP;
2477 }
2478
2479 /*
2480 * Note:
2481 * Be aware that when STUN request is received, we might not get
2482 * SDP answer yet, so we might not have remote candidates and
2483 * checklist yet. This case will be handled after we send
2484 * a response.
2485 */
2486
2487 /* Get PRIORITY attribute */
2488 prio_attr = (pj_stun_priority_attr*)
2489 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0);
2490 if (prio_attr == NULL) {
2491 LOG5((ice->obj_name, "Received Binding request with no PRIORITY"));
2492 pj_grp_lock_release(ice->grp_lock);
2493 return PJ_SUCCESS;
2494 }
2495
2496 /* Get USE-CANDIDATE attribute */
2497 uc_attr = (pj_stun_use_candidate_attr*)
2498 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0);
2499
2500
2501 /* Get ICE-CONTROLLING or ICE-CONTROLLED */
2502 role_attr = (pj_stun_uint64_attr*)
2503 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLING, 0);
2504 if (role_attr == NULL) {
2505 role_attr = (pj_stun_uint64_attr*)
2506 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLED, 0);
2507 }
2508
2509 /* Handle the case when request comes before answer is received.
2510 * We need to put credential in the response, and since we haven't
2511 * got the response, copy the username from the request.
2512 */
2513 if (ice->rcand_cnt == 0) {
2514 pj_stun_string_attr *uname_attr;
2515
2516 uname_attr = (pj_stun_string_attr*)
2517 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
2518 pj_assert(uname_attr != NULL);
2519 pj_strdup(ice->pool, &ice->rx_uname, &uname_attr->value);
2520 }
2521
2522 /* 7.2.1.1. Detecting and Repairing Role Conflicts
2523 */
2524 if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING &&
2525 role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLING)
2526 {
2527 if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
2528 /* Switch role to controlled */
2529 LOG4((ice->obj_name,
2530 "Changing role because of ICE-CONTROLLING attribute"));
2531 pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLED);
2532 } else {
2533 /* Generate 487 response */
2534 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
2535 NULL, token, PJ_TRUE,
2536 src_addr, src_addr_len);
2537 pj_grp_lock_release(ice->grp_lock);
2538 return PJ_SUCCESS;
2539 }
2540
2541 } else if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED &&
2542 role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLED)
2543 {
2544 if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
2545 /* Generate 487 response */
2546 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
2547 NULL, token, PJ_TRUE,
2548 src_addr, src_addr_len);
2549 pj_grp_lock_release(ice->grp_lock);
2550 return PJ_SUCCESS;
2551 } else {
2552 /* Switch role to controlled */
2553 LOG4((ice->obj_name,
2554 "Changing role because of ICE-CONTROLLED attribute"));
2555 pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLING);
2556 }
2557 }
2558
2559 /*
2560 * First send response to this request
2561 */
2562 status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata);
2563 if (status != PJ_SUCCESS) {
2564 pj_grp_lock_release(ice->grp_lock);
2565 return status;
2566 }
2567
2568 /* Add XOR-MAPPED-ADDRESS attribute */
2569 status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
2570 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
2571 PJ_TRUE, src_addr, src_addr_len);
2572
2573 /* Create a msg_data to be associated with this response */
2574 msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
2575 msg_data->transport_id = ((pj_ice_msg_data*)token)->transport_id;
2576 msg_data->has_req_data = PJ_FALSE;
2577
2578 /* Send the response */
2579 status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
2580 src_addr, src_addr_len, tdata);
2581
2582
2583 /*
2584 * Handling early check.
2585 *
2586 * It's possible that we receive this request before we receive SDP
2587 * answer. In this case, we can't perform trigger check since we
2588 * don't have checklist yet, so just save this check in a pending
2589 * triggered check array to be acted upon later.
2590 */
2591 if (ice->rcand_cnt == 0) {
2592 rcheck = PJ_POOL_ZALLOC_T(ice->pool, pj_ice_rx_check);
2593 } else {
2594 rcheck = &tmp_rcheck;
2595 }
2596
2597 /* Init rcheck */
2598 rcheck->comp_id = sd->comp_id;
2599 rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
2600 rcheck->src_addr_len = src_addr_len;
2601 pj_sockaddr_cp(&rcheck->src_addr, src_addr);
2602 rcheck->use_candidate = (uc_attr != NULL);
2603 rcheck->priority = prio_attr->value;
2604 rcheck->role_attr = role_attr;
2605
2606 if (ice->rcand_cnt == 0) {
2607 /* We don't have answer yet, so keep this request for later */
2608 LOG4((ice->obj_name, "Received an early check for comp %d",
2609 rcheck->comp_id));
2610 pj_list_push_back(&ice->early_check, rcheck);
2611 } else {
2612 /* Handle this check */
2613 handle_incoming_check(ice, rcheck);
2614 }
2615
2616 pj_grp_lock_release(ice->grp_lock);
2617 return PJ_SUCCESS;
2618}
2619
2620
2621/* Handle incoming Binding request and perform triggered check.
2622 * This function may be called by on_stun_rx_request(), or when
2623 * SDP answer is received and we have received early checks.
2624 */
2625static void handle_incoming_check(pj_ice_sess *ice,
2626 const pj_ice_rx_check *rcheck)
2627{
2628 pj_ice_sess_comp *comp;
2629 pj_ice_sess_cand *lcand = NULL;
2630 pj_ice_sess_cand *rcand;
2631 unsigned i;
2632
2633 comp = find_comp(ice, rcheck->comp_id);
2634
2635 /* Find remote candidate based on the source transport address of
2636 * the request.
2637 */
2638 for (i=0; i<ice->rcand_cnt; ++i) {
2639 if (pj_sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0)
2640 break;
2641 }
2642
2643 /* 7.2.1.3. Learning Peer Reflexive Candidates
2644 * If the source transport address of the request does not match any
2645 * existing remote candidates, it represents a new peer reflexive remote
2646 * candidate.
2647 */
2648 if (i == ice->rcand_cnt) {
2649 char raddr[PJ_INET6_ADDRSTRLEN];
2650 if (ice->rcand_cnt >= PJ_ICE_MAX_CAND) {
2651 LOG4((ice->obj_name,
2652 "Unable to add new peer reflexive candidate: too many "
2653 "candidates already (%d)", PJ_ICE_MAX_CAND));
2654 return;
2655 }
2656
2657 rcand = &ice->rcand[ice->rcand_cnt++];
2658 rcand->comp_id = (pj_uint8_t)rcheck->comp_id;
2659 rcand->type = PJ_ICE_CAND_TYPE_PRFLX;
2660 rcand->prio = rcheck->priority;
2661 pj_sockaddr_cp(&rcand->addr, &rcheck->src_addr);
2662
2663 /* Foundation is random, unique from other foundation */
2664 rcand->foundation.ptr = (char*) pj_pool_alloc(ice->pool, 36);
2665 rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 36,
2666 "f%p",
2667 rcand->foundation.ptr);
2668
2669 LOG4((ice->obj_name,
2670 "Added new remote candidate from the request: %s:%d",
2671 pj_sockaddr_print(&rcand->addr, raddr, sizeof(raddr), 0),
2672 pj_sockaddr_get_port(&rcand->addr)));
2673
2674 } else {
2675 /* Remote candidate found */
2676 rcand = &ice->rcand[i];
2677 }
2678
2679#if 0
2680 /* Find again the local candidate by matching the base address
2681 * with the local candidates in the checklist. Checks may have
2682 * been pruned before, so it's possible that if we use the lcand
2683 * as it is, we wouldn't be able to find the check in the checklist
2684 * and we will end up creating a new check unnecessarily.
2685 */
2686 for (i=0; i<ice->clist.count; ++i) {
2687 pj_ice_sess_check *c = &ice->clist.checks[i];
2688 if (/*c->lcand == lcand ||*/
2689 pj_sockaddr_cmp(&c->lcand->base_addr, &lcand->base_addr)==0)
2690 {
2691 lcand = c->lcand;
2692 break;
2693 }
2694 }
2695#else
2696 /* Just get candidate with the highest priority and same transport ID
2697 * for the specified component ID in the checklist.
2698 */
2699 for (i=0; i<ice->clist.count; ++i) {
2700 pj_ice_sess_check *c = &ice->clist.checks[i];
2701 if (c->lcand->comp_id == rcheck->comp_id &&
2702 c->lcand->transport_id == rcheck->transport_id)
2703 {
2704 lcand = c->lcand;
2705 break;
2706 }
2707 }
2708 if (lcand == NULL) {
2709 /* Should not happen, but just in case remote is sending a
2710 * Binding request for a component which it doesn't have.
2711 */
2712 LOG4((ice->obj_name,
2713 "Received Binding request but no local candidate is found!"));
2714 return;
2715 }
2716#endif
2717
2718 /*
2719 * Create candidate pair for this request.
2720 */
2721
2722 /*
2723 * 7.2.1.4. Triggered Checks
2724 *
2725 * Now that we have local and remote candidate, check if we already
2726 * have this pair in our checklist.
2727 */
2728 for (i=0; i<ice->clist.count; ++i) {
2729 pj_ice_sess_check *c = &ice->clist.checks[i];
2730 if (c->lcand == lcand && c->rcand == rcand)
2731 break;
2732 }
2733
2734 /* If the pair is already on the check list:
2735 * - If the state of that pair is Waiting or Frozen, its state is
2736 * changed to In-Progress and a check for that pair is performed
2737 * immediately. This is called a triggered check.
2738 *
2739 * - If the state of that pair is In-Progress, the agent SHOULD
2740 * generate an immediate retransmit of the Binding Request for the
2741 * check in progress. This is to facilitate rapid completion of
2742 * ICE when both agents are behind NAT.
2743 *
2744 * - If the state of that pair is Failed or Succeeded, no triggered
2745 * check is sent.
2746 */
2747 if (i != ice->clist.count) {
2748 pj_ice_sess_check *c = &ice->clist.checks[i];
2749
2750 /* If USE-CANDIDATE is present, set nominated flag
2751 * Note: DO NOT overwrite nominated flag if one is already set.
2752 */
2753 c->nominated = ((rcheck->use_candidate) || c->nominated);
2754
2755 if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN ||
2756 c->state == PJ_ICE_SESS_CHECK_STATE_WAITING)
2757 {
2758 /* See if we shall nominate this check */
2759 pj_bool_t nominate = (c->nominated || ice->is_nominating);
2760
2761 LOG5((ice->obj_name, "Performing triggered check for check %d",i));
2762 pj_log_push_indent();
2763 perform_check(ice, &ice->clist, i, nominate);
2764 pj_log_pop_indent();
2765
2766 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
2767 /* Should retransmit immediately
2768 */
2769 LOG5((ice->obj_name, "Triggered check for check %d not performed "
2770 "because it's in progress. Retransmitting", i));
2771 pj_log_push_indent();
2772 pj_stun_session_retransmit_req(comp->stun_sess, c->tdata, PJ_FALSE);
2773 pj_log_pop_indent();
2774
2775 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
2776 /* Check complete for this component.
2777 * Note this may end ICE process.
2778 */
2779 pj_bool_t complete;
2780 unsigned j;
2781
2782 /* If this check is nominated, scan the valid_list for the
2783 * same check and update the nominated flag. A controlled
2784 * agent might have finished the check earlier.
2785 */
2786 if (rcheck->use_candidate) {
2787 for (j=0; j<ice->valid_list.count; ++j) {
2788 pj_ice_sess_check *vc = &ice->valid_list.checks[j];
2789 if (vc->lcand->transport_id == c->lcand->transport_id &&
2790 vc->rcand == c->rcand)
2791 {
2792 /* Set nominated flag */
2793 vc->nominated = PJ_TRUE;
2794
2795 /* Update valid check and nominated check for the component */
2796 update_comp_check(ice, vc->lcand->comp_id, vc);
2797
2798 LOG5((ice->obj_name, "Valid check %s is nominated",
2799 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2800 &ice->valid_list, vc)));
2801 }
2802 }
2803 }
2804
2805 LOG5((ice->obj_name, "Triggered check for check %d not performed "
2806 "because it's completed", i));
2807 pj_log_push_indent();
2808 complete = on_check_complete(ice, c);
2809 pj_log_pop_indent();
2810 if (complete) {
2811 return;
2812 }
2813 }
2814
2815 }
2816 /* If the pair is not already on the check list:
2817 * - The pair is inserted into the check list based on its priority.
2818 * - Its state is set to In-Progress
2819 * - A triggered check for that pair is performed immediately.
2820 */
2821 /* Note: only do this if we don't have too many checks in checklist */
2822 else if (ice->clist.count < PJ_ICE_MAX_CHECKS) {
2823
2824 pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count];
2825 pj_bool_t nominate;
2826
2827 c->lcand = lcand;
2828 c->rcand = rcand;
2829 c->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
2830 c->state = PJ_ICE_SESS_CHECK_STATE_WAITING;
2831 c->nominated = rcheck->use_candidate;
2832 c->err_code = PJ_SUCCESS;
2833
2834 nominate = (c->nominated || ice->is_nominating);
2835
2836 LOG4((ice->obj_name, "New triggered check added: %d",
2837 ice->clist.count));
2838 pj_log_push_indent();
2839 perform_check(ice, &ice->clist, ice->clist.count++, nominate);
2840 pj_log_pop_indent();
2841
2842 } else {
2843 LOG4((ice->obj_name, "Error: unable to perform triggered check: "
2844 "TOO MANY CHECKS IN CHECKLIST!"));
2845 }
2846}
2847
2848
2849static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
2850 const pj_uint8_t *pkt,
2851 unsigned pkt_len,
2852 const pj_stun_msg *msg,
2853 void *token,
2854 const pj_sockaddr_t *src_addr,
2855 unsigned src_addr_len)
2856{
2857 struct stun_data *sd;
2858
2859 PJ_UNUSED_ARG(sess);
2860 PJ_UNUSED_ARG(pkt);
2861 PJ_UNUSED_ARG(pkt_len);
2862 PJ_UNUSED_ARG(msg);
2863 PJ_UNUSED_ARG(token);
2864 PJ_UNUSED_ARG(src_addr);
2865 PJ_UNUSED_ARG(src_addr_len);
2866
2867 sd = (struct stun_data*) pj_stun_session_get_user_data(sess);
2868
2869 pj_log_push_indent();
2870
2871 if (msg->hdr.type == PJ_STUN_BINDING_INDICATION) {
2872 LOG5((sd->ice->obj_name, "Received Binding Indication keep-alive "
2873 "for component %d", sd->comp_id));
2874 } else {
2875 LOG4((sd->ice->obj_name, "Received unexpected %s indication "
2876 "for component %d", pj_stun_get_method_name(msg->hdr.type),
2877 sd->comp_id));
2878 }
2879
2880 pj_log_pop_indent();
2881
2882 return PJ_SUCCESS;
2883}
2884
2885
2886PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
2887 unsigned comp_id,
2888 const void *data,
2889 pj_size_t data_len)
2890{
2891 pj_status_t status = PJ_SUCCESS;
2892 pj_ice_sess_comp *comp;
2893 pj_ice_sess_cand *cand;
2894 pj_uint8_t transport_id;
2895 pj_sockaddr addr;
2896
2897 PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
2898
2899 /* It is possible that comp_cnt is less than comp_id, when remote
2900 * doesn't support all the components that we have.
2901 */
2902 if (comp_id > ice->comp_cnt) {
2903 return PJNATH_EICEINCOMPID;
2904 }
2905
2906 pj_grp_lock_acquire(ice->grp_lock);
2907
2908 if (ice->is_destroying) {
2909 pj_grp_lock_release(ice->grp_lock);
2910 return PJ_EINVALIDOP;
2911 }
2912
2913 comp = find_comp(ice, comp_id);
2914 if (comp == NULL) {
2915 status = PJNATH_EICEINCOMPID;
2916 pj_grp_lock_release(ice->grp_lock);
2917 goto on_return;
2918 }
2919
2920 if (comp->valid_check == NULL) {
2921 status = PJNATH_EICEINPROGRESS;
2922 pj_grp_lock_release(ice->grp_lock);
2923 goto on_return;
2924 }
2925
2926 cand = comp->valid_check->lcand;
2927 transport_id = cand->transport_id;
2928 pj_sockaddr_cp(&addr, &comp->valid_check->rcand->addr);
2929
2930 /* Release the mutex now to avoid deadlock (see ticket #1451). */
2931 pj_grp_lock_release(ice->grp_lock);
2932
2933 PJ_RACE_ME(5);
2934
2935 status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id,
2936 data, data_len,
2937 &addr,
2938 pj_sockaddr_get_len(&addr));
2939
2940on_return:
2941 return status;
2942}
2943
2944
2945PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
2946 unsigned comp_id,
2947 unsigned transport_id,
2948 void *pkt,
2949 pj_size_t pkt_size,
2950 const pj_sockaddr_t *src_addr,
2951 int src_addr_len)
2952{
2953 pj_status_t status = PJ_SUCCESS;
2954 pj_ice_sess_comp *comp;
2955 pj_ice_msg_data *msg_data = NULL;
2956 unsigned i;
2957
2958 PJ_ASSERT_RETURN(ice, PJ_EINVAL);
2959
2960 pj_grp_lock_acquire(ice->grp_lock);
2961
2962 if (ice->is_destroying) {
2963 pj_grp_lock_release(ice->grp_lock);
2964 return PJ_EINVALIDOP;
2965 }
2966
2967 comp = find_comp(ice, comp_id);
2968 if (comp == NULL) {
2969 pj_grp_lock_release(ice->grp_lock);
2970 return PJNATH_EICEINCOMPID;
2971 }
2972
2973 /* Find transport */
2974 for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
2975 if (ice->tp_data[i].transport_id == transport_id) {
2976 msg_data = &ice->tp_data[i];
2977 break;
2978 }
2979 }
2980 if (msg_data == NULL) {
2981 pj_assert(!"Invalid transport ID");
2982 pj_grp_lock_release(ice->grp_lock);
2983 return PJ_EINVAL;
2984 }
2985
2986 /* Don't check fingerprint. We only need to distinguish STUN and non-STUN
2987 * packets. We don't need to verify the STUN packet too rigorously, that
2988 * will be done by the user.
2989 */
2990 status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size,
2991 PJ_STUN_IS_DATAGRAM |
2992 PJ_STUN_NO_FINGERPRINT_CHECK);
2993 if (status == PJ_SUCCESS) {
2994 status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
2995 PJ_STUN_IS_DATAGRAM, msg_data,
2996 NULL, src_addr, src_addr_len);
2997 if (status != PJ_SUCCESS) {
2998 pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg));
2999 LOG4((ice->obj_name, "Error processing incoming message: %s",
3000 ice->tmp.errmsg));
3001 }
3002 pj_grp_lock_release(ice->grp_lock);
3003 } else {
3004 /* Not a STUN packet. Call application's callback instead, but release
3005 * the mutex now or otherwise we may get deadlock.
3006 */
3007 pj_grp_lock_release(ice->grp_lock);
3008
3009 PJ_RACE_ME(5);
3010
3011 (*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size,
3012 src_addr, src_addr_len);
3013 status = PJ_SUCCESS;
3014 }
3015
3016 return status;
3017}
3018
3019