blob: a40687143b85856ec716f7601d3d0671ff9b84ef [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $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[PJ_ICE_CAND_TYPE_MAX] =
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_ICE_CAND_TYPE_MAX,
549 sizeof(pj_uint8_t));
550 for (i=0; i<PJ_ICE_CAND_TYPE_MAX; ++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 len = pj_ansi_snprintf(buffer, bufsize,
903 "%d: [%d] %s:%d-->%s:%d",
904 (int)GET_CHECK_ID(clist, check),
905 check->lcand->comp_id,
906 pj_sockaddr_print(&lcand->addr, laddr,
907 sizeof(laddr), 0),
908 pj_sockaddr_get_port(&lcand->addr),
909 pj_sockaddr_print(&rcand->addr, raddr,
910 sizeof(raddr), 0),
911 pj_sockaddr_get_port(&rcand->addr));
912
913 if (len < 0)
914 len = 0;
915 else if (len >= (int)bufsize)
916 len = bufsize - 1;
917
918 buffer[len] = '\0';
919 return buffer;
920}
921
922static void dump_checklist(const char *title, pj_ice_sess *ice,
923 const pj_ice_sess_checklist *clist)
924{
925 unsigned i;
926
927 LOG4((ice->obj_name, "%s", title));
928 for (i=0; i<clist->count; ++i) {
929 const pj_ice_sess_check *c = &clist->checks[i];
930 LOG4((ice->obj_name, " %s (%s, state=%s)",
931 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, c),
932 (c->nominated ? "nominated" : "not nominated"),
933 check_state_name[c->state]));
934 }
935}
936
937#else
938#define dump_checklist(title, ice, clist)
939#endif
940
941static void check_set_state(pj_ice_sess *ice, pj_ice_sess_check *check,
942 pj_ice_sess_check_state st,
943 pj_status_t err_code)
944{
945 pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
946
947 LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
948 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), &ice->clist, check),
949 check_state_name[check->state],
950 check_state_name[st]));
951 check->state = st;
952 check->err_code = err_code;
953}
954
955static void clist_set_state(pj_ice_sess *ice, pj_ice_sess_checklist *clist,
956 pj_ice_sess_checklist_state st)
957{
958 if (clist->state != st) {
959 LOG5((ice->obj_name, "Checklist: state changed from %s to %s",
960 clist_state_name[clist->state],
961 clist_state_name[st]));
962 clist->state = st;
963 }
964}
965
966/* Sort checklist based on priority */
967static void sort_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist)
968{
969 unsigned i;
970 pj_ice_sess_check **check_ptr[PJ_ICE_MAX_COMP*2];
971 unsigned check_ptr_cnt = 0;
972
973 for (i=0; i<ice->comp_cnt; ++i) {
974 if (ice->comp[i].valid_check) {
975 check_ptr[check_ptr_cnt++] = &ice->comp[i].valid_check;
976 }
977 if (ice->comp[i].nominated_check) {
978 check_ptr[check_ptr_cnt++] = &ice->comp[i].nominated_check;
979 }
980 }
981
982 pj_assert(clist->count > 0);
983 for (i=0; i<clist->count-1; ++i) {
984 unsigned j, highest = i;
985
986 for (j=i+1; j<clist->count; ++j) {
987 if (CMP_CHECK_PRIO(&clist->checks[j], &clist->checks[highest]) > 0) {
988 highest = j;
989 }
990 }
991
992 if (highest != i) {
993 pj_ice_sess_check tmp;
994 unsigned k;
995
996 pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_sess_check));
997 pj_memcpy(&clist->checks[i], &clist->checks[highest],
998 sizeof(pj_ice_sess_check));
999 pj_memcpy(&clist->checks[highest], &tmp,
1000 sizeof(pj_ice_sess_check));
1001
1002 /* Update valid and nominated check pointers, since we're moving
1003 * around checks
1004 */
1005 for (k=0; k<check_ptr_cnt; ++k) {
1006 if (*check_ptr[k] == &clist->checks[highest])
1007 *check_ptr[k] = &clist->checks[i];
1008 else if (*check_ptr[k] == &clist->checks[i])
1009 *check_ptr[k] = &clist->checks[highest];
1010 }
1011 }
1012 }
1013}
1014
1015/* Prune checklist, this must have been done after the checklist
1016 * is sorted.
1017 */
1018static pj_status_t prune_checklist(pj_ice_sess *ice,
1019 pj_ice_sess_checklist *clist)
1020{
1021 unsigned i;
1022
1023 /* Since an agent cannot send requests directly from a reflexive
1024 * candidate, but only from its base, the agent next goes through the
1025 * sorted list of candidate pairs. For each pair where the local
1026 * candidate is server reflexive, the server reflexive candidate MUST be
1027 * replaced by its base. Once this has been done, the agent MUST prune
1028 * the list. This is done by removing a pair if its local and remote
1029 * candidates are identical to the local and remote candidates of a pair
1030 * higher up on the priority list. The result is a sequence of ordered
1031 * candidate pairs, called the check list for that media stream.
1032 */
1033 /* First replace SRFLX candidates with their base */
1034 for (i=0; i<clist->count; ++i) {
1035 pj_ice_sess_cand *srflx = clist->checks[i].lcand;
1036
1037 if (clist->checks[i].lcand->type == PJ_ICE_CAND_TYPE_SRFLX) {
1038 /* Find the base for this candidate */
1039 unsigned j;
1040 for (j=0; j<ice->lcand_cnt; ++j) {
1041 pj_ice_sess_cand *host = &ice->lcand[j];
1042
1043 if (host->type != PJ_ICE_CAND_TYPE_HOST)
1044 continue;
1045
1046 if (pj_sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) {
1047 /* Replace this SRFLX with its BASE */
1048 clist->checks[i].lcand = host;
1049 break;
1050 }
1051 }
1052
1053 if (j==ice->lcand_cnt) {
1054 char baddr[PJ_INET6_ADDRSTRLEN];
1055 /* Host candidate not found this this srflx! */
1056 LOG4((ice->obj_name,
1057 "Base candidate %s:%d not found for srflx candidate %d",
1058 pj_sockaddr_print(&srflx->base_addr, baddr,
1059 sizeof(baddr), 0),
1060 pj_sockaddr_get_port(&srflx->base_addr),
1061 GET_LCAND_ID(clist->checks[i].lcand)));
1062 return PJNATH_EICENOHOSTCAND;
1063 }
1064 }
1065 }
1066
1067 /* Next remove a pair if its local and remote candidates are identical
1068 * to the local and remote candidates of a pair higher up on the priority
1069 * list
1070 */
1071 /*
1072 * Not in ICE!
1073 * Remove host candidates if their base are the the same!
1074 */
1075 for (i=0; i<clist->count; ++i) {
1076 pj_ice_sess_cand *licand = clist->checks[i].lcand;
1077 pj_ice_sess_cand *ricand = clist->checks[i].rcand;
1078 unsigned j;
1079
1080 for (j=i+1; j<clist->count;) {
1081 pj_ice_sess_cand *ljcand = clist->checks[j].lcand;
1082 pj_ice_sess_cand *rjcand = clist->checks[j].rcand;
1083 const char *reason = NULL;
1084
1085 if ((licand == ljcand) && (ricand == rjcand)) {
1086 reason = "duplicate found";
1087 } else if ((rjcand == ricand) &&
1088 (pj_sockaddr_cmp(&ljcand->base_addr,
1089 &licand->base_addr)==0))
1090 {
1091 reason = "equal base";
1092 }
1093
1094 if (reason != NULL) {
1095 /* Found duplicate, remove it */
1096 LOG5((ice->obj_name, "Check %s pruned (%s)",
1097 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1098 &ice->clist, &clist->checks[j]),
1099 reason));
1100
1101 pj_array_erase(clist->checks, sizeof(clist->checks[0]),
1102 clist->count, j);
1103 --clist->count;
1104
1105 } else {
1106 ++j;
1107 }
1108 }
1109 }
1110
1111 return PJ_SUCCESS;
1112}
1113
1114/* Timer callback */
1115static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te)
1116{
1117 pj_ice_sess *ice = (pj_ice_sess*) te->user_data;
1118 enum timer_type type = (enum timer_type)te->id;
1119
1120 PJ_UNUSED_ARG(th);
1121
1122 pj_grp_lock_acquire(ice->grp_lock);
1123
1124 te->id = TIMER_NONE;
1125
1126 if (ice->is_destroying) {
1127 /* Stray timer, could happen when destroy is invoked while callback
1128 * is pending. */
1129 pj_grp_lock_release(ice->grp_lock);
1130 return;
1131 }
1132
1133 switch (type) {
1134 case TIMER_CONTROLLED_WAIT_NOM:
1135 LOG4((ice->obj_name,
1136 "Controlled agent timed-out in waiting for the controlling "
1137 "agent to send nominated check. Setting state to fail now.."));
1138 on_ice_complete(ice, PJNATH_EICENOMTIMEOUT);
1139 break;
1140 case TIMER_COMPLETION_CALLBACK:
1141 {
1142 void (*on_ice_complete)(pj_ice_sess *ice, pj_status_t status);
1143 pj_status_t ice_status;
1144
1145 /* Start keep-alive timer but don't send any packets yet.
1146 * Need to do it here just in case app destroy the session
1147 * in the callback.
1148 */
1149 if (ice->ice_status == PJ_SUCCESS)
1150 ice_keep_alive(ice, PJ_FALSE);
1151
1152 /* Release mutex in case app destroy us in the callback */
1153 ice_status = ice->ice_status;
1154 on_ice_complete = ice->cb.on_ice_complete;
1155
1156 /* Notify app about ICE completion*/
1157 if (on_ice_complete)
1158 (*on_ice_complete)(ice, ice_status);
1159 }
1160 break;
1161 case TIMER_START_NOMINATED_CHECK:
1162 start_nominated_check(ice);
1163 break;
1164 case TIMER_KEEP_ALIVE:
1165 ice_keep_alive(ice, PJ_TRUE);
1166 break;
1167 case TIMER_NONE:
1168 /* Nothing to do, just to get rid of gcc warning */
1169 break;
1170 }
1171
1172 pj_grp_lock_release(ice->grp_lock);
1173}
1174
1175/* Send keep-alive */
1176static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now)
1177{
1178 if (send_now) {
1179 /* Send Binding Indication for the component */
1180 pj_ice_sess_comp *comp = &ice->comp[ice->comp_ka];
1181 pj_stun_tx_data *tdata;
1182 pj_ice_sess_check *the_check;
1183 pj_ice_msg_data *msg_data;
1184 int addr_len;
1185 pj_bool_t saved;
1186 pj_status_t status;
1187
1188 /* Must have nominated check by now */
1189 pj_assert(comp->nominated_check != NULL);
1190 the_check = comp->nominated_check;
1191
1192 /* Create the Binding Indication */
1193 status = pj_stun_session_create_ind(comp->stun_sess,
1194 PJ_STUN_BINDING_INDICATION,
1195 &tdata);
1196 if (status != PJ_SUCCESS)
1197 goto done;
1198
1199 /* Need the transport_id */
1200 msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
1201 msg_data->transport_id = the_check->lcand->transport_id;
1202
1203 /* Temporarily disable FINGERPRINT. The Binding Indication
1204 * SHOULD NOT contain any attributes.
1205 */
1206 saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_FALSE);
1207
1208 /* Send to session */
1209 addr_len = pj_sockaddr_get_len(&the_check->rcand->addr);
1210 status = pj_stun_session_send_msg(comp->stun_sess, msg_data,
1211 PJ_FALSE, PJ_FALSE,
1212 &the_check->rcand->addr,
1213 addr_len, tdata);
1214
1215 /* Restore FINGERPRINT usage */
1216 pj_stun_session_use_fingerprint(comp->stun_sess, saved);
1217
1218done:
1219 ice->comp_ka = (ice->comp_ka + 1) % ice->comp_cnt;
1220 }
1221
1222 if (ice->timer.id == TIMER_NONE) {
1223 pj_time_val delay = { 0, 0 };
1224
1225 delay.msec = (PJ_ICE_SESS_KEEP_ALIVE_MIN +
1226 (pj_rand() % PJ_ICE_SESS_KEEP_ALIVE_MAX_RAND)) * 1000 /
1227 ice->comp_cnt;
1228 pj_time_val_normalize(&delay);
1229
1230 pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1231 &ice->timer, &delay,
1232 TIMER_KEEP_ALIVE,
1233 ice->grp_lock);
1234
1235 } else {
1236 pj_assert(!"Not expected any timer active");
1237 }
1238}
1239
1240/* This function is called when ICE processing completes */
1241static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
1242{
1243 if (!ice->is_complete) {
1244 ice->is_complete = PJ_TRUE;
1245 ice->ice_status = status;
1246
1247 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer,
1248 TIMER_NONE);
1249
1250 /* Log message */
1251 LOG4((ice->obj_name, "ICE process complete, status=%s",
1252 pj_strerror(status, ice->tmp.errmsg,
1253 sizeof(ice->tmp.errmsg)).ptr));
1254
1255 dump_checklist("Valid list", ice, &ice->valid_list);
1256
1257 /* Call callback */
1258 if (ice->cb.on_ice_complete) {
1259 pj_time_val delay = {0, 0};
1260
1261 pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1262 &ice->timer, &delay,
1263 TIMER_COMPLETION_CALLBACK,
1264 ice->grp_lock);
1265 }
1266 }
1267}
1268
1269/* Update valid check and nominated check for the candidate */
1270static void update_comp_check(pj_ice_sess *ice, unsigned comp_id,
1271 pj_ice_sess_check *check)
1272{
1273 pj_ice_sess_comp *comp;
1274
1275 comp = find_comp(ice, comp_id);
1276 if (comp->valid_check == NULL) {
1277 comp->valid_check = check;
1278 } else {
1279 if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
1280 comp->valid_check = check;
1281 }
1282
1283 if (check->nominated) {
1284 /* Update the nominated check for the component */
1285 if (comp->nominated_check == NULL) {
1286 comp->nominated_check = check;
1287 } else {
1288 if (CMP_CHECK_PRIO(comp->nominated_check, check) < 0)
1289 comp->nominated_check = check;
1290 }
1291 }
1292}
1293
1294/* This function is called when one check completes */
1295static pj_bool_t on_check_complete(pj_ice_sess *ice,
1296 pj_ice_sess_check *check)
1297{
1298 pj_ice_sess_comp *comp;
1299 unsigned i;
1300
1301 pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
1302
1303 comp = find_comp(ice, check->lcand->comp_id);
1304
1305 /* 7.1.2.2.2. Updating Pair States
1306 *
1307 * The agent sets the state of the pair that generated the check to
1308 * Succeeded. The success of this check might also cause the state of
1309 * other checks to change as well. The agent MUST perform the following
1310 * two steps:
1311 *
1312 * 1. The agent changes the states for all other Frozen pairs for the
1313 * same media stream and same foundation to Waiting. Typically
1314 * these other pairs will have different component IDs but not
1315 * always.
1316 */
1317 if (check->err_code==PJ_SUCCESS) {
1318
1319 for (i=0; i<ice->clist.count; ++i) {
1320 pj_ice_sess_check *c = &ice->clist.checks[i];
1321 if (pj_strcmp(&c->lcand->foundation, &check->lcand->foundation)==0
1322 && c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN)
1323 {
1324 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
1325 }
1326 }
1327
1328 LOG5((ice->obj_name, "Check %d is successful%s",
1329 GET_CHECK_ID(&ice->clist, check),
1330 (check->nominated ? " and nominated" : "")));
1331
1332 }
1333
1334 /* 8.2. Updating States
1335 *
1336 * For both controlling and controlled agents, the state of ICE
1337 * processing depends on the presence of nominated candidate pairs in
1338 * the valid list and on the state of the check list:
1339 *
1340 * o If there are no nominated pairs in the valid list for a media
1341 * stream and the state of the check list is Running, ICE processing
1342 * continues.
1343 *
1344 * o If there is at least one nominated pair in the valid list:
1345 *
1346 * - The agent MUST remove all Waiting and Frozen pairs in the check
1347 * list for the same component as the nominated pairs for that
1348 * media stream
1349 *
1350 * - If an In-Progress pair in the check list is for the same
1351 * component as a nominated pair, the agent SHOULD cease
1352 * retransmissions for its check if its pair priority is lower
1353 * than the lowest priority nominated pair for that component
1354 */
1355 if (check->err_code==PJ_SUCCESS && check->nominated) {
1356
1357 for (i=0; i<ice->clist.count; ++i) {
1358
1359 pj_ice_sess_check *c = &ice->clist.checks[i];
1360
1361 if (c->lcand->comp_id == check->lcand->comp_id) {
1362
1363 if (c->state < PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
1364
1365 /* Just fail Frozen/Waiting check */
1366 LOG5((ice->obj_name,
1367 "Check %s to be failed because state is %s",
1368 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1369 &ice->clist, c),
1370 check_state_name[c->state]));
1371 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
1372 PJ_ECANCELLED);
1373
1374 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS
1375 && (PJ_ICE_CANCEL_ALL ||
1376 CMP_CHECK_PRIO(c, check) < 0)) {
1377
1378 /* State is IN_PROGRESS, cancel transaction */
1379 if (c->tdata) {
1380 LOG5((ice->obj_name,
1381 "Cancelling check %s (In Progress)",
1382 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
1383 &ice->clist, c)));
1384 pj_stun_session_cancel_req(comp->stun_sess,
1385 c->tdata, PJ_FALSE, 0);
1386 c->tdata = NULL;
1387 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
1388 PJ_ECANCELLED);
1389 }
1390 }
1391 }
1392 }
1393 }
1394
1395
1396 /* Still in 8.2. Updating States
1397 *
1398 * o Once there is at least one nominated pair in the valid list for
1399 * every component of at least one media stream and the state of the
1400 * check list is Running:
1401 *
1402 * * The agent MUST change the state of processing for its check
1403 * list for that media stream to Completed.
1404 *
1405 * * The agent MUST continue to respond to any checks it may still
1406 * receive for that media stream, and MUST perform triggered
1407 * checks if required by the processing of Section 7.2.
1408 *
1409 * * The agent MAY begin transmitting media for this media stream as
1410 * described in Section 11.1
1411 */
1412
1413 /* See if all components have nominated pair. If they do, then mark
1414 * ICE processing as success, otherwise wait.
1415 */
1416 for (i=0; i<ice->comp_cnt; ++i) {
1417 if (ice->comp[i].nominated_check == NULL)
1418 break;
1419 }
1420 if (i == ice->comp_cnt) {
1421 /* All components have nominated pair */
1422 on_ice_complete(ice, PJ_SUCCESS);
1423 return PJ_TRUE;
1424 }
1425
1426 /* Note: this is the stuffs that we don't do in 7.1.2.2.2, since our
1427 * ICE session only supports one media stream for now:
1428 *
1429 * 7.1.2.2.2. Updating Pair States
1430 *
1431 * 2. If there is a pair in the valid list for every component of this
1432 * media stream (where this is the actual number of components being
1433 * used, in cases where the number of components signaled in the SDP
1434 * differs from offerer to answerer), the success of this check may
1435 * unfreeze checks for other media streams.
1436 */
1437
1438 /* 7.1.2.3. Check List and Timer State Updates
1439 * Regardless of whether the check was successful or failed, the
1440 * completion of the transaction may require updating of check list and
1441 * timer states.
1442 *
1443 * If all of the pairs in the check list are now either in the Failed or
1444 * Succeeded state, and there is not a pair in the valid list for each
1445 * component of the media stream, the state of the check list is set to
1446 * Failed.
1447 */
1448
1449 /*
1450 * See if all checks in the checklist have completed. If we do,
1451 * then mark ICE processing as failed.
1452 */
1453 for (i=0; i<ice->clist.count; ++i) {
1454 pj_ice_sess_check *c = &ice->clist.checks[i];
1455 if (c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
1456 break;
1457 }
1458 }
1459
1460 if (i == ice->clist.count) {
1461 /* All checks have completed, but we don't have nominated pair.
1462 * If agent's role is controlled, check if all components have
1463 * valid pair. If it does, this means the controlled agent has
1464 * finished the check list and it's waiting for controlling
1465 * agent to send checks with USE-CANDIDATE flag set.
1466 */
1467 if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED) {
1468 for (i=0; i < ice->comp_cnt; ++i) {
1469 if (ice->comp[i].valid_check == NULL)
1470 break;
1471 }
1472
1473 if (i < ice->comp_cnt) {
1474 /* This component ID doesn't have valid pair.
1475 * Mark ICE as failed.
1476 */
1477 on_ice_complete(ice, PJNATH_EICEFAILED);
1478 return PJ_TRUE;
1479 } else {
1480 /* All components have a valid pair.
1481 * We should wait until we receive nominated checks.
1482 */
1483 if (ice->timer.id == TIMER_NONE &&
1484 ice->opt.controlled_agent_want_nom_timeout >= 0)
1485 {
1486 pj_time_val delay;
1487
1488 delay.sec = 0;
1489 delay.msec = ice->opt.controlled_agent_want_nom_timeout;
1490 pj_time_val_normalize(&delay);
1491
1492 pj_timer_heap_schedule_w_grp_lock(
1493 ice->stun_cfg.timer_heap,
1494 &ice->timer, &delay,
1495 TIMER_CONTROLLED_WAIT_NOM,
1496 ice->grp_lock);
1497
1498 LOG5((ice->obj_name,
1499 "All checks have completed. Controlled agent now "
1500 "waits for nomination from controlling agent "
1501 "(timeout=%d msec)",
1502 ice->opt.controlled_agent_want_nom_timeout));
1503 }
1504 return PJ_FALSE;
1505 }
1506
1507 /* Unreached */
1508
1509 } else if (ice->is_nominating) {
1510 /* We are controlling agent and all checks have completed but
1511 * there's at least one component without nominated pair (or
1512 * more likely we don't have any nominated pairs at all).
1513 */
1514 on_ice_complete(ice, PJNATH_EICEFAILED);
1515 return PJ_TRUE;
1516
1517 } else {
1518 /* We are controlling agent and all checks have completed. If
1519 * we have valid list for every component, then move on to
1520 * sending nominated check, otherwise we have failed.
1521 */
1522 for (i=0; i<ice->comp_cnt; ++i) {
1523 if (ice->comp[i].valid_check == NULL)
1524 break;
1525 }
1526
1527 if (i < ice->comp_cnt) {
1528 /* At least one component doesn't have a valid check. Mark
1529 * ICE as failed.
1530 */
1531 on_ice_complete(ice, PJNATH_EICEFAILED);
1532 return PJ_TRUE;
1533 }
1534
1535 /* Now it's time to send connectivity check with nomination
1536 * flag set.
1537 */
1538 LOG4((ice->obj_name,
1539 "All checks have completed, starting nominated checks now"));
1540 start_nominated_check(ice);
1541 return PJ_FALSE;
1542 }
1543 }
1544
1545 /* If this connectivity check has been successful, scan all components
1546 * and see if they have a valid pair, if we are controlling and we haven't
1547 * started our nominated check yet.
1548 */
1549 if (check->err_code == PJ_SUCCESS &&
1550 ice->role==PJ_ICE_SESS_ROLE_CONTROLLING &&
1551 !ice->is_nominating &&
1552 ice->timer.id == TIMER_NONE)
1553 {
1554 pj_time_val delay;
1555
1556 for (i=0; i<ice->comp_cnt; ++i) {
1557 if (ice->comp[i].valid_check == NULL)
1558 break;
1559 }
1560
1561 if (i < ice->comp_cnt) {
1562 /* Some components still don't have valid pair, continue
1563 * processing.
1564 */
1565 return PJ_FALSE;
1566 }
1567
1568 LOG4((ice->obj_name,
1569 "Scheduling nominated check in %d ms",
1570 ice->opt.nominated_check_delay));
1571
1572 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer,
1573 TIMER_NONE);
1574
1575 /* All components have valid pair. Let connectivity checks run for
1576 * a little bit more time, then start our nominated check.
1577 */
1578 delay.sec = 0;
1579 delay.msec = ice->opt.nominated_check_delay;
1580 pj_time_val_normalize(&delay);
1581
1582 pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1583 &ice->timer, &delay,
1584 TIMER_START_NOMINATED_CHECK,
1585 ice->grp_lock);
1586 return PJ_FALSE;
1587 }
1588
1589 /* We still have checks to perform */
1590 return PJ_FALSE;
1591}
1592
1593
1594/* Create checklist by pairing local candidates with remote candidates */
1595PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
1596 pj_ice_sess *ice,
1597 const pj_str_t *rem_ufrag,
1598 const pj_str_t *rem_passwd,
1599 unsigned rcand_cnt,
1600 const pj_ice_sess_cand rcand[])
1601{
1602 pj_ice_sess_checklist *clist;
1603 char buf[128];
1604 pj_str_t username;
1605 timer_data *td;
1606 unsigned i, j;
1607 unsigned highest_comp = 0;
1608 pj_status_t status;
1609
1610 PJ_ASSERT_RETURN(ice && rem_ufrag && rem_passwd && rcand_cnt && rcand,
1611 PJ_EINVAL);
1612 PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND,
1613 PJ_ETOOMANY);
1614
1615 pj_grp_lock_acquire(ice->grp_lock);
1616
1617 /* Save credentials */
1618 username.ptr = buf;
1619
1620 pj_strcpy(&username, rem_ufrag);
1621 pj_strcat2(&username, ":");
1622 pj_strcat(&username, &ice->rx_ufrag);
1623
1624 pj_strdup(ice->pool, &ice->tx_uname, &username);
1625 pj_strdup(ice->pool, &ice->tx_ufrag, rem_ufrag);
1626 pj_strdup(ice->pool, &ice->tx_pass, rem_passwd);
1627
1628 pj_strcpy(&username, &ice->rx_ufrag);
1629 pj_strcat2(&username, ":");
1630 pj_strcat(&username, rem_ufrag);
1631
1632 pj_strdup(ice->pool, &ice->rx_uname, &username);
1633
1634
1635 /* Save remote candidates */
1636 ice->rcand_cnt = 0;
1637 for (i=0; i<rcand_cnt; ++i) {
1638 pj_ice_sess_cand *cn = &ice->rcand[ice->rcand_cnt];
1639
1640 /* Ignore candidate which has no matching component ID */
1641 if (rcand[i].comp_id==0 || rcand[i].comp_id > ice->comp_cnt) {
1642 continue;
1643 }
1644
1645 if (rcand[i].comp_id > highest_comp)
1646 highest_comp = rcand[i].comp_id;
1647
1648 pj_memcpy(cn, &rcand[i], sizeof(pj_ice_sess_cand));
1649 pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation);
1650 ice->rcand_cnt++;
1651 }
1652
1653 /* Generate checklist */
1654 clist = &ice->clist;
1655 for (i=0; i<ice->lcand_cnt; ++i) {
1656 for (j=0; j<ice->rcand_cnt; ++j) {
1657
1658 pj_ice_sess_cand *lcand = &ice->lcand[i];
1659 pj_ice_sess_cand *rcand = &ice->rcand[j];
1660 pj_ice_sess_check *chk = &clist->checks[clist->count];
1661
1662 if (clist->count >= PJ_ICE_MAX_CHECKS) {
1663 pj_grp_lock_release(ice->grp_lock);
1664 return PJ_ETOOMANY;
1665 }
1666
1667 /* A local candidate is paired with a remote candidate if
1668 * and only if the two candidates have the same component ID
1669 * and have the same IP address version.
1670 */
1671 if ((lcand->comp_id != rcand->comp_id) ||
1672 (lcand->addr.addr.sa_family != rcand->addr.addr.sa_family))
1673 {
1674 continue;
1675 }
1676
1677
1678 chk->lcand = lcand;
1679 chk->rcand = rcand;
1680 chk->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
1681
1682 chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
1683
1684 clist->count++;
1685 }
1686 }
1687
1688 /* This could happen if candidates have no matching address families */
1689 if (clist->count == 0) {
1690 LOG4((ice->obj_name, "Error: no checklist can be created"));
1691 pj_grp_lock_release(ice->grp_lock);
1692 return PJ_ENOTFOUND;
1693 }
1694
1695 /* Sort checklist based on priority */
1696 sort_checklist(ice, clist);
1697
1698 /* Prune the checklist */
1699 status = prune_checklist(ice, clist);
1700 if (status != PJ_SUCCESS) {
1701 pj_grp_lock_release(ice->grp_lock);
1702 return status;
1703 }
1704
1705 /* Disable our components which don't have matching component */
1706 for (i=highest_comp; i<ice->comp_cnt; ++i) {
1707 if (ice->comp[i].stun_sess) {
1708 pj_stun_session_destroy(ice->comp[i].stun_sess);
1709 pj_bzero(&ice->comp[i], sizeof(ice->comp[i]));
1710 }
1711 }
1712 ice->comp_cnt = highest_comp;
1713
1714 /* Init timer entry in the checklist. Initially the timer ID is FALSE
1715 * because timer is not running.
1716 */
1717 clist->timer.id = PJ_FALSE;
1718 td = PJ_POOL_ZALLOC_T(ice->pool, timer_data);
1719 td->ice = ice;
1720 td->clist = clist;
1721 clist->timer.user_data = (void*)td;
1722 clist->timer.cb = &periodic_timer;
1723
1724
1725 /* Log checklist */
1726 dump_checklist("Checklist created:", ice, clist);
1727
1728 pj_grp_lock_release(ice->grp_lock);
1729
1730 return PJ_SUCCESS;
1731}
1732
1733/* Perform check on the specified candidate pair. */
1734static pj_status_t perform_check(pj_ice_sess *ice,
1735 pj_ice_sess_checklist *clist,
1736 unsigned check_id,
1737 pj_bool_t nominate)
1738{
1739 pj_ice_sess_comp *comp;
1740 pj_ice_msg_data *msg_data;
1741 pj_ice_sess_check *check;
1742 const pj_ice_sess_cand *lcand;
1743 const pj_ice_sess_cand *rcand;
1744 pj_uint32_t prio;
1745 pj_status_t status;
1746
1747 check = &clist->checks[check_id];
1748 lcand = check->lcand;
1749 rcand = check->rcand;
1750 comp = find_comp(ice, lcand->comp_id);
1751
1752 LOG5((ice->obj_name,
1753 "Sending connectivity check for check %s",
1754 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, check)));
1755 pj_log_push_indent();
1756
1757 /* Create request */
1758 status = pj_stun_session_create_req(comp->stun_sess,
1759 PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC,
1760 NULL, &check->tdata);
1761 if (status != PJ_SUCCESS) {
1762 pjnath_perror(ice->obj_name, "Error creating STUN request", status);
1763 pj_log_pop_indent();
1764 return status;
1765 }
1766
1767 /* Attach data to be retrieved later when STUN request transaction
1768 * completes and on_stun_request_complete() callback is called.
1769 */
1770 msg_data = PJ_POOL_ZALLOC_T(check->tdata->pool, pj_ice_msg_data);
1771 msg_data->transport_id = lcand->transport_id;
1772 msg_data->has_req_data = PJ_TRUE;
1773 msg_data->data.req.ice = ice;
1774 msg_data->data.req.clist = clist;
1775 msg_data->data.req.ckid = check_id;
1776
1777 /* Add PRIORITY */
1778#if PJNATH_ICE_PRIO_STD
1779 prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535,
1780 lcand->comp_id);
1781#else
1782 prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 0,
1783 lcand->comp_id);
1784#endif
1785 pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg,
1786 PJ_STUN_ATTR_PRIORITY, prio);
1787
1788 /* Add USE-CANDIDATE and set this check to nominated.
1789 * Also add ICE-CONTROLLING or ICE-CONTROLLED
1790 */
1791 if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
1792 if (nominate) {
1793 pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg,
1794 PJ_STUN_ATTR_USE_CANDIDATE);
1795 check->nominated = PJ_TRUE;
1796 }
1797
1798 pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,
1799 PJ_STUN_ATTR_ICE_CONTROLLING,
1800 &ice->tie_breaker);
1801
1802 } else {
1803 pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,
1804 PJ_STUN_ATTR_ICE_CONTROLLED,
1805 &ice->tie_breaker);
1806 }
1807
1808
1809 /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the
1810 * STUN session.
1811 */
1812
1813 /* Initiate STUN transaction to send the request */
1814 status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE,
1815 PJ_TRUE, &rcand->addr,
1816 pj_sockaddr_get_len(&rcand->addr),
1817 check->tdata);
1818 if (status != PJ_SUCCESS) {
1819 check->tdata = NULL;
1820 pjnath_perror(ice->obj_name, "Error sending STUN request", status);
1821 pj_log_pop_indent();
1822 return status;
1823 }
1824
1825 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS,
1826 PJ_SUCCESS);
1827 pj_log_pop_indent();
1828 return PJ_SUCCESS;
1829}
1830
1831
1832/* Start periodic check for the specified checklist.
1833 * This callback is called by timer on every Ta (20msec by default)
1834 */
1835static pj_status_t start_periodic_check(pj_timer_heap_t *th,
1836 pj_timer_entry *te)
1837{
1838 timer_data *td;
1839 pj_ice_sess *ice;
1840 pj_ice_sess_checklist *clist;
1841 unsigned i, start_count=0;
1842 pj_status_t status;
1843
1844 td = (struct timer_data*) te->user_data;
1845 ice = td->ice;
1846 clist = td->clist;
1847
1848 pj_grp_lock_acquire(ice->grp_lock);
1849
1850 if (ice->is_destroying) {
1851 pj_grp_lock_release(ice->grp_lock);
1852 return PJ_SUCCESS;
1853 }
1854
1855 /* Set timer ID to FALSE first */
1856 te->id = PJ_FALSE;
1857
1858 /* Set checklist state to Running */
1859 clist_set_state(ice, clist, PJ_ICE_SESS_CHECKLIST_ST_RUNNING);
1860
1861 LOG5((ice->obj_name, "Starting checklist periodic check"));
1862 pj_log_push_indent();
1863
1864 /* Send STUN Binding request for check with highest priority on
1865 * Waiting state.
1866 */
1867 for (i=0; i<clist->count; ++i) {
1868 pj_ice_sess_check *check = &clist->checks[i];
1869
1870 if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
1871 status = perform_check(ice, clist, i, ice->is_nominating);
1872 if (status != PJ_SUCCESS) {
1873 pj_grp_lock_release(ice->grp_lock);
1874 pj_log_pop_indent();
1875 return status;
1876 }
1877
1878 ++start_count;
1879 break;
1880 }
1881 }
1882
1883 /* If we don't have anything in Waiting state, perform check to
1884 * highest priority pair that is in Frozen state.
1885 */
1886 if (start_count==0) {
1887 for (i=0; i<clist->count; ++i) {
1888 pj_ice_sess_check *check = &clist->checks[i];
1889
1890 if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
1891 status = perform_check(ice, clist, i, ice->is_nominating);
1892 if (status != PJ_SUCCESS) {
1893 pj_grp_lock_release(ice->grp_lock);
1894 pj_log_pop_indent();
1895 return status;
1896 }
1897
1898 ++start_count;
1899 break;
1900 }
1901 }
1902 }
1903
1904 /* Cannot start check because there's no suitable candidate pair.
1905 */
1906 if (start_count!=0) {
1907 /* Schedule for next timer */
1908 pj_time_val timeout = {0, PJ_ICE_TA_VAL};
1909
1910 pj_time_val_normalize(&timeout);
1911 pj_timer_heap_schedule_w_grp_lock(th, te, &timeout, PJ_TRUE,
1912 ice->grp_lock);
1913 }
1914
1915 pj_grp_lock_release(ice->grp_lock);
1916 pj_log_pop_indent();
1917 return PJ_SUCCESS;
1918}
1919
1920
1921/* Start sending connectivity check with USE-CANDIDATE */
1922static void start_nominated_check(pj_ice_sess *ice)
1923{
1924 pj_time_val delay;
1925 unsigned i;
1926 pj_status_t status;
1927
1928 LOG4((ice->obj_name, "Starting nominated check.."));
1929 pj_log_push_indent();
1930
1931 pj_assert(ice->is_nominating == PJ_FALSE);
1932
1933 /* Stop our timer if it's active */
1934 if (ice->timer.id == TIMER_START_NOMINATED_CHECK) {
1935 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer,
1936 TIMER_NONE);
1937 }
1938
1939 /* For each component, set the check state of valid check with
1940 * highest priority to Waiting (it should have Success state now).
1941 */
1942 for (i=0; i<ice->comp_cnt; ++i) {
1943 unsigned j;
1944 const pj_ice_sess_check *vc = ice->comp[i].valid_check;
1945
1946 pj_assert(ice->comp[i].nominated_check == NULL);
1947 pj_assert(vc->err_code == PJ_SUCCESS);
1948
1949 for (j=0; j<ice->clist.count; ++j) {
1950 pj_ice_sess_check *c = &ice->clist.checks[j];
1951 if (c->lcand->transport_id == vc->lcand->transport_id &&
1952 c->rcand == vc->rcand)
1953 {
1954 pj_assert(c->err_code == PJ_SUCCESS);
1955 c->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
1956 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING,
1957 PJ_SUCCESS);
1958 break;
1959 }
1960 }
1961 }
1962
1963 /* And (re)start the periodic check */
1964 pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,
1965 &ice->clist.timer, PJ_FALSE);
1966
1967 delay.sec = delay.msec = 0;
1968 status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
1969 &ice->clist.timer, &delay,
1970 PJ_TRUE,
1971 ice->grp_lock);
1972 if (status == PJ_SUCCESS) {
1973 LOG5((ice->obj_name, "Periodic timer rescheduled.."));
1974 }
1975
1976 ice->is_nominating = PJ_TRUE;
1977 pj_log_pop_indent();
1978}
1979
1980/* Timer callback to perform periodic check */
1981static void periodic_timer(pj_timer_heap_t *th,
1982 pj_timer_entry *te)
1983{
1984 start_periodic_check(th, te);
1985}
1986
1987
1988/* Utility: find string in string array */
1989const pj_str_t *find_str(const pj_str_t *strlist[], unsigned count,
1990 const pj_str_t *str)
1991{
1992 unsigned i;
1993 for (i=0; i<count; ++i) {
1994 if (pj_strcmp(strlist[i], str)==0)
1995 return strlist[i];
1996 }
1997 return NULL;
1998}
1999
2000
2001/*
2002 * Start ICE periodic check. This function will return immediately, and
2003 * application will be notified about the connectivity check status in
2004 * #pj_ice_sess_cb callback.
2005 */
2006PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice)
2007{
2008 pj_ice_sess_checklist *clist;
2009 const pj_ice_sess_cand *cand0;
2010 const pj_str_t *flist[PJ_ICE_MAX_CAND]; // XXX
2011 pj_ice_rx_check *rcheck;
2012 unsigned i, flist_cnt = 0;
2013 pj_time_val delay;
2014 pj_status_t status;
2015
2016 PJ_ASSERT_RETURN(ice, PJ_EINVAL);
2017
2018 /* Checklist must have been created */
2019 PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
2020
2021 /* Lock session */
2022 pj_grp_lock_acquire(ice->grp_lock);
2023
2024 LOG4((ice->obj_name, "Starting ICE check.."));
2025 pj_log_push_indent();
2026
2027 /* If we are using aggressive nomination, set the is_nominating state */
2028 if (ice->opt.aggressive)
2029 ice->is_nominating = PJ_TRUE;
2030
2031 /* The agent examines the check list for the first media stream (a
2032 * media stream is the first media stream when it is described by
2033 * the first m-line in the SDP offer and answer). For that media
2034 * stream, it:
2035 *
2036 * - Groups together all of the pairs with the same foundation,
2037 *
2038 * - For each group, sets the state of the pair with the lowest
2039 * component ID to Waiting. If there is more than one such pair,
2040 * the one with the highest priority is used.
2041 */
2042
2043 clist = &ice->clist;
2044
2045 /* Pickup the first pair for component 1. */
2046 for (i=0; i<clist->count; ++i) {
2047 if (clist->checks[i].lcand->comp_id == 1)
2048 break;
2049 }
2050 if (i == clist->count) {
2051 pj_assert(!"Unable to find checklist for component 1");
2052 pj_grp_lock_release(ice->grp_lock);
2053 pj_log_pop_indent();
2054 return PJNATH_EICEINCOMPID;
2055 }
2056
2057 /* Set this check to WAITING only if state is frozen. It may be possible
2058 * that this check has already been started by a trigger check
2059 */
2060 if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
2061 check_set_state(ice, &clist->checks[i],
2062 PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
2063 }
2064
2065 cand0 = clist->checks[i].lcand;
2066 flist[flist_cnt++] = &clist->checks[i].lcand->foundation;
2067
2068 /* Find all of the other pairs in that check list with the same
2069 * component ID, but different foundations, and sets all of their
2070 * states to Waiting as well.
2071 */
2072 for (++i; i<clist->count; ++i) {
2073 const pj_ice_sess_cand *cand1;
2074
2075 cand1 = clist->checks[i].lcand;
2076
2077 if (cand1->comp_id==cand0->comp_id &&
2078 find_str(flist, flist_cnt, &cand1->foundation)==NULL)
2079 {
2080 if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
2081 check_set_state(ice, &clist->checks[i],
2082 PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
2083 }
2084 flist[flist_cnt++] = &cand1->foundation;
2085 }
2086 }
2087
2088 /* First, perform all pending triggered checks, simultaneously. */
2089 rcheck = ice->early_check.next;
2090 while (rcheck != &ice->early_check) {
2091 LOG4((ice->obj_name,
2092 "Performing delayed triggerred check for component %d",
2093 rcheck->comp_id));
2094 pj_log_push_indent();
2095 handle_incoming_check(ice, rcheck);
2096 rcheck = rcheck->next;
2097 pj_log_pop_indent();
2098 }
2099 pj_list_init(&ice->early_check);
2100
2101 /* Start periodic check */
2102 /* We could start it immediately like below, but lets schedule timer
2103 * instead to reduce stack usage:
2104 * return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer);
2105 */
2106 delay.sec = delay.msec = 0;
2107 status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
2108 &clist->timer, &delay,
2109 PJ_TRUE, ice->grp_lock);
2110 if (status != PJ_SUCCESS) {
2111 clist->timer.id = PJ_FALSE;
2112 }
2113
2114 pj_grp_lock_release(ice->grp_lock);
2115 pj_log_pop_indent();
2116 return status;
2117}
2118
2119
2120//////////////////////////////////////////////////////////////////////////////
2121
2122/* Callback called by STUN session to send the STUN message.
2123 * STUN session also doesn't have a transport, remember?!
2124 */
2125static pj_status_t on_stun_send_msg(pj_stun_session *sess,
2126 void *token,
2127 const void *pkt,
2128 pj_size_t pkt_size,
2129 const pj_sockaddr_t *dst_addr,
2130 unsigned addr_len)
2131{
2132 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
2133 pj_ice_sess *ice = sd->ice;
2134 pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
2135 pj_status_t status;
2136
2137 pj_grp_lock_acquire(ice->grp_lock);
2138
2139 if (ice->is_destroying) {
2140 /* Stray retransmit timer that could happen while
2141 * we're being destroyed */
2142 pj_grp_lock_release(ice->grp_lock);
2143 return PJ_EINVALIDOP;
2144 }
2145
2146 status = (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id,
2147 pkt, pkt_size, dst_addr, addr_len);
2148
2149 pj_grp_lock_release(ice->grp_lock);
2150 return status;
2151}
2152
2153
2154/* This callback is called when outgoing STUN request completed */
2155static void on_stun_request_complete(pj_stun_session *stun_sess,
2156 pj_status_t status,
2157 void *token,
2158 pj_stun_tx_data *tdata,
2159 const pj_stun_msg *response,
2160 const pj_sockaddr_t *src_addr,
2161 unsigned src_addr_len)
2162{
2163 pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
2164 pj_ice_sess *ice;
2165 pj_ice_sess_check *check, *new_check;
2166 pj_ice_sess_cand *lcand;
2167 pj_ice_sess_checklist *clist;
2168 pj_stun_xor_mapped_addr_attr *xaddr;
2169 unsigned i;
2170
2171 PJ_UNUSED_ARG(stun_sess);
2172 PJ_UNUSED_ARG(src_addr_len);
2173
2174 pj_assert(msg_data->has_req_data);
2175
2176 ice = msg_data->data.req.ice;
2177 clist = msg_data->data.req.clist;
2178 check = &clist->checks[msg_data->data.req.ckid];
2179
2180
2181 /* Mark STUN transaction as complete */
2182 pj_assert(tdata == check->tdata);
2183 check->tdata = NULL;
2184
2185 pj_grp_lock_acquire(ice->grp_lock);
2186
2187 if (ice->is_destroying) {
2188 /* Not sure if this is possible but just in case */
2189 pj_grp_lock_release(ice->grp_lock);
2190 return;
2191 }
2192
2193 /* Init lcand to NULL. lcand will be found from the mapped address
2194 * found in the response.
2195 */
2196 lcand = NULL;
2197
2198 if (status != PJ_SUCCESS) {
2199 char errmsg[PJ_ERR_MSG_SIZE];
2200
2201 if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ROLE_CONFLICT)) {
2202
2203 /* Role conclict response.
2204 *
2205 * 7.1.2.1. Failure Cases:
2206 *
2207 * If the request had contained the ICE-CONTROLLED attribute,
2208 * the agent MUST switch to the controlling role if it has not
2209 * already done so. If the request had contained the
2210 * ICE-CONTROLLING attribute, the agent MUST switch to the
2211 * controlled role if it has not already done so. Once it has
2212 * switched, the agent MUST immediately retry the request with
2213 * the ICE-CONTROLLING or ICE-CONTROLLED attribute reflecting
2214 * its new role.
2215 */
2216 pj_ice_sess_role new_role = PJ_ICE_SESS_ROLE_UNKNOWN;
2217 pj_stun_msg *req = tdata->msg;
2218
2219 if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLING, 0)) {
2220 new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
2221 } else if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLED,
2222 0)) {
2223 new_role = PJ_ICE_SESS_ROLE_CONTROLLING;
2224 } else {
2225 pj_assert(!"We should have put CONTROLLING/CONTROLLED attr!");
2226 new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
2227 }
2228
2229 if (new_role != ice->role) {
2230 LOG4((ice->obj_name,
2231 "Changing role because of role conflict response"));
2232 pj_ice_sess_change_role(ice, new_role);
2233 }
2234
2235 /* Resend request */
2236 LOG4((ice->obj_name, "Resending check because of role conflict"));
2237 pj_log_push_indent();
2238 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
2239 perform_check(ice, clist, msg_data->data.req.ckid,
2240 check->nominated || ice->is_nominating);
2241 pj_log_pop_indent();
2242 pj_grp_lock_release(ice->grp_lock);
2243 return;
2244 }
2245
2246 pj_strerror(status, errmsg, sizeof(errmsg));
2247 LOG4((ice->obj_name,
2248 "Check %s%s: connectivity check FAILED: %s",
2249 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2250 &ice->clist, check),
2251 (check->nominated ? " (nominated)" : " (not nominated)"),
2252 errmsg));
2253 pj_log_push_indent();
2254 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
2255 on_check_complete(ice, check);
2256 pj_log_pop_indent();
2257 pj_grp_lock_release(ice->grp_lock);
2258 return;
2259 }
2260
2261
2262 /* 7.1.2.1. Failure Cases
2263 *
2264 * The agent MUST check that the source IP address and port of the
2265 * response equals the destination IP address and port that the Binding
2266 * Request was sent to, and that the destination IP address and port of
2267 * the response match the source IP address and port that the Binding
2268 * Request was sent from.
2269 */
2270 if (pj_sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr)!=0)
2271 {
2272 status = PJNATH_EICEINSRCADDR;
2273 LOG4((ice->obj_name,
2274 "Check %s%s: connectivity check FAILED: source address mismatch",
2275 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2276 &ice->clist, check),
2277 (check->nominated ? " (nominated)" : " (not nominated)")));
2278 pj_log_push_indent();
2279 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
2280 on_check_complete(ice, check);
2281 pj_log_pop_indent();
2282 pj_grp_lock_release(ice->grp_lock);
2283 return;
2284 }
2285
2286 /* 7.1.2.2. Success Cases
2287 *
2288 * A check is considered to be a success if all of the following are
2289 * true:
2290 *
2291 * o the STUN transaction generated a success response
2292 *
2293 * o the source IP address and port of the response equals the
2294 * destination IP address and port that the Binding Request was sent
2295 * to
2296 *
2297 * o the destination IP address and port of the response match the
2298 * source IP address and port that the Binding Request was sent from
2299 */
2300
2301
2302 LOG4((ice->obj_name,
2303 "Check %s%s: connectivity check SUCCESS",
2304 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2305 &ice->clist, check),
2306 (check->nominated ? " (nominated)" : " (not nominated)")));
2307
2308 /* Get the STUN XOR-MAPPED-ADDRESS attribute. */
2309 xaddr = (pj_stun_xor_mapped_addr_attr*)
2310 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0);
2311 if (!xaddr) {
2312 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
2313 PJNATH_ESTUNNOMAPPEDADDR);
2314 on_check_complete(ice, check);
2315 pj_grp_lock_release(ice->grp_lock);
2316 return;
2317 }
2318
2319 /* Find local candidate that matches the XOR-MAPPED-ADDRESS */
2320 pj_assert(lcand == NULL);
2321 for (i=0; i<ice->lcand_cnt; ++i) {
2322 if (pj_sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) {
2323 /* Match */
2324 lcand = &ice->lcand[i];
2325 break;
2326 }
2327 }
2328
2329 /* 7.1.2.2.1. Discovering Peer Reflexive Candidates
2330 * If the transport address returned in XOR-MAPPED-ADDRESS does not match
2331 * any of the local candidates that the agent knows about, the mapped
2332 * address represents a new candidate - a peer reflexive candidate.
2333 */
2334 if (lcand == NULL) {
2335 unsigned cand_id;
2336 pj_str_t foundation;
2337
2338 pj_ice_calc_foundation(ice->pool, &foundation, PJ_ICE_CAND_TYPE_PRFLX,
2339 &check->lcand->base_addr);
2340
2341 /* Still in 7.1.2.2.1. Discovering Peer Reflexive Candidates
2342 * Its priority is set equal to the value of the PRIORITY attribute
2343 * in the Binding Request.
2344 *
2345 * I think the priority calculated by add_cand() should be the same
2346 * as the one calculated in perform_check(), so there's no need to
2347 * get the priority from the PRIORITY attribute.
2348 */
2349
2350 /* Add new peer reflexive candidate */
2351 status = pj_ice_sess_add_cand(ice, check->lcand->comp_id,
2352 msg_data->transport_id,
2353 PJ_ICE_CAND_TYPE_PRFLX,
2354 65535, &foundation,
2355 &xaddr->sockaddr,
2356 &check->lcand->base_addr,
2357 &check->lcand->base_addr,
2358 pj_sockaddr_get_len(&xaddr->sockaddr),
2359 &cand_id);
2360 if (status != PJ_SUCCESS) {
2361 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
2362 status);
2363 on_check_complete(ice, check);
2364 pj_grp_lock_release(ice->grp_lock);
2365 return;
2366 }
2367
2368 /* Update local candidate */
2369 lcand = &ice->lcand[cand_id];
2370
2371 }
2372
2373 /* 7.1.2.2.3. Constructing a Valid Pair
2374 * Next, the agent constructs a candidate pair whose local candidate
2375 * equals the mapped address of the response, and whose remote candidate
2376 * equals the destination address to which the request was sent.
2377 */
2378
2379 /* Add pair to valid list, if it's not there, otherwise just update
2380 * nominated flag
2381 */
2382 for (i=0; i<ice->valid_list.count; ++i) {
2383 if (ice->valid_list.checks[i].lcand == lcand &&
2384 ice->valid_list.checks[i].rcand == check->rcand)
2385 break;
2386 }
2387
2388 if (i==ice->valid_list.count) {
2389 pj_assert(ice->valid_list.count < PJ_ICE_MAX_CHECKS);
2390 new_check = &ice->valid_list.checks[ice->valid_list.count++];
2391 new_check->lcand = lcand;
2392 new_check->rcand = check->rcand;
2393 new_check->prio = CALC_CHECK_PRIO(ice, lcand, check->rcand);
2394 new_check->state = PJ_ICE_SESS_CHECK_STATE_SUCCEEDED;
2395 new_check->nominated = check->nominated;
2396 new_check->err_code = PJ_SUCCESS;
2397 } else {
2398 new_check = &ice->valid_list.checks[i];
2399 ice->valid_list.checks[i].nominated = check->nominated;
2400 }
2401
2402 /* Update valid check and nominated check for the component */
2403 update_comp_check(ice, new_check->lcand->comp_id, new_check);
2404
2405 /* Sort valid_list (must do so after update_comp_check(), otherwise
2406 * new_check will point to something else (#953)
2407 */
2408 sort_checklist(ice, &ice->valid_list);
2409
2410 /* 7.1.2.2.2. Updating Pair States
2411 *
2412 * The agent sets the state of the pair that generated the check to
2413 * Succeeded. The success of this check might also cause the state of
2414 * other checks to change as well.
2415 */
2416 check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_SUCCEEDED,
2417 PJ_SUCCESS);
2418
2419 /* Perform 7.1.2.2.2. Updating Pair States.
2420 * This may terminate ICE processing.
2421 */
2422 if (on_check_complete(ice, check)) {
2423 /* ICE complete! */
2424 pj_grp_lock_release(ice->grp_lock);
2425 return;
2426 }
2427
2428 pj_grp_lock_release(ice->grp_lock);
2429}
2430
2431
2432/* This callback is called by the STUN session associated with a candidate
2433 * when it receives incoming request.
2434 */
2435static pj_status_t on_stun_rx_request(pj_stun_session *sess,
2436 const pj_uint8_t *pkt,
2437 unsigned pkt_len,
2438 const pj_stun_rx_data *rdata,
2439 void *token,
2440 const pj_sockaddr_t *src_addr,
2441 unsigned src_addr_len)
2442{
2443 stun_data *sd;
2444 const pj_stun_msg *msg = rdata->msg;
2445 pj_ice_msg_data *msg_data;
2446 pj_ice_sess *ice;
2447 pj_stun_priority_attr *prio_attr;
2448 pj_stun_use_candidate_attr *uc_attr;
2449 pj_stun_uint64_attr *role_attr;
2450 pj_stun_tx_data *tdata;
2451 pj_ice_rx_check *rcheck, tmp_rcheck;
2452 pj_status_t status;
2453
2454 PJ_UNUSED_ARG(pkt);
2455 PJ_UNUSED_ARG(pkt_len);
2456
2457 /* Reject any requests except Binding request */
2458 if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
2459 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
2460 NULL, token, PJ_TRUE,
2461 src_addr, src_addr_len);
2462 return PJ_SUCCESS;
2463 }
2464
2465
2466 sd = (stun_data*) pj_stun_session_get_user_data(sess);
2467 ice = sd->ice;
2468
2469 pj_grp_lock_acquire(ice->grp_lock);
2470
2471 if (ice->is_destroying) {
2472 pj_grp_lock_release(ice->grp_lock);
2473 return PJ_EINVALIDOP;
2474 }
2475
2476 /*
2477 * Note:
2478 * Be aware that when STUN request is received, we might not get
2479 * SDP answer yet, so we might not have remote candidates and
2480 * checklist yet. This case will be handled after we send
2481 * a response.
2482 */
2483
2484 /* Get PRIORITY attribute */
2485 prio_attr = (pj_stun_priority_attr*)
2486 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0);
2487 if (prio_attr == NULL) {
2488 LOG5((ice->obj_name, "Received Binding request with no PRIORITY"));
2489 pj_grp_lock_release(ice->grp_lock);
2490 return PJ_SUCCESS;
2491 }
2492
2493 /* Get USE-CANDIDATE attribute */
2494 uc_attr = (pj_stun_use_candidate_attr*)
2495 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0);
2496
2497
2498 /* Get ICE-CONTROLLING or ICE-CONTROLLED */
2499 role_attr = (pj_stun_uint64_attr*)
2500 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLING, 0);
2501 if (role_attr == NULL) {
2502 role_attr = (pj_stun_uint64_attr*)
2503 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLED, 0);
2504 }
2505
2506 /* Handle the case when request comes before answer is received.
2507 * We need to put credential in the response, and since we haven't
2508 * got the response, copy the username from the request.
2509 */
2510 if (ice->rcand_cnt == 0) {
2511 pj_stun_string_attr *uname_attr;
2512
2513 uname_attr = (pj_stun_string_attr*)
2514 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
2515 pj_assert(uname_attr != NULL);
2516 pj_strdup(ice->pool, &ice->rx_uname, &uname_attr->value);
2517 }
2518
2519 /* 7.2.1.1. Detecting and Repairing Role Conflicts
2520 */
2521 if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING &&
2522 role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLING)
2523 {
2524 if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
2525 /* Switch role to controlled */
2526 LOG4((ice->obj_name,
2527 "Changing role because of ICE-CONTROLLING attribute"));
2528 pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLED);
2529 } else {
2530 /* Generate 487 response */
2531 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
2532 NULL, token, PJ_TRUE,
2533 src_addr, src_addr_len);
2534 pj_grp_lock_release(ice->grp_lock);
2535 return PJ_SUCCESS;
2536 }
2537
2538 } else if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED &&
2539 role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLED)
2540 {
2541 if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
2542 /* Generate 487 response */
2543 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
2544 NULL, token, PJ_TRUE,
2545 src_addr, src_addr_len);
2546 pj_grp_lock_release(ice->grp_lock);
2547 return PJ_SUCCESS;
2548 } else {
2549 /* Switch role to controlled */
2550 LOG4((ice->obj_name,
2551 "Changing role because of ICE-CONTROLLED attribute"));
2552 pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLING);
2553 }
2554 }
2555
2556 /*
2557 * First send response to this request
2558 */
2559 status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata);
2560 if (status != PJ_SUCCESS) {
2561 pj_grp_lock_release(ice->grp_lock);
2562 return status;
2563 }
2564
2565 /* Add XOR-MAPPED-ADDRESS attribute */
2566 status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
2567 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
2568 PJ_TRUE, src_addr, src_addr_len);
2569
2570 /* Create a msg_data to be associated with this response */
2571 msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
2572 msg_data->transport_id = ((pj_ice_msg_data*)token)->transport_id;
2573 msg_data->has_req_data = PJ_FALSE;
2574
2575 /* Send the response */
2576 status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
2577 src_addr, src_addr_len, tdata);
2578
2579
2580 /*
2581 * Handling early check.
2582 *
2583 * It's possible that we receive this request before we receive SDP
2584 * answer. In this case, we can't perform trigger check since we
2585 * don't have checklist yet, so just save this check in a pending
2586 * triggered check array to be acted upon later.
2587 */
2588 if (ice->rcand_cnt == 0) {
2589 rcheck = PJ_POOL_ZALLOC_T(ice->pool, pj_ice_rx_check);
2590 } else {
2591 rcheck = &tmp_rcheck;
2592 }
2593
2594 /* Init rcheck */
2595 rcheck->comp_id = sd->comp_id;
2596 rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
2597 rcheck->src_addr_len = src_addr_len;
2598 pj_sockaddr_cp(&rcheck->src_addr, src_addr);
2599 rcheck->use_candidate = (uc_attr != NULL);
2600 rcheck->priority = prio_attr->value;
2601 rcheck->role_attr = role_attr;
2602
2603 if (ice->rcand_cnt == 0) {
2604 /* We don't have answer yet, so keep this request for later */
2605 LOG4((ice->obj_name, "Received an early check for comp %d",
2606 rcheck->comp_id));
2607 pj_list_push_back(&ice->early_check, rcheck);
2608 } else {
2609 /* Handle this check */
2610 handle_incoming_check(ice, rcheck);
2611 }
2612
2613 pj_grp_lock_release(ice->grp_lock);
2614 return PJ_SUCCESS;
2615}
2616
2617
2618/* Handle incoming Binding request and perform triggered check.
2619 * This function may be called by on_stun_rx_request(), or when
2620 * SDP answer is received and we have received early checks.
2621 */
2622static void handle_incoming_check(pj_ice_sess *ice,
2623 const pj_ice_rx_check *rcheck)
2624{
2625 pj_ice_sess_comp *comp;
2626 pj_ice_sess_cand *lcand = NULL;
2627 pj_ice_sess_cand *rcand;
2628 unsigned i;
2629
2630 comp = find_comp(ice, rcheck->comp_id);
2631
2632 /* Find remote candidate based on the source transport address of
2633 * the request.
2634 */
2635 for (i=0; i<ice->rcand_cnt; ++i) {
2636 if (pj_sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0)
2637 break;
2638 }
2639
2640 /* 7.2.1.3. Learning Peer Reflexive Candidates
2641 * If the source transport address of the request does not match any
2642 * existing remote candidates, it represents a new peer reflexive remote
2643 * candidate.
2644 */
2645 if (i == ice->rcand_cnt) {
2646 char raddr[PJ_INET6_ADDRSTRLEN];
2647 if (ice->rcand_cnt >= PJ_ICE_MAX_CAND) {
2648 LOG4((ice->obj_name,
2649 "Unable to add new peer reflexive candidate: too many "
2650 "candidates already (%d)", PJ_ICE_MAX_CAND));
2651 return;
2652 }
2653
2654 rcand = &ice->rcand[ice->rcand_cnt++];
2655 rcand->comp_id = (pj_uint8_t)rcheck->comp_id;
2656 rcand->type = PJ_ICE_CAND_TYPE_PRFLX;
2657 rcand->prio = rcheck->priority;
2658 pj_sockaddr_cp(&rcand->addr, &rcheck->src_addr);
2659
2660 /* Foundation is random, unique from other foundation */
2661 rcand->foundation.ptr = (char*) pj_pool_alloc(ice->pool, 36);
2662 rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 36,
2663 "f%p",
2664 rcand->foundation.ptr);
2665
2666 LOG4((ice->obj_name,
2667 "Added new remote candidate from the request: %s:%d",
2668 pj_sockaddr_print(&rcand->addr, raddr, sizeof(raddr), 0),
2669 pj_sockaddr_get_port(&rcand->addr)));
2670
2671 } else {
2672 /* Remote candidate found */
2673 rcand = &ice->rcand[i];
2674 }
2675
2676#if 0
2677 /* Find again the local candidate by matching the base address
2678 * with the local candidates in the checklist. Checks may have
2679 * been pruned before, so it's possible that if we use the lcand
2680 * as it is, we wouldn't be able to find the check in the checklist
2681 * and we will end up creating a new check unnecessarily.
2682 */
2683 for (i=0; i<ice->clist.count; ++i) {
2684 pj_ice_sess_check *c = &ice->clist.checks[i];
2685 if (/*c->lcand == lcand ||*/
2686 pj_sockaddr_cmp(&c->lcand->base_addr, &lcand->base_addr)==0)
2687 {
2688 lcand = c->lcand;
2689 break;
2690 }
2691 }
2692#else
2693 /* Just get candidate with the highest priority and same transport ID
2694 * for the specified component ID in the checklist.
2695 */
2696 for (i=0; i<ice->clist.count; ++i) {
2697 pj_ice_sess_check *c = &ice->clist.checks[i];
2698 if (c->lcand->comp_id == rcheck->comp_id &&
2699 c->lcand->transport_id == rcheck->transport_id)
2700 {
2701 lcand = c->lcand;
2702 break;
2703 }
2704 }
2705 if (lcand == NULL) {
2706 /* Should not happen, but just in case remote is sending a
2707 * Binding request for a component which it doesn't have.
2708 */
2709 LOG4((ice->obj_name,
2710 "Received Binding request but no local candidate is found!"));
2711 return;
2712 }
2713#endif
2714
2715 /*
2716 * Create candidate pair for this request.
2717 */
2718
2719 /*
2720 * 7.2.1.4. Triggered Checks
2721 *
2722 * Now that we have local and remote candidate, check if we already
2723 * have this pair in our checklist.
2724 */
2725 for (i=0; i<ice->clist.count; ++i) {
2726 pj_ice_sess_check *c = &ice->clist.checks[i];
2727 if (c->lcand == lcand && c->rcand == rcand)
2728 break;
2729 }
2730
2731 /* If the pair is already on the check list:
2732 * - If the state of that pair is Waiting or Frozen, its state is
2733 * changed to In-Progress and a check for that pair is performed
2734 * immediately. This is called a triggered check.
2735 *
2736 * - If the state of that pair is In-Progress, the agent SHOULD
2737 * generate an immediate retransmit of the Binding Request for the
2738 * check in progress. This is to facilitate rapid completion of
2739 * ICE when both agents are behind NAT.
2740 *
2741 * - If the state of that pair is Failed or Succeeded, no triggered
2742 * check is sent.
2743 */
2744 if (i != ice->clist.count) {
2745 pj_ice_sess_check *c = &ice->clist.checks[i];
2746
2747 /* If USE-CANDIDATE is present, set nominated flag
2748 * Note: DO NOT overwrite nominated flag if one is already set.
2749 */
2750 c->nominated = ((rcheck->use_candidate) || c->nominated);
2751
2752 if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN ||
2753 c->state == PJ_ICE_SESS_CHECK_STATE_WAITING)
2754 {
2755 /* See if we shall nominate this check */
2756 pj_bool_t nominate = (c->nominated || ice->is_nominating);
2757
2758 LOG5((ice->obj_name, "Performing triggered check for check %d",i));
2759 pj_log_push_indent();
2760 perform_check(ice, &ice->clist, i, nominate);
2761 pj_log_pop_indent();
2762
2763 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
2764 /* Should retransmit immediately
2765 */
2766 LOG5((ice->obj_name, "Triggered check for check %d not performed "
2767 "because it's in progress. Retransmitting", i));
2768 pj_log_push_indent();
2769 pj_stun_session_retransmit_req(comp->stun_sess, c->tdata, PJ_FALSE);
2770 pj_log_pop_indent();
2771
2772 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
2773 /* Check complete for this component.
2774 * Note this may end ICE process.
2775 */
2776 pj_bool_t complete;
2777 unsigned j;
2778
2779 /* If this check is nominated, scan the valid_list for the
2780 * same check and update the nominated flag. A controlled
2781 * agent might have finished the check earlier.
2782 */
2783 if (rcheck->use_candidate) {
2784 for (j=0; j<ice->valid_list.count; ++j) {
2785 pj_ice_sess_check *vc = &ice->valid_list.checks[j];
2786 if (vc->lcand->transport_id == c->lcand->transport_id &&
2787 vc->rcand == c->rcand)
2788 {
2789 /* Set nominated flag */
2790 vc->nominated = PJ_TRUE;
2791
2792 /* Update valid check and nominated check for the component */
2793 update_comp_check(ice, vc->lcand->comp_id, vc);
2794
2795 LOG5((ice->obj_name, "Valid check %s is nominated",
2796 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt),
2797 &ice->valid_list, vc)));
2798 }
2799 }
2800 }
2801
2802 LOG5((ice->obj_name, "Triggered check for check %d not performed "
2803 "because it's completed", i));
2804 pj_log_push_indent();
2805 complete = on_check_complete(ice, c);
2806 pj_log_pop_indent();
2807 if (complete) {
2808 return;
2809 }
2810 }
2811
2812 }
2813 /* If the pair is not already on the check list:
2814 * - The pair is inserted into the check list based on its priority.
2815 * - Its state is set to In-Progress
2816 * - A triggered check for that pair is performed immediately.
2817 */
2818 /* Note: only do this if we don't have too many checks in checklist */
2819 else if (ice->clist.count < PJ_ICE_MAX_CHECKS) {
2820
2821 pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count];
2822 pj_bool_t nominate;
2823
2824 c->lcand = lcand;
2825 c->rcand = rcand;
2826 c->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
2827 c->state = PJ_ICE_SESS_CHECK_STATE_WAITING;
2828 c->nominated = rcheck->use_candidate;
2829 c->err_code = PJ_SUCCESS;
2830
2831 nominate = (c->nominated || ice->is_nominating);
2832
2833 LOG4((ice->obj_name, "New triggered check added: %d",
2834 ice->clist.count));
2835 pj_log_push_indent();
2836 perform_check(ice, &ice->clist, ice->clist.count++, nominate);
2837 pj_log_pop_indent();
2838
2839 } else {
2840 LOG4((ice->obj_name, "Error: unable to perform triggered check: "
2841 "TOO MANY CHECKS IN CHECKLIST!"));
2842 }
2843}
2844
2845
2846static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
2847 const pj_uint8_t *pkt,
2848 unsigned pkt_len,
2849 const pj_stun_msg *msg,
2850 void *token,
2851 const pj_sockaddr_t *src_addr,
2852 unsigned src_addr_len)
2853{
2854 struct stun_data *sd;
2855
2856 PJ_UNUSED_ARG(sess);
2857 PJ_UNUSED_ARG(pkt);
2858 PJ_UNUSED_ARG(pkt_len);
2859 PJ_UNUSED_ARG(msg);
2860 PJ_UNUSED_ARG(token);
2861 PJ_UNUSED_ARG(src_addr);
2862 PJ_UNUSED_ARG(src_addr_len);
2863
2864 sd = (struct stun_data*) pj_stun_session_get_user_data(sess);
2865
2866 pj_log_push_indent();
2867
2868 if (msg->hdr.type == PJ_STUN_BINDING_INDICATION) {
2869 LOG5((sd->ice->obj_name, "Received Binding Indication keep-alive "
2870 "for component %d", sd->comp_id));
2871 } else {
2872 LOG4((sd->ice->obj_name, "Received unexpected %s indication "
2873 "for component %d", pj_stun_get_method_name(msg->hdr.type),
2874 sd->comp_id));
2875 }
2876
2877 pj_log_pop_indent();
2878
2879 return PJ_SUCCESS;
2880}
2881
2882
2883PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
2884 unsigned comp_id,
2885 const void *data,
2886 pj_size_t data_len)
2887{
2888 pj_status_t status = PJ_SUCCESS;
2889 pj_ice_sess_comp *comp;
2890 pj_ice_sess_cand *cand;
2891 pj_uint8_t transport_id;
2892 pj_sockaddr addr;
2893
2894 PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
2895
2896 /* It is possible that comp_cnt is less than comp_id, when remote
2897 * doesn't support all the components that we have.
2898 */
2899 if (comp_id > ice->comp_cnt) {
2900 return PJNATH_EICEINCOMPID;
2901 }
2902
2903 pj_grp_lock_acquire(ice->grp_lock);
2904
2905 if (ice->is_destroying) {
2906 pj_grp_lock_release(ice->grp_lock);
2907 return PJ_EINVALIDOP;
2908 }
2909
2910 comp = find_comp(ice, comp_id);
2911 if (comp == NULL) {
2912 status = PJNATH_EICEINCOMPID;
2913 pj_grp_lock_release(ice->grp_lock);
2914 goto on_return;
2915 }
2916
2917 if (comp->valid_check == NULL) {
2918 status = PJNATH_EICEINPROGRESS;
2919 pj_grp_lock_release(ice->grp_lock);
2920 goto on_return;
2921 }
2922
2923 cand = comp->valid_check->lcand;
2924 transport_id = cand->transport_id;
2925 pj_sockaddr_cp(&addr, &comp->valid_check->rcand->addr);
2926
2927 /* Release the mutex now to avoid deadlock (see ticket #1451). */
2928 pj_grp_lock_release(ice->grp_lock);
2929
2930 PJ_RACE_ME(5);
2931
2932 status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id,
2933 data, data_len,
2934 &addr,
2935 pj_sockaddr_get_len(&addr));
2936
2937on_return:
2938 return status;
2939}
2940
2941
2942PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
2943 unsigned comp_id,
2944 unsigned transport_id,
2945 void *pkt,
2946 pj_size_t pkt_size,
2947 const pj_sockaddr_t *src_addr,
2948 int src_addr_len)
2949{
2950 pj_status_t status = PJ_SUCCESS;
2951 pj_ice_sess_comp *comp;
2952 pj_ice_msg_data *msg_data = NULL;
2953 unsigned i;
2954
2955 PJ_ASSERT_RETURN(ice, PJ_EINVAL);
2956
2957 pj_grp_lock_acquire(ice->grp_lock);
2958
2959 if (ice->is_destroying) {
2960 pj_grp_lock_release(ice->grp_lock);
2961 return PJ_EINVALIDOP;
2962 }
2963
2964 comp = find_comp(ice, comp_id);
2965 if (comp == NULL) {
2966 pj_grp_lock_release(ice->grp_lock);
2967 return PJNATH_EICEINCOMPID;
2968 }
2969
2970 /* Find transport */
2971 for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
2972 if (ice->tp_data[i].transport_id == transport_id) {
2973 msg_data = &ice->tp_data[i];
2974 break;
2975 }
2976 }
2977 if (msg_data == NULL) {
2978 pj_assert(!"Invalid transport ID");
2979 pj_grp_lock_release(ice->grp_lock);
2980 return PJ_EINVAL;
2981 }
2982
2983 /* Don't check fingerprint. We only need to distinguish STUN and non-STUN
2984 * packets. We don't need to verify the STUN packet too rigorously, that
2985 * will be done by the user.
2986 */
2987 status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size,
2988 PJ_STUN_IS_DATAGRAM |
2989 PJ_STUN_NO_FINGERPRINT_CHECK);
2990 if (status == PJ_SUCCESS) {
2991 status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
2992 PJ_STUN_IS_DATAGRAM, msg_data,
2993 NULL, src_addr, src_addr_len);
2994 if (status != PJ_SUCCESS) {
2995 pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg));
2996 LOG4((ice->obj_name, "Error processing incoming message: %s",
2997 ice->tmp.errmsg));
2998 }
2999 pj_grp_lock_release(ice->grp_lock);
3000 } else {
3001 /* Not a STUN packet. Call application's callback instead, but release
3002 * the mutex now or otherwise we may get deadlock.
3003 */
3004 pj_grp_lock_release(ice->grp_lock);
3005
3006 PJ_RACE_ME(5);
3007
3008 (*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size,
3009 src_addr, src_addr_len);
3010 status = PJ_SUCCESS;
3011 }
3012
3013 return status;
3014}
3015
3016