1 /* $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_strans.h>
21 #include <pjnath/errno.h>
22 #include <pj/addr_resolv.h>
23 #include <pj/array.h>
24 #include <pj/assert.h>
25 #include <pj/ip_helper.h>
26 #include <pj/lock.h>
27 #include <pj/log.h>
28 #include <pj/os.h>
29 #include <pj/pool.h>
30 #include <pj/rand.h>
31 #include <pj/string.h>
32 #include <pj/compat/socket.h>
33 
34 #define ENABLE_TRACE 0
35 
36 #if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0)
37 #  define TRACE_PKT(expr)	    PJ_LOG(5,expr)
38 #else
39 #  define TRACE_PKT(expr)
40 #endif
41 
42 
43 /* Transport IDs */
44 enum tp_type
45 {
46     TP_NONE,
47     TP_STUN,
48     TP_TURN
49 };
50 
51 
52 #define CREATE_TP_ID(type, idx)	    (pj_uint8_t)((type << 6) | idx)
53 #define GET_TP_TYPE(transport_id)   ((transport_id & 0xC0) >> 6)
54 #define GET_TP_IDX(transport_id)    (transport_id & 0x3F)
55 
56 
57 /* Candidate's local preference values. This is mostly used to
58  * specify preference among candidates with the same type. Since
59  * we don't have the facility to specify that, we'll just set it
60  * all to the same value.
61  */
62 #if PJNATH_ICE_PRIO_STD
63 #   define SRFLX_PREF  65535
64 #   define HOST_PREF   65535
65 #   define RELAY_PREF  65535
66 #else
67 #   define SRFLX_PREF  ((1 << PJ_ICE_LOCAL_PREF_BITS) - 1)
68 #   define HOST_PREF   ((1 << PJ_ICE_LOCAL_PREF_BITS) - 1)
69 #   define RELAY_PREF  ((1 << PJ_ICE_LOCAL_PREF_BITS) - 1)
70 #endif
71 
72 
73 /* The candidate type preference when STUN candidate is used */
74 static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] =
75 {
76 #if PJNATH_ICE_PRIO_STD
77     100,    /**< PJ_ICE_HOST_PREF	    */
78     110,    /**< PJ_ICE_SRFLX_PREF	    */
79     126,    /**< PJ_ICE_PRFLX_PREF	    */
80     0	    /**< PJ_ICE_RELAYED_PREF    */
81 #else
82     /* Keep it to 2 bits */
83     1,	/**< PJ_ICE_HOST_PREF	    */
84     2,	/**< PJ_ICE_SRFLX_PREF	    */
85     3,	/**< PJ_ICE_PRFLX_PREF	    */
86     0	/**< PJ_ICE_RELAYED_PREF    */
87 #endif
88 };
89 
90 
91 /* ICE callbacks */
92 static void	   on_valid_pair(pj_ice_sess *ice);
93 static void	   on_ice_complete(pj_ice_sess *ice, pj_status_t status);
94 static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
95 			      unsigned comp_id,
96 			      unsigned transport_id,
97 			      const void *pkt, pj_size_t size,
98 			      const pj_sockaddr_t *dst_addr,
99 			      unsigned dst_addr_len);
100 static void	   ice_rx_data(pj_ice_sess *ice,
101 			       unsigned comp_id,
102 			       unsigned transport_id,
103 			       void *pkt, pj_size_t size,
104 			       const pj_sockaddr_t *src_addr,
105 			       unsigned src_addr_len);
106 
107 
108 /* STUN socket callbacks */
109 /* Notification when incoming packet has been received. */
110 static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
111 				 void *pkt,
112 				 unsigned pkt_len,
113 				 const pj_sockaddr_t *src_addr,
114 				 unsigned addr_len);
115 /* Notifification when asynchronous send operation has completed. */
116 static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
117 				   pj_ioqueue_op_key_t *send_key,
118 				   pj_ssize_t sent);
119 /* Notification when the status of the STUN transport has changed. */
120 static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
121 				pj_stun_sock_op op,
122 				pj_status_t status);
123 
124 
125 /* TURN callbacks */
126 static void turn_on_rx_data(pj_turn_sock *turn_sock,
127 			    void *pkt,
128 			    unsigned pkt_len,
129 			    const pj_sockaddr_t *peer_addr,
130 			    unsigned addr_len);
131 static pj_bool_t turn_on_data_sent(pj_turn_sock *turn_sock,
132 				   pj_ssize_t sent);
133 static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
134 			  pj_turn_state_t new_state);
135 
136 
137 
138 /* Forward decls */
139 static pj_bool_t on_data_sent(pj_ice_strans *ice_st, pj_ssize_t sent);
140 static void check_pending_send(pj_ice_strans *ice_st);
141 static void ice_st_on_destroy(void *obj);
142 static void destroy_ice_st(pj_ice_strans *ice_st);
143 #define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
144 static void sess_init_update(pj_ice_strans *ice_st);
145 
146 /**
147  * This structure describes an ICE stream transport component. A component
148  * in ICE stream transport typically corresponds to a single socket created
149  * for this component, and bound to a specific transport address. This
150  * component may have multiple alias addresses, for example one alias
151  * address for each interfaces in multi-homed host, another for server
152  * reflexive alias, and another for relayed alias. For each transport
153  * address alias, an ICE stream transport candidate (#pj_ice_sess_cand) will
154  * be created, and these candidates will eventually registered to the ICE
155  * session.
156  */
157 typedef struct pj_ice_strans_comp
158 {
159     pj_ice_strans	*ice_st;	/**< ICE stream transport.	*/
160     unsigned		 comp_id;	/**< Component ID.		*/
161 
162     struct {
163 	pj_stun_sock	*sock;		/**< STUN transport.		*/
164     } stun[PJ_ICE_MAX_STUN];
165 
166     struct {
167 	pj_turn_sock	*sock;		/**< TURN relay transport.	*/
168 	pj_bool_t	 log_off;	/**< TURN loggin off?		*/
169 	unsigned	 err_cnt;	/**< TURN disconnected count.	*/
170     } turn[PJ_ICE_MAX_TURN];
171 
172     pj_bool_t		 creating;	/**< Is creating the candidates?*/
173     unsigned		 cand_cnt;	/**< # of candidates/aliaes.	*/
174     pj_ice_sess_cand	 cand_list[PJ_ICE_ST_MAX_CAND];	/**< Cand array	*/
175 
176     pj_bool_t		 ipv4_mapped;   /**< Is IPv6 addr mapped to IPv4?*/
177     pj_sockaddr		 dst_addr;	/**< Destination address	*/
178     pj_sockaddr		 synth_addr;	/**< Synthesized dest address	*/
179     unsigned 		 synth_addr_len;/**< Synthesized dest addr len  */
180 
181     unsigned		 default_cand;	/**< Default candidate.		*/
182 
183 } pj_ice_strans_comp;
184 
185 
186 /* Pending send buffer */
187 typedef struct pending_send
188 {
189     void       	       *buffer;
190     unsigned 		comp_id;
191     pj_size_t 		data_len;
192     pj_sockaddr       	dst_addr;
193     int 		dst_addr_len;
194 } pending_send;
195 
196 /**
197  * This structure represents the ICE stream transport.
198  */
199 struct pj_ice_strans
200 {
201     char		    *obj_name;	/**< Log ID.			*/
202     pj_pool_factory	    *pf;	/**< Pool factory.		*/
203     pj_pool_t		    *pool;	/**< Pool used by this object.	*/
204     void		    *user_data;	/**< Application data.		*/
205     pj_ice_strans_cfg	     cfg;	/**< Configuration.		*/
206     pj_ice_strans_cb	     cb;	/**< Application callback.	*/
207     pj_grp_lock_t	    *grp_lock;  /**< Group lock.		*/
208 
209     pj_ice_strans_state	     state;	/**< Session state.		*/
210     pj_ice_sess		    *ice;	/**< ICE session.		*/
211     pj_time_val		     start_time;/**< Time when ICE was started	*/
212 
213     unsigned		     comp_cnt;	/**< Number of components.	*/
214     pj_ice_strans_comp	   **comp;	/**< Components array.		*/
215 
216     pj_pool_t		    *buf_pool;  /**< Pool for buffers.		*/
217     unsigned		     num_buf;	/**< Number of buffers.		*/
218     unsigned		     buf_idx;	/**< Index of buffer.		*/
219     unsigned		     empty_idx;	/**< Index of empty buffer.	*/
220     unsigned		     buf_size;  /**< Buffer size.		*/
221     pending_send	    *send_buf;	/**< Send buffers.		*/
222     pj_bool_t		     is_pending;/**< Any pending send?		*/
223 
224     pj_timer_entry	     ka_timer;	/**< STUN keep-alive timer.	*/
225 
226     pj_bool_t		     destroy_req;/**< Destroy has been called?	*/
227     pj_bool_t		     cb_called;	/**< Init error callback called?*/
228     pj_bool_t		     call_send_cb;/**< Need to call send cb?	*/
229 
230     pj_bool_t		     rem_cand_end;/**< Trickle ICE: remote has
231 					       signalled end of candidate? */
232     pj_bool_t		     loc_cand_end;/**< Trickle ICE: local has
233 					       signalled end of candidate? */
234 };
235 
236 
237 /**
238  * This structure describe user data for STUN/TURN sockets of the
239  * ICE stream transport.
240  */
241 typedef struct sock_user_data
242 {
243     pj_ice_strans_comp	    *comp;
244     pj_uint8_t		     transport_id;
245 
246 } sock_user_data;
247 
248 
249 /* Validate configuration */
pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg * cfg)250 static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg)
251 {
252     pj_status_t status;
253 
254     status = pj_stun_config_check_valid(&cfg->stun_cfg);
255     if (!status)
256 	return status;
257 
258     return PJ_SUCCESS;
259 }
260 
261 
262 /*
263  * Initialize ICE transport configuration with default values.
264  */
pj_ice_strans_cfg_default(pj_ice_strans_cfg * cfg)265 PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg)
266 {
267     pj_bzero(cfg, sizeof(*cfg));
268 
269     cfg->af = pj_AF_INET();
270     pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL);
271     pj_ice_strans_stun_cfg_default(&cfg->stun);
272     pj_ice_strans_turn_cfg_default(&cfg->turn);
273     pj_ice_sess_options_default(&cfg->opt);
274 
275     cfg->num_send_buf = 4;
276 }
277 
278 
279 /*
280  * Initialize ICE STUN transport configuration with default values.
281  */
pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg * cfg)282 PJ_DEF(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg)
283 {
284     pj_bzero(cfg, sizeof(*cfg));
285 
286     cfg->af = pj_AF_INET();
287     cfg->port = PJ_STUN_PORT;
288     cfg->max_host_cands = 64;
289     cfg->ignore_stun_error = PJ_FALSE;
290     pj_stun_sock_cfg_default(&cfg->cfg);
291 }
292 
293 
294 /*
295  * Initialize ICE TURN transport configuration with default values.
296  */
pj_ice_strans_turn_cfg_default(pj_ice_strans_turn_cfg * cfg)297 PJ_DEF(void) pj_ice_strans_turn_cfg_default(pj_ice_strans_turn_cfg *cfg)
298 {
299     pj_bzero(cfg, sizeof(*cfg));
300 
301     cfg->af = pj_AF_INET();
302     cfg->conn_type = PJ_TURN_TP_UDP;
303     pj_turn_alloc_param_default(&cfg->alloc_param);
304     pj_turn_sock_cfg_default(&cfg->cfg);
305 }
306 
307 
308 /*
309  * Copy configuration.
310  */
pj_ice_strans_cfg_copy(pj_pool_t * pool,pj_ice_strans_cfg * dst,const pj_ice_strans_cfg * src)311 PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool,
312 				     pj_ice_strans_cfg *dst,
313 				     const pj_ice_strans_cfg *src)
314 {
315     unsigned i;
316 
317     pj_memcpy(dst, src, sizeof(*src));
318 
319     if (src->stun.server.slen)
320 	pj_strdup(pool, &dst->stun.server, &src->stun.server);
321 
322     for (i = 0; i < src->stun_tp_cnt; ++i) {
323 	if (src->stun_tp[i].server.slen)
324 	    pj_strdup(pool, &dst->stun_tp[i].server,
325 		      &src->stun_tp[i].server);
326     }
327 
328     if (src->turn.server.slen)
329 	pj_strdup(pool, &dst->turn.server, &src->turn.server);
330     pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred, &src->turn.auth_cred);
331 
332     for (i = 0; i < src->turn_tp_cnt; ++i) {
333 	if (src->turn_tp[i].server.slen)
334 	    pj_strdup(pool, &dst->turn_tp[i].server,
335 		      &src->turn_tp[i].server);
336 	pj_stun_auth_cred_dup(pool, &dst->turn_tp[i].auth_cred,
337 			      &src->turn_tp[i].auth_cred);
338     }
339 }
340 
341 
342 /*
343  * Add or update TURN candidate.
344  */
add_update_turn(pj_ice_strans * ice_st,pj_ice_strans_comp * comp,unsigned idx,unsigned max_cand_cnt)345 static pj_status_t add_update_turn(pj_ice_strans *ice_st,
346 				   pj_ice_strans_comp *comp,
347 				   unsigned idx,
348 				   unsigned max_cand_cnt)
349 {
350     pj_ice_sess_cand *cand = NULL;
351     pj_ice_strans_turn_cfg *turn_cfg = &ice_st->cfg.turn_tp[idx];
352     pj_turn_sock_cfg *sock_cfg  = &turn_cfg->cfg;
353     unsigned comp_idx = comp->comp_id - 1;
354     pj_turn_sock_cb turn_sock_cb;
355     sock_user_data *data;
356     unsigned i;
357     pj_bool_t new_cand = PJ_FALSE;
358     pj_uint8_t tp_id;
359     pj_status_t status;
360 
361     /* Check if TURN transport is configured */
362     if (turn_cfg->server.slen == 0)
363 	return PJ_SUCCESS;
364 
365     /* Find relayed candidate in the component */
366     tp_id = CREATE_TP_ID(TP_TURN, idx);
367     for (i=0; i<comp->cand_cnt; ++i) {
368 	if (comp->cand_list[i].transport_id == tp_id) {
369 	    cand = &comp->cand_list[i];
370 	    break;
371 	}
372     }
373 
374     /* If candidate is found, invalidate it first */
375     if (cand) {
376 	cand->status = PJ_EPENDING;
377 
378 	/* Also if this component's default candidate is set to relay,
379 	 * move it temporarily to something else.
380 	 */
381 	if ((int)comp->default_cand == cand - comp->cand_list) {
382 	    /* Init to something */
383 	    comp->default_cand = 0;
384 	    /* Use srflx candidate as the default, if any */
385 	    for (i=0; i<comp->cand_cnt; ++i) {
386 		if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
387 		    comp->default_cand = i;
388 		    if (ice_st->cfg.af == pj_AF_UNSPEC() ||
389 		        comp->cand_list[i].base_addr.addr.sa_family ==
390 		        ice_st->cfg.af)
391 		    {
392 		        break;
393 		    }
394 		}
395 	    }
396 	}
397     }
398 
399     /* Init TURN socket */
400     pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
401     turn_sock_cb.on_rx_data = &turn_on_rx_data;
402     turn_sock_cb.on_data_sent = &turn_on_data_sent;
403     turn_sock_cb.on_state = &turn_on_state;
404 
405     /* Override with component specific QoS settings, if any */
406     if (ice_st->cfg.comp[comp_idx].qos_type)
407 	sock_cfg->qos_type = ice_st->cfg.comp[comp_idx].qos_type;
408     if (ice_st->cfg.comp[comp_idx].qos_params.flags)
409 	pj_memcpy(&sock_cfg->qos_params,
410 		  &ice_st->cfg.comp[comp_idx].qos_params,
411 		  sizeof(sock_cfg->qos_params));
412 
413     /* Override with component specific socket buffer size settings, if any */
414     if (ice_st->cfg.comp[comp_idx].so_rcvbuf_size > 0)
415 	sock_cfg->so_rcvbuf_size = ice_st->cfg.comp[comp_idx].so_rcvbuf_size;
416     if (ice_st->cfg.comp[comp_idx].so_sndbuf_size > 0)
417 	sock_cfg->so_sndbuf_size = ice_st->cfg.comp[comp_idx].so_sndbuf_size;
418 
419     /* Add relayed candidate with pending status if there's no existing one */
420     if (cand == NULL) {
421 	PJ_ASSERT_RETURN(max_cand_cnt > 0, PJ_ETOOSMALL);
422 
423 	cand = &comp->cand_list[comp->cand_cnt];
424 	cand->type = PJ_ICE_CAND_TYPE_RELAYED;
425 	cand->status = PJ_EPENDING;
426 	cand->local_pref = (pj_uint16_t)(RELAY_PREF - idx);
427 	cand->transport_id = tp_id;
428 	cand->comp_id = (pj_uint8_t) comp->comp_id;
429 	new_cand = PJ_TRUE;
430     }
431 
432     /* Allocate and initialize TURN socket data */
433     data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data);
434     data->comp = comp;
435     data->transport_id = cand->transport_id;
436 
437     /* Create the TURN transport */
438     status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, turn_cfg->af,
439 				 turn_cfg->conn_type,
440 				 &turn_sock_cb, sock_cfg,
441 				 data, &comp->turn[idx].sock);
442     if (status != PJ_SUCCESS) {
443 	return status;
444     }
445 
446     if (new_cand) {
447 	/* Commit the relayed candidate before pj_turn_sock_alloc(), as
448 	 * otherwise there can be race condition, please check
449 	 * https://github.com/pjsip/pjproject/pull/2525 for more info.
450 	 */
451 	comp->cand_cnt++;
452     }
453 
454     /* Add pending job */
455     ///sess_add_ref(ice_st);
456 
457     /* Start allocation */
458     status=pj_turn_sock_alloc(comp->turn[idx].sock,
459 			      &turn_cfg->server,
460 			      turn_cfg->port,
461 			      ice_st->cfg.resolver,
462 			      &turn_cfg->auth_cred,
463 			      &turn_cfg->alloc_param);
464     if (status != PJ_SUCCESS) {
465 	///sess_dec_ref(ice_st);
466 	cand->status = status;
467 	return status;
468     }
469 
470     PJ_LOG(4,(ice_st->obj_name,
471 		  "Comp %d/%d: TURN relay candidate (tpid=%d) "
472 		  "waiting for allocation",
473 		  comp->comp_id, comp->cand_cnt-1, cand->transport_id));
474 
475     return PJ_SUCCESS;
476 }
477 
ice_cand_equals(pj_ice_sess_cand * lcand,pj_ice_sess_cand * rcand)478 static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand,
479 		    	         pj_ice_sess_cand *rcand)
480 {
481     if (lcand == NULL && rcand == NULL){
482         return PJ_TRUE;
483     }
484     if (lcand == NULL || rcand == NULL){
485         return PJ_FALSE;
486     }
487 
488     if (lcand->type != rcand->type
489         || lcand->status != rcand->status
490         || lcand->comp_id != rcand->comp_id
491         || lcand->transport_id != rcand->transport_id
492 	// local pref is no longer a constant, so it may be different
493         //|| lcand->local_pref != rcand->local_pref
494         || lcand->prio != rcand->prio
495         || pj_sockaddr_cmp(&lcand->addr, &rcand->addr) != 0
496         || pj_sockaddr_cmp(&lcand->base_addr, &rcand->base_addr) != 0)
497     {
498         return PJ_FALSE;
499     }
500 
501     return PJ_TRUE;
502 }
503 
504 
add_stun_and_host(pj_ice_strans * ice_st,pj_ice_strans_comp * comp,unsigned idx,unsigned max_cand_cnt)505 static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
506 				     pj_ice_strans_comp *comp,
507 				     unsigned idx,
508 				     unsigned max_cand_cnt)
509 {
510     pj_ice_sess_cand *cand;
511     pj_ice_strans_stun_cfg *stun_cfg = &ice_st->cfg.stun_tp[idx];
512     pj_stun_sock_cfg *sock_cfg  = &stun_cfg->cfg;
513     unsigned comp_idx = comp->comp_id - 1;
514     pj_stun_sock_cb stun_sock_cb;
515     sock_user_data *data;
516     pj_status_t status;
517 
518     PJ_ASSERT_RETURN(max_cand_cnt > 0, PJ_ETOOSMALL);
519 
520     /* Check if STUN transport or host candidate is configured */
521     if (stun_cfg->server.slen == 0 && stun_cfg->max_host_cands == 0)
522 	return PJ_SUCCESS;
523 
524     /* Initialize STUN socket callback */
525     pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
526     stun_sock_cb.on_rx_data = &stun_on_rx_data;
527     stun_sock_cb.on_status = &stun_on_status;
528     stun_sock_cb.on_data_sent = &stun_on_data_sent;
529 
530     /* Override component specific QoS settings, if any */
531     if (ice_st->cfg.comp[comp_idx].qos_type) {
532 	sock_cfg->qos_type = ice_st->cfg.comp[comp_idx].qos_type;
533     }
534     if (ice_st->cfg.comp[comp_idx].qos_params.flags) {
535 	pj_memcpy(&sock_cfg->qos_params,
536 		  &ice_st->cfg.comp[comp_idx].qos_params,
537 		  sizeof(sock_cfg->qos_params));
538     }
539 
540     /* Override component specific socket buffer size settings, if any */
541     if (ice_st->cfg.comp[comp_idx].so_rcvbuf_size > 0) {
542 	sock_cfg->so_rcvbuf_size = ice_st->cfg.comp[comp_idx].so_rcvbuf_size;
543     }
544     if (ice_st->cfg.comp[comp_idx].so_sndbuf_size > 0) {
545 	sock_cfg->so_sndbuf_size = ice_st->cfg.comp[comp_idx].so_sndbuf_size;
546     }
547 
548     /* Prepare srflx candidate with pending status. */
549     cand = &comp->cand_list[comp->cand_cnt];
550     cand->type = PJ_ICE_CAND_TYPE_SRFLX;
551     cand->status = PJ_EPENDING;
552     cand->local_pref = (pj_uint16_t)(SRFLX_PREF - idx);
553     cand->transport_id = CREATE_TP_ID(TP_STUN, idx);
554     cand->comp_id = (pj_uint8_t) comp->comp_id;
555 
556     /* Allocate and initialize STUN socket data */
557     data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data);
558     data->comp = comp;
559     data->transport_id = cand->transport_id;
560 
561     /* Create the STUN transport */
562     status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL,
563 				 stun_cfg->af, &stun_sock_cb,
564 				 sock_cfg, data, &comp->stun[idx].sock);
565     if (status != PJ_SUCCESS)
566 	return status;
567 
568     /* Start STUN Binding resolution and add srflx candidate only if server
569      * is set. When any error occur during STUN Binding resolution, let's
570      * just skip it and generate host candidates.
571      */
572     while (stun_cfg->server.slen) {
573 	pj_stun_sock_info stun_sock_info;
574 
575 	/* Add pending job */
576 	///sess_add_ref(ice_st);
577 
578 	PJ_LOG(4,(ice_st->obj_name,
579 		  "Comp %d: srflx candidate (tpid=%d) starts "
580 		  "Binding discovery",
581 		  comp->comp_id, cand->transport_id));
582 
583 	pj_log_push_indent();
584 
585 	/* Start Binding resolution */
586 	status = pj_stun_sock_start(comp->stun[idx].sock, &stun_cfg->server,
587 				    stun_cfg->port, ice_st->cfg.resolver);
588 	if (status != PJ_SUCCESS) {
589 	    ///sess_dec_ref(ice_st);
590 	    PJ_PERROR(5,(ice_st->obj_name, status,
591 			 "Comp %d: srflx candidate (tpid=%d) failed in "
592 			 "pj_stun_sock_start()",
593 			 comp->comp_id, cand->transport_id));
594 	    pj_log_pop_indent();
595 	    break;
596 	}
597 
598 	/* Enumerate addresses */
599 	status = pj_stun_sock_get_info(comp->stun[idx].sock, &stun_sock_info);
600 	if (status != PJ_SUCCESS) {
601 	    ///sess_dec_ref(ice_st);
602 	    PJ_PERROR(5,(ice_st->obj_name, status,
603 			 "Comp %d: srflx candidate (tpid=%d) failed in "
604 			 "pj_stun_sock_get_info()",
605 			 comp->comp_id, cand->transport_id));
606 	    pj_log_pop_indent();
607 	    break;
608 	}
609 
610 	/* Update and commit the srflx candidate. */
611 	pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]);
612 	pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr);
613 	pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
614 			       cand->type, &cand->base_addr);
615 	comp->cand_cnt++;
616 	max_cand_cnt--;
617 
618 	/* Set default candidate to srflx */
619 	if (comp->cand_list[comp->default_cand].type != PJ_ICE_CAND_TYPE_SRFLX
620 	    || (ice_st->cfg.af != pj_AF_UNSPEC() &&
621 	        comp->cand_list[comp->default_cand].base_addr.addr.sa_family
622 	        != ice_st->cfg.af))
623 	{
624 	    comp->default_cand = (unsigned)(cand - comp->cand_list);
625 	}
626 
627 	pj_log_pop_indent();
628 
629 	/* Not really a loop, just trying to avoid complex 'if' blocks */
630 	break;
631     }
632 
633     /* Add local addresses to host candidates, unless max_host_cands
634      * is set to zero.
635      */
636     if (stun_cfg->max_host_cands) {
637 	pj_stun_sock_info stun_sock_info;
638 	unsigned i, cand_cnt = 0;
639 
640 	/* Enumerate addresses */
641 	status = pj_stun_sock_get_info(comp->stun[idx].sock, &stun_sock_info);
642 	if (status != PJ_SUCCESS) {
643 	    PJ_PERROR(4,(ice_st->obj_name, status,
644 			 "Failed in querying STUN socket info"));
645 	    return status;
646 	}
647 
648 	for (i = 0; i < stun_sock_info.alias_cnt &&
649 		    cand_cnt < stun_cfg->max_host_cands; ++i)
650 	{
651 	    unsigned j;
652 	    pj_bool_t cand_duplicate = PJ_FALSE;
653 	    char addrinfo[PJ_INET6_ADDRSTRLEN+10];
654 	    const pj_sockaddr *addr = &stun_sock_info.aliases[i];
655 
656 	    if (max_cand_cnt==0) {
657 		PJ_LOG(4,(ice_st->obj_name, "Too many host candidates"));
658 		break;
659 	    }
660 
661 	    /* Ignore loopback addresses if cfg->stun.loop_addr is unset */
662 	    if (stun_cfg->loop_addr==PJ_FALSE) {
663 		if (stun_cfg->af == pj_AF_INET() &&
664 		    (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127)
665 		{
666 		    continue;
667 		}
668 		else if (stun_cfg->af == pj_AF_INET6()) {
669 		    pj_in6_addr in6addr = {{{0}}};
670 		    in6addr.s6_addr[15] = 1;
671 		    if (pj_memcmp(&in6addr, &addr->ipv6.sin6_addr,
672 				  sizeof(in6addr))==0)
673 		    {
674 			continue;
675 		    }
676 		}
677 	    }
678 
679 	    /* Ignore IPv6 link-local address, unless it is the default
680 	     * address (first alias).
681 	     */
682 	    if (stun_cfg->af == pj_AF_INET6() && i != 0) {
683 		const pj_in6_addr *a = &addr->ipv6.sin6_addr;
684 		if (a->s6_addr[0] == 0xFE && (a->s6_addr[1] & 0xC0) == 0x80)
685 		    continue;
686 	    }
687 
688 	    cand = &comp->cand_list[comp->cand_cnt];
689 
690 	    cand->type = PJ_ICE_CAND_TYPE_HOST;
691 	    cand->status = PJ_SUCCESS;
692 	    cand->local_pref = (pj_uint16_t)(HOST_PREF - cand_cnt);
693 	    cand->transport_id = CREATE_TP_ID(TP_STUN, idx);
694 	    cand->comp_id = (pj_uint8_t) comp->comp_id;
695 	    pj_sockaddr_cp(&cand->addr, addr);
696 	    pj_sockaddr_cp(&cand->base_addr, addr);
697 	    pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr));
698 
699 	    /* Check if not already in list */
700 	    for (j=0; j<comp->cand_cnt; j++) {
701 		if (ice_cand_equals(cand, &comp->cand_list[j])) {
702 		    cand_duplicate = PJ_TRUE;
703 		    break;
704 		}
705 	    }
706 
707 	    if (cand_duplicate) {
708 		PJ_LOG(4, (ice_st->obj_name,
709 		       "Comp %d: host candidate %s (tpid=%d) is a duplicate",
710 		       comp->comp_id, pj_sockaddr_print(&cand->addr, addrinfo,
711 		       sizeof(addrinfo), 3), cand->transport_id));
712 
713 		pj_bzero(&cand->addr, sizeof(cand->addr));
714 		pj_bzero(&cand->base_addr, sizeof(cand->base_addr));
715 		continue;
716 	    } else {
717 		comp->cand_cnt+=1;
718 		cand_cnt++;
719 		max_cand_cnt--;
720 	    }
721 
722 	    pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
723 				   cand->type, &cand->base_addr);
724 
725 	    /* Set default candidate with the preferred default
726 	     * address family
727 	     */
728 	    if (comp->ice_st->cfg.af != pj_AF_UNSPEC() &&
729 	        addr->addr.sa_family == comp->ice_st->cfg.af &&
730 	        comp->cand_list[comp->default_cand].base_addr.addr.sa_family !=
731 	        ice_st->cfg.af)
732 	    {
733 	        comp->default_cand = (unsigned)(cand - comp->cand_list);
734 	    }
735 
736 	    PJ_LOG(4,(ice_st->obj_name,
737 		      "Comp %d/%d: host candidate %s (tpid=%d) added",
738 		      comp->comp_id, comp->cand_cnt-1,
739 		      pj_sockaddr_print(&cand->addr, addrinfo,
740 					sizeof(addrinfo), 3),
741 					cand->transport_id));
742 	}
743     }
744 
745     return status;
746 }
747 
748 
749 /*
750  * Create the component.
751  */
create_comp(pj_ice_strans * ice_st,unsigned comp_id)752 static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id)
753 {
754     pj_ice_strans_comp *comp = NULL;
755     unsigned i;
756     pj_status_t status;
757 
758     /* Verify arguments */
759     PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
760 
761     /* Check that component ID present */
762     PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
763 
764     /* Create component */
765     comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp);
766     comp->ice_st = ice_st;
767     comp->comp_id = comp_id;
768     comp->creating = PJ_TRUE;
769 
770     ice_st->comp[comp_id-1] = comp;
771 
772     /* Initialize default candidate */
773     comp->default_cand = 0;
774 
775     /* Create STUN transport if configured */
776     for (i=0; i<ice_st->cfg.stun_tp_cnt; ++i) {
777 	unsigned max_cand_cnt = PJ_ICE_ST_MAX_CAND - comp->cand_cnt -
778 				ice_st->cfg.turn_tp_cnt;
779 
780 	status = PJ_ETOOSMALL;
781 
782 	if ((max_cand_cnt > 0) && (max_cand_cnt <= PJ_ICE_ST_MAX_CAND))
783 	    status = add_stun_and_host(ice_st, comp, i, max_cand_cnt);
784 
785 	if (status != PJ_SUCCESS) {
786 	    PJ_PERROR(3,(ice_st->obj_name, status,
787 			 "Failed creating STUN transport #%d for comp %d",
788 			 i, comp->comp_id));
789 	    //return status;
790 	}
791     }
792 
793     /* Create TURN relay if configured. */
794     for (i=0; i<ice_st->cfg.turn_tp_cnt; ++i) {
795 	unsigned max_cand_cnt = PJ_ICE_ST_MAX_CAND - comp->cand_cnt;
796 
797 	status = PJ_ETOOSMALL;
798 
799 	if ((max_cand_cnt > 0) && (max_cand_cnt <= PJ_ICE_ST_MAX_CAND))
800 	    status = add_update_turn(ice_st, comp, i, max_cand_cnt);
801 
802 	if (status != PJ_SUCCESS) {
803 	    PJ_PERROR(3,(ice_st->obj_name, status,
804 			 "Failed creating TURN transport #%d for comp %d",
805 			 i, comp->comp_id));
806 
807 	    //return status;
808 	} else if (max_cand_cnt > 0) {
809 	    max_cand_cnt = PJ_ICE_ST_MAX_CAND - comp->cand_cnt;
810 	}
811     }
812 
813     /* Done creating all the candidates */
814     comp->creating = PJ_FALSE;
815 
816     /* It's possible that we end up without any candidates */
817     if (comp->cand_cnt == 0) {
818 	PJ_LOG(4,(ice_st->obj_name,
819 		  "Error: no candidate is created due to settings"));
820 	return PJ_EINVAL;
821     }
822 
823     return PJ_SUCCESS;
824 }
825 
alloc_send_buf(pj_ice_strans * ice_st,unsigned buf_size)826 static pj_status_t alloc_send_buf(pj_ice_strans *ice_st, unsigned buf_size)
827 {
828     if (buf_size > ice_st->buf_size) {
829         unsigned i;
830 
831         if (ice_st->is_pending) {
832             /* The current buffer is insufficient, but still currently used.*/
833             return PJ_EBUSY;
834         }
835 
836     	pj_pool_safe_release(&ice_st->buf_pool);
837 
838     	ice_st->buf_pool = pj_pool_create(ice_st->pf, "ice_buf",
839     			       (buf_size + sizeof(pending_send)) *
840     			       ice_st->num_buf, 512, NULL);
841 	if (!ice_st->buf_pool)
842 	    return PJ_ENOMEM;
843 
844 	ice_st->buf_size = buf_size;
845 	ice_st->send_buf = pj_pool_calloc(ice_st->buf_pool, ice_st->num_buf,
846 			       		  sizeof(pending_send));
847 	for (i = 0; i < ice_st->num_buf; i++) {
848 	    ice_st->send_buf[i].buffer = pj_pool_alloc(ice_st->buf_pool,
849 	    					       buf_size);
850 	}
851 	ice_st->buf_idx = ice_st->empty_idx = 0;
852     }
853 
854     return PJ_SUCCESS;
855 }
856 
857 /*
858  * Create ICE stream transport
859  */
pj_ice_strans_create(const char * name,const pj_ice_strans_cfg * cfg,unsigned comp_cnt,void * user_data,const pj_ice_strans_cb * cb,pj_ice_strans ** p_ice_st)860 PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name,
861 					  const pj_ice_strans_cfg *cfg,
862 					  unsigned comp_cnt,
863 					  void *user_data,
864 					  const pj_ice_strans_cb *cb,
865 					  pj_ice_strans **p_ice_st)
866 {
867     pj_pool_t *pool;
868     pj_ice_strans *ice_st;
869     unsigned i;
870     pj_status_t status;
871 
872     status = pj_ice_strans_cfg_check_valid(cfg);
873     if (status != PJ_SUCCESS)
874 	return status;
875 
876     PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st &&
877 		     comp_cnt <= PJ_ICE_MAX_COMP , PJ_EINVAL);
878 
879     if (name == NULL)
880 	name = "ice%p";
881 
882     pool = pj_pool_create(cfg->stun_cfg.pf, name, PJNATH_POOL_LEN_ICE_STRANS,
883 			  PJNATH_POOL_INC_ICE_STRANS, NULL);
884     ice_st = PJ_POOL_ZALLOC_T(pool, pj_ice_strans);
885     ice_st->pool = pool;
886     ice_st->pf = cfg->stun_cfg.pf;
887     ice_st->obj_name = pool->obj_name;
888     ice_st->user_data = user_data;
889 
890     PJ_LOG(4,(ice_st->obj_name,
891 	      "Creating ICE stream transport with %d component(s)",
892 	      comp_cnt));
893     pj_log_push_indent();
894 
895     status = pj_grp_lock_create(pool, NULL, &ice_st->grp_lock);
896     if (status != PJ_SUCCESS) {
897 	pj_pool_release(pool);
898 	pj_log_pop_indent();
899 	return status;
900     }
901 
902     /* Allocate send buffer */
903     ice_st->num_buf = cfg->num_send_buf;
904     status = alloc_send_buf(ice_st, cfg->send_buf_size);
905     if (status != PJ_SUCCESS) {
906 	destroy_ice_st(ice_st);
907 	pj_log_pop_indent();
908 	return status;
909     }
910 
911     pj_grp_lock_add_ref(ice_st->grp_lock);
912     pj_grp_lock_add_handler(ice_st->grp_lock, pool, ice_st,
913 			    &ice_st_on_destroy);
914 
915     pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg);
916 
917     /* To maintain backward compatibility, check if old/deprecated setting is set
918      * and the new setting is not, copy the value to the new setting.
919      */
920     if (cfg->stun_tp_cnt == 0 &&
921 	(cfg->stun.server.slen || cfg->stun.max_host_cands))
922     {
923 	ice_st->cfg.stun_tp_cnt = 1;
924 	ice_st->cfg.stun_tp[0] = ice_st->cfg.stun;
925     }
926     if (cfg->turn_tp_cnt == 0 && cfg->turn.server.slen) {
927 	ice_st->cfg.turn_tp_cnt = 1;
928 	ice_st->cfg.turn_tp[0] = ice_st->cfg.turn;
929     }
930 
931     for (i=0; i<ice_st->cfg.stun_tp_cnt; ++i)
932 	ice_st->cfg.stun_tp[i].cfg.grp_lock = ice_st->grp_lock;
933     for (i=0; i<ice_st->cfg.turn_tp_cnt; ++i)
934 	ice_st->cfg.turn_tp[i].cfg.grp_lock = ice_st->grp_lock;
935     pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
936 
937     ice_st->comp_cnt = comp_cnt;
938     ice_st->comp = (pj_ice_strans_comp**)
939 		   pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*));
940 
941     /* Move state to candidate gathering */
942     ice_st->state = PJ_ICE_STRANS_STATE_INIT;
943 
944     /* Acquire initialization mutex to prevent callback to be
945      * called before we finish initialization.
946      */
947     pj_grp_lock_acquire(ice_st->grp_lock);
948 
949     for (i=0; i<comp_cnt; ++i) {
950 	status = create_comp(ice_st, i+1);
951 	if (status != PJ_SUCCESS) {
952 	    pj_grp_lock_release(ice_st->grp_lock);
953 	    destroy_ice_st(ice_st);
954 	    pj_log_pop_indent();
955 	    return status;
956 	}
957     }
958 
959     /* Done with initialization */
960     pj_grp_lock_release(ice_st->grp_lock);
961 
962     PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p created", ice_st));
963 
964     *p_ice_st = ice_st;
965 
966     /* Check if all candidates are ready (this may call callback) */
967     sess_init_update(ice_st);
968 
969     /* If ICE init done, notify app about end of candidate gathering via
970      * on_new_candidate() callback.
971      */
972     if (ice_st->state==PJ_ICE_STRANS_STATE_READY &&
973 	ice_st->cb.on_new_candidate)
974     {
975 	(*ice_st->cb.on_new_candidate)(ice_st, NULL, PJ_TRUE);
976     }
977 
978     pj_log_pop_indent();
979 
980     return PJ_SUCCESS;
981 }
982 
983 /* REALLY destroy ICE */
ice_st_on_destroy(void * obj)984 static void ice_st_on_destroy(void *obj)
985 {
986     pj_ice_strans *ice_st = (pj_ice_strans*)obj;
987 
988     PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p destroyed", obj));
989 
990     /* Done */
991     pj_pool_safe_release(&ice_st->buf_pool);
992     pj_pool_safe_release(&ice_st->pool);
993 }
994 
995 /* Destroy ICE */
destroy_ice_st(pj_ice_strans * ice_st)996 static void destroy_ice_st(pj_ice_strans *ice_st)
997 {
998     unsigned i;
999 
1000     PJ_LOG(5,(ice_st->obj_name, "ICE stream transport %p destroy request..",
1001 	      ice_st));
1002     pj_log_push_indent();
1003 
1004     /* Reset callback and user data */
1005     pj_bzero(&ice_st->cb, sizeof(ice_st->cb));
1006     ice_st->user_data = NULL;
1007 
1008     pj_grp_lock_acquire(ice_st->grp_lock);
1009 
1010     if (ice_st->destroy_req) {
1011 	pj_grp_lock_release(ice_st->grp_lock);
1012 	return;
1013     }
1014 
1015     ice_st->destroy_req = PJ_TRUE;
1016 
1017     /* Destroy ICE if we have ICE */
1018     if (ice_st->ice) {
1019 	pj_ice_sess_destroy(ice_st->ice);
1020 	ice_st->ice = NULL;
1021     }
1022 
1023     /* Destroy all components */
1024     for (i=0; i<ice_st->comp_cnt; ++i) {
1025 	if (ice_st->comp[i]) {
1026 	    pj_ice_strans_comp *comp = ice_st->comp[i];
1027 	    unsigned j;
1028 	    for (j = 0; j < ice_st->cfg.stun_tp_cnt; ++j) {
1029 		if (comp->stun[j].sock) {
1030 		    pj_stun_sock_destroy(comp->stun[j].sock);
1031 		    comp->stun[j].sock = NULL;
1032 		}
1033 	    }
1034 	    for (j = 0; j < ice_st->cfg.turn_tp_cnt; ++j) {
1035 		if (comp->turn[j].sock) {
1036 		    pj_turn_sock_destroy(comp->turn[j].sock);
1037 		    comp->turn[j].sock = NULL;
1038 		}
1039 	    }
1040 	}
1041     }
1042 
1043     pj_grp_lock_dec_ref(ice_st->grp_lock);
1044     pj_grp_lock_release(ice_st->grp_lock);
1045 
1046     pj_log_pop_indent();
1047 }
1048 
1049 /* Get ICE session state. */
pj_ice_strans_get_state(pj_ice_strans * ice_st)1050 PJ_DEF(pj_ice_strans_state) pj_ice_strans_get_state(pj_ice_strans *ice_st)
1051 {
1052     return ice_st->state;
1053 }
1054 
1055 /* State string */
pj_ice_strans_state_name(pj_ice_strans_state state)1056 PJ_DEF(const char*) pj_ice_strans_state_name(pj_ice_strans_state state)
1057 {
1058     const char *names[] = {
1059 	"Null",
1060 	"Candidate Gathering",
1061 	"Candidate Gathering Complete",
1062 	"Session Initialized",
1063 	"Negotiation In Progress",
1064 	"Negotiation Success",
1065 	"Negotiation Failed"
1066     };
1067 
1068     PJ_ASSERT_RETURN(state <= PJ_ICE_STRANS_STATE_FAILED, "???");
1069     return names[state];
1070 }
1071 
1072 /* Notification about failure */
sess_fail(pj_ice_strans * ice_st,pj_ice_strans_op op,const char * title,pj_status_t status)1073 static void sess_fail(pj_ice_strans *ice_st, pj_ice_strans_op op,
1074 		      const char *title, pj_status_t status)
1075 {
1076     PJ_PERROR(4,(ice_st->obj_name, status, title));
1077 
1078     pj_log_push_indent();
1079 
1080     if (op==PJ_ICE_STRANS_OP_INIT && ice_st->cb_called) {
1081 	pj_log_pop_indent();
1082 	return;
1083     }
1084 
1085     ice_st->cb_called = PJ_TRUE;
1086 
1087     if (ice_st->cb.on_ice_complete)
1088 	(*ice_st->cb.on_ice_complete)(ice_st, op, status);
1089 
1090     pj_log_pop_indent();
1091 }
1092 
1093 /* Update initialization status */
sess_init_update(pj_ice_strans * ice_st)1094 static void sess_init_update(pj_ice_strans *ice_st)
1095 {
1096     unsigned i;
1097     pj_status_t status = PJ_EUNKNOWN;
1098 
1099     /* Ignore if ICE is destroying or init callback has been called */
1100     if (ice_st->destroy_req || ice_st->cb_called)
1101 	return;
1102 
1103     /* Notify application when all candidates have been gathered */
1104     for (i=0; i<ice_st->comp_cnt; ++i) {
1105 	unsigned j;
1106 	pj_ice_strans_comp *comp = ice_st->comp[i];
1107 
1108 	/* This function can be called when all components or candidates
1109 	 * have not been created.
1110 	 */
1111 	if (!comp || comp->creating) {
1112 	    PJ_LOG(5, (ice_st->obj_name, "ICE init update: creating comp %d",
1113 		       (comp?comp->comp_id:(i+1)) ));
1114 	    return;
1115 	}
1116 
1117 	status = PJ_EUNKNOWN;
1118 	for (j=0; j<comp->cand_cnt; ++j) {
1119 	    pj_ice_sess_cand *cand = &comp->cand_list[j];
1120 
1121 	    if (cand->status == PJ_EPENDING) {
1122 		PJ_LOG(5, (ice_st->obj_name, "ICE init update: "
1123 			   "comp %d/%d[%s] is pending",
1124 			   comp->comp_id, j,
1125 			   pj_ice_get_cand_type_name(cand->type)));
1126 		return;
1127 	    }
1128 
1129 	    if (status == PJ_EUNKNOWN) {
1130 	    	status = cand->status;
1131 	    } else {
1132 	    	/* We only need one successful candidate. */
1133 	    	if (cand->status == PJ_SUCCESS)
1134 	    	    status = PJ_SUCCESS;
1135 	    }
1136 	}
1137 
1138 	if (status != PJ_SUCCESS)
1139 	    break;
1140     }
1141 
1142     /* All candidates have been gathered or there's no successful
1143      * candidate for a component.
1144      */
1145     ice_st->cb_called = PJ_TRUE;
1146     ice_st->state = PJ_ICE_STRANS_STATE_READY;
1147     if (ice_st->cb.on_ice_complete)
1148 	(*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT,
1149 				      status);
1150 
1151     /* Tell ICE session that trickling is done */
1152     ice_st->loc_cand_end = PJ_TRUE;
1153     if (ice_st->ice && ice_st->ice->is_trickling && ice_st->rem_cand_end) {
1154 	pj_ice_sess_update_check_list(ice_st->ice, NULL, NULL, 0, NULL,
1155 				      PJ_TRUE);
1156     }
1157 }
1158 
1159 /*
1160  * Destroy ICE stream transport.
1161  */
pj_ice_strans_destroy(pj_ice_strans * ice_st)1162 PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st)
1163 {
1164     destroy_ice_st(ice_st);
1165     return PJ_SUCCESS;
1166 }
1167 
1168 
1169 /*
1170  * Get user data
1171  */
pj_ice_strans_get_user_data(pj_ice_strans * ice_st)1172 PJ_DEF(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st)
1173 {
1174     PJ_ASSERT_RETURN(ice_st, NULL);
1175     return ice_st->user_data;
1176 }
1177 
1178 
1179 /*
1180  * Get the value of various options of the ICE stream transport.
1181  */
pj_ice_strans_get_options(pj_ice_strans * ice_st,pj_ice_sess_options * opt)1182 PJ_DEF(pj_status_t) pj_ice_strans_get_options( pj_ice_strans *ice_st,
1183 					       pj_ice_sess_options *opt)
1184 {
1185     PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
1186     pj_memcpy(opt, &ice_st->cfg.opt, sizeof(*opt));
1187     return PJ_SUCCESS;
1188 }
1189 
1190 /*
1191  * Specify various options for this ICE stream transport.
1192  */
pj_ice_strans_set_options(pj_ice_strans * ice_st,const pj_ice_sess_options * opt)1193 PJ_DEF(pj_status_t) pj_ice_strans_set_options(pj_ice_strans *ice_st,
1194 					      const pj_ice_sess_options *opt)
1195 {
1196     PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
1197     pj_memcpy(&ice_st->cfg.opt, opt, sizeof(*opt));
1198     if (ice_st->ice)
1199 	pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
1200     return PJ_SUCCESS;
1201 }
1202 
1203 /*
1204  * Update number of components of the ICE stream transport.
1205  */
pj_ice_strans_update_comp_cnt(pj_ice_strans * ice_st,unsigned comp_cnt)1206 PJ_DEF(pj_status_t) pj_ice_strans_update_comp_cnt( pj_ice_strans *ice_st,
1207 						   unsigned comp_cnt)
1208 {
1209     unsigned i;
1210 
1211     PJ_ASSERT_RETURN(ice_st && comp_cnt < ice_st->comp_cnt, PJ_EINVAL);
1212     PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EINVALIDOP);
1213 
1214     pj_grp_lock_acquire(ice_st->grp_lock);
1215 
1216     for (i=comp_cnt; i<ice_st->comp_cnt; ++i) {
1217 	pj_ice_strans_comp *comp = ice_st->comp[i];
1218 	unsigned j;
1219 
1220 	/* Destroy the component */
1221 	for (j = 0; j < ice_st->cfg.stun_tp_cnt; ++j) {
1222 	    if (comp->stun[j].sock) {
1223 		pj_stun_sock_destroy(comp->stun[j].sock);
1224 		comp->stun[j].sock = NULL;
1225 	    }
1226 	}
1227 	for (j = 0; j < ice_st->cfg.turn_tp_cnt; ++j) {
1228 	    if (comp->turn[j].sock) {
1229 		pj_turn_sock_destroy(comp->turn[j].sock);
1230 		comp->turn[j].sock = NULL;
1231 	    }
1232 	}
1233 	comp->cand_cnt = 0;
1234 	ice_st->comp[i] = NULL;
1235     }
1236     ice_st->comp_cnt = comp_cnt;
1237     pj_grp_lock_release(ice_st->grp_lock);
1238 
1239     PJ_LOG(4,(ice_st->obj_name,
1240 	      "Updated ICE stream transport components number to %d",
1241 	      comp_cnt));
1242 
1243     return PJ_SUCCESS;
1244 }
1245 
1246 /**
1247  * Get the group lock for this ICE stream transport.
1248  */
pj_ice_strans_get_grp_lock(pj_ice_strans * ice_st)1249 PJ_DEF(pj_grp_lock_t *) pj_ice_strans_get_grp_lock(pj_ice_strans *ice_st)
1250 {
1251     PJ_ASSERT_RETURN(ice_st, NULL);
1252     return ice_st->grp_lock;
1253 }
1254 
1255 /*
1256  * Create ICE!
1257  */
pj_ice_strans_init_ice(pj_ice_strans * ice_st,pj_ice_sess_role role,const pj_str_t * local_ufrag,const pj_str_t * local_passwd)1258 PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
1259 					   pj_ice_sess_role role,
1260 					   const pj_str_t *local_ufrag,
1261 					   const pj_str_t *local_passwd)
1262 {
1263     pj_status_t status;
1264     unsigned i;
1265     pj_ice_sess_cb ice_cb;
1266     //const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };
1267 
1268     /* Check arguments */
1269     PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
1270     /* Must not have ICE */
1271     PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EINVALIDOP);
1272     /* Components must have been created */
1273     PJ_ASSERT_RETURN(ice_st->comp[0] != NULL, PJ_EINVALIDOP);
1274 
1275     /* Init callback */
1276     pj_bzero(&ice_cb, sizeof(ice_cb));
1277     ice_cb.on_valid_pair   = &on_valid_pair;
1278     ice_cb.on_ice_complete = &on_ice_complete;
1279     ice_cb.on_rx_data = &ice_rx_data;
1280     ice_cb.on_tx_pkt = &ice_tx_pkt;
1281 
1282     /* Create! */
1283     status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
1284 			        ice_st->comp_cnt, &ice_cb,
1285 			        local_ufrag, local_passwd,
1286 			        ice_st->grp_lock,
1287 			        &ice_st->ice);
1288     if (status != PJ_SUCCESS)
1289 	return status;
1290 
1291     /* Associate user data */
1292     ice_st->ice->user_data = (void*)ice_st;
1293 
1294     /* Set options */
1295     pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
1296 
1297     /* If default candidate for components are SRFLX one, upload a custom
1298      * type priority to ICE session so that SRFLX candidates will get
1299      * checked first.
1300      */
1301     if (ice_st->comp[0]->cand_list[ice_st->comp[0]->default_cand].type
1302 	    == PJ_ICE_CAND_TYPE_SRFLX)
1303     {
1304 	pj_ice_sess_set_prefs(ice_st->ice, srflx_pref_table);
1305     }
1306 
1307     /* Add components/candidates */
1308     for (i=0; i<ice_st->comp_cnt; ++i) {
1309 	unsigned j;
1310 	pj_ice_strans_comp *comp = ice_st->comp[i];
1311 
1312 	/* Re-enable logging for Send/Data indications */
1313 	if (ice_st->cfg.turn_tp_cnt) {
1314 	    PJ_LOG(5,(ice_st->obj_name,
1315 		      "Enabling STUN Indication logging for "
1316 		      "component %d", i+1));
1317 	}
1318 	for (j = 0; j < ice_st->cfg.turn_tp_cnt; ++j) {
1319 	    if (comp->turn[j].sock) {
1320 		pj_turn_sock_set_log(comp->turn[j].sock, 0xFFFF);
1321 		comp->turn[j].log_off = PJ_FALSE;
1322 	    }
1323 	}
1324 
1325 	for (j=0; j<comp->cand_cnt; ++j) {
1326 	    pj_ice_sess_cand *cand = &comp->cand_list[j];
1327 	    unsigned ice_cand_id;
1328 
1329 	    /* Skip if candidate is not ready */
1330 	    if (cand->status != PJ_SUCCESS) {
1331 		PJ_LOG(5,(ice_st->obj_name,
1332 			  "Candidate %d of comp %d is not added (pending)",
1333 			  j, i));
1334 		continue;
1335 	    }
1336 
1337 	    /* Must have address */
1338 	    pj_assert(pj_sockaddr_has_addr(&cand->addr));
1339 
1340 	    /* Skip if we are mapped to IPv4 address and this candidate
1341 	     * is not IPv4.
1342 	     */
1343 	    if (comp->ipv4_mapped &&
1344 	        cand->addr.addr.sa_family != pj_AF_INET())
1345 	    {
1346 	    	continue;
1347 	    }
1348 
1349 	    /* Add the candidate */
1350 	    status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,
1351 					  cand->transport_id, cand->type,
1352 					  cand->local_pref,
1353 					  &cand->foundation, &cand->addr,
1354 					  &cand->base_addr,  &cand->rel_addr,
1355 					  pj_sockaddr_get_len(&cand->addr),
1356 					  (unsigned*)&ice_cand_id);
1357 	    if (status != PJ_SUCCESS)
1358 		goto on_error;
1359 	}
1360     }
1361 
1362     /* ICE session is ready for negotiation */
1363     ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY;
1364 
1365     return PJ_SUCCESS;
1366 
1367 on_error:
1368     pj_ice_strans_stop_ice(ice_st);
1369     return status;
1370 }
1371 
1372 /*
1373  * Check if the ICE stream transport has the ICE session created.
1374  */
pj_ice_strans_has_sess(pj_ice_strans * ice_st)1375 PJ_DEF(pj_bool_t) pj_ice_strans_has_sess(pj_ice_strans *ice_st)
1376 {
1377     PJ_ASSERT_RETURN(ice_st, PJ_FALSE);
1378     return ice_st->ice != NULL;
1379 }
1380 
1381 /*
1382  * Check if ICE negotiation is still running.
1383  */
pj_ice_strans_sess_is_running(pj_ice_strans * ice_st)1384 PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_running(pj_ice_strans *ice_st)
1385 {
1386     // Trickle ICE can start ICE before remote candidate list is received
1387     return ice_st && ice_st->ice && /* ice_st->ice->rcand_cnt && */
1388 	   ice_st->ice->clist.state == PJ_ICE_SESS_CHECKLIST_ST_RUNNING &&
1389 	   !pj_ice_strans_sess_is_complete(ice_st);
1390 }
1391 
1392 
1393 /*
1394  * Check if ICE negotiation has completed.
1395  */
pj_ice_strans_sess_is_complete(pj_ice_strans * ice_st)1396 PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_complete(pj_ice_strans *ice_st)
1397 {
1398     return ice_st && ice_st->ice && ice_st->ice->is_complete;
1399 }
1400 
1401 
1402 /*
1403  * Get the current/running component count.
1404  */
pj_ice_strans_get_running_comp_cnt(pj_ice_strans * ice_st)1405 PJ_DEF(unsigned) pj_ice_strans_get_running_comp_cnt(pj_ice_strans *ice_st)
1406 {
1407     PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
1408 
1409     if (ice_st->ice && ice_st->ice->rcand_cnt) {
1410 	return ice_st->ice->comp_cnt;
1411     } else {
1412 	return ice_st->comp_cnt;
1413     }
1414 }
1415 
1416 
1417 /*
1418  * Get the ICE username fragment and password of the ICE session.
1419  */
pj_ice_strans_get_ufrag_pwd(pj_ice_strans * ice_st,pj_str_t * loc_ufrag,pj_str_t * loc_pwd,pj_str_t * rem_ufrag,pj_str_t * rem_pwd)1420 PJ_DEF(pj_status_t) pj_ice_strans_get_ufrag_pwd( pj_ice_strans *ice_st,
1421 						 pj_str_t *loc_ufrag,
1422 						 pj_str_t *loc_pwd,
1423 						 pj_str_t *rem_ufrag,
1424 						 pj_str_t *rem_pwd)
1425 {
1426     PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
1427 
1428     if (loc_ufrag) *loc_ufrag = ice_st->ice->rx_ufrag;
1429     if (loc_pwd) *loc_pwd = ice_st->ice->rx_pass;
1430 
1431     if (rem_ufrag || rem_pwd) {
1432 	// In trickle ICE, remote may send initial SDP with empty candidates
1433 	//PJ_ASSERT_RETURN(ice_st->ice->rcand_cnt != 0, PJ_EINVALIDOP);
1434 	if (rem_ufrag) *rem_ufrag = ice_st->ice->tx_ufrag;
1435 	if (rem_pwd) *rem_pwd = ice_st->ice->tx_pass;
1436     }
1437 
1438     return PJ_SUCCESS;
1439 }
1440 
1441 /*
1442  * Get number of candidates
1443  */
pj_ice_strans_get_cands_count(pj_ice_strans * ice_st,unsigned comp_id)1444 PJ_DEF(unsigned) pj_ice_strans_get_cands_count(pj_ice_strans *ice_st,
1445 					       unsigned comp_id)
1446 {
1447     unsigned i, cnt;
1448 
1449     PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
1450 		     comp_id <= ice_st->comp_cnt, 0);
1451 
1452     cnt = 0;
1453     for (i=0; i<ice_st->ice->lcand_cnt; ++i) {
1454 	if (ice_st->ice->lcand[i].comp_id != comp_id)
1455 	    continue;
1456 	++cnt;
1457     }
1458 
1459     return cnt;
1460 }
1461 
1462 /*
1463  * Enum candidates
1464  */
pj_ice_strans_enum_cands(pj_ice_strans * ice_st,unsigned comp_id,unsigned * count,pj_ice_sess_cand cand[])1465 PJ_DEF(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st,
1466 					     unsigned comp_id,
1467 					     unsigned *count,
1468 					     pj_ice_sess_cand cand[])
1469 {
1470     unsigned i, cnt;
1471 
1472     PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
1473 		     comp_id <= ice_st->comp_cnt && count && cand, PJ_EINVAL);
1474 
1475     cnt = 0;
1476     for (i=0; i<ice_st->ice->lcand_cnt && cnt<*count; ++i) {
1477 	if (ice_st->ice->lcand[i].comp_id != comp_id)
1478 	    continue;
1479 	pj_memcpy(&cand[cnt], &ice_st->ice->lcand[i],
1480 		  sizeof(pj_ice_sess_cand));
1481 	++cnt;
1482     }
1483 
1484     *count = cnt;
1485     return PJ_SUCCESS;
1486 }
1487 
1488 /*
1489  * Get default candidate.
1490  */
pj_ice_strans_get_def_cand(pj_ice_strans * ice_st,unsigned comp_id,pj_ice_sess_cand * cand)1491 PJ_DEF(pj_status_t) pj_ice_strans_get_def_cand( pj_ice_strans *ice_st,
1492 						unsigned comp_id,
1493 						pj_ice_sess_cand *cand)
1494 {
1495     const pj_ice_sess_check *valid_pair;
1496 
1497     PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1498 		      cand, PJ_EINVAL);
1499 
1500     valid_pair = pj_ice_strans_get_valid_pair(ice_st, comp_id);
1501     if (valid_pair) {
1502 	pj_memcpy(cand, valid_pair->lcand, sizeof(pj_ice_sess_cand));
1503     } else {
1504 	pj_ice_strans_comp *comp = ice_st->comp[comp_id - 1];
1505 	pj_assert(comp->default_cand<comp->cand_cnt);
1506 	pj_memcpy(cand, &comp->cand_list[comp->default_cand],
1507 		  sizeof(pj_ice_sess_cand));
1508     }
1509     return PJ_SUCCESS;
1510 }
1511 
1512 /*
1513  * Get the current ICE role.
1514  */
pj_ice_strans_get_role(pj_ice_strans * ice_st)1515 PJ_DEF(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st)
1516 {
1517     PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_ICE_SESS_ROLE_UNKNOWN);
1518     return ice_st->ice->role;
1519 }
1520 
1521 /*
1522  * Change session role.
1523  */
pj_ice_strans_change_role(pj_ice_strans * ice_st,pj_ice_sess_role new_role)1524 PJ_DEF(pj_status_t) pj_ice_strans_change_role( pj_ice_strans *ice_st,
1525 					       pj_ice_sess_role new_role)
1526 {
1527     PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
1528     return pj_ice_sess_change_role(ice_st->ice, new_role);
1529 }
1530 
setup_turn_perm(pj_ice_strans * ice_st)1531 static pj_status_t setup_turn_perm( pj_ice_strans *ice_st)
1532 {
1533     unsigned n;
1534     pj_status_t status;
1535 
1536     for (n = 0; n < ice_st->cfg.turn_tp_cnt; ++n) {
1537 	unsigned i, comp_cnt;
1538 
1539 	comp_cnt = pj_ice_strans_get_running_comp_cnt(ice_st);
1540 	for (i=0; i<comp_cnt; ++i) {
1541 	    pj_ice_strans_comp *comp = ice_st->comp[i];
1542 	    pj_turn_session_info info;
1543 	    pj_sockaddr addrs[PJ_ICE_ST_MAX_CAND];
1544 	    unsigned j, count=0;
1545 	    unsigned rem_cand_cnt;
1546 	    const pj_ice_sess_cand *rem_cand;
1547 
1548 	    if (!comp->turn[n].sock)
1549 		continue;
1550 
1551 	    status = pj_turn_sock_get_info(comp->turn[n].sock, &info);
1552 	    if (status != PJ_SUCCESS || info.state != PJ_TURN_STATE_READY)
1553 		continue;
1554 
1555 	    /* Gather remote addresses for this component */
1556 	    rem_cand_cnt = ice_st->ice->rcand_cnt;
1557 	    rem_cand = ice_st->ice->rcand;
1558 	    if (status != PJ_SUCCESS)
1559 		continue;
1560 
1561 	    for (j=0; j<rem_cand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) {
1562 		if (rem_cand[j].comp_id==i+1 &&
1563 		    rem_cand[j].addr.addr.sa_family==
1564 		    ice_st->cfg.turn_tp[n].af)
1565 		{
1566 		    pj_sockaddr_cp(&addrs[count++], &rem_cand[j].addr);
1567 		}
1568 	    }
1569 
1570 	    if (count && !comp->turn[n].err_cnt && comp->turn[n].sock) {
1571 		status = pj_turn_sock_set_perm(
1572 				    comp->turn[n].sock, count,
1573 				    addrs, PJ_ICE_ST_USE_TURN_PERMANENT_PERM);
1574 		if (status != PJ_SUCCESS) {
1575 		    pj_ice_strans_stop_ice(ice_st);
1576 		    return status;
1577 		}
1578 	    }
1579 	}
1580     }
1581 
1582     return PJ_SUCCESS;
1583 }
1584 
1585 /*
1586  * Start ICE processing !
1587  */
pj_ice_strans_start_ice(pj_ice_strans * ice_st,const pj_str_t * rem_ufrag,const pj_str_t * rem_passwd,unsigned rem_cand_cnt,const pj_ice_sess_cand rem_cand[])1588 PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st,
1589 					     const pj_str_t *rem_ufrag,
1590 					     const pj_str_t *rem_passwd,
1591 					     unsigned rem_cand_cnt,
1592 					     const pj_ice_sess_cand rem_cand[])
1593 {
1594     pj_status_t status;
1595 
1596     PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
1597     PJ_ASSERT_RETURN(ice_st->ice, PJ_EINVALIDOP);
1598 
1599     /* Mark start time */
1600     pj_gettimeofday(&ice_st->start_time);
1601 
1602     /* Update check list */
1603     status = pj_ice_strans_update_check_list(ice_st, rem_ufrag, rem_passwd,
1604 					     rem_cand_cnt, rem_cand,
1605 					     !ice_st->ice->is_trickling);
1606     if (status != PJ_SUCCESS)
1607 	return status;
1608 
1609     /* If we have TURN candidate, now is the time to create the permissions */
1610     status = setup_turn_perm(ice_st);
1611     if (status != PJ_SUCCESS) {
1612 	pj_ice_strans_stop_ice(ice_st);
1613 	return status;
1614     }
1615 
1616     /* Start ICE negotiation! */
1617     status = pj_ice_sess_start_check(ice_st->ice);
1618     if (status != PJ_SUCCESS) {
1619 	pj_ice_strans_stop_ice(ice_st);
1620 	return status;
1621     }
1622 
1623     ice_st->state = PJ_ICE_STRANS_STATE_NEGO;
1624     return status;
1625 }
1626 
1627 
1628 /*
1629  * Update check list after discovering and conveying new local ICE candidate,
1630  * or receiving update of remote ICE candidates in trickle ICE.
1631  */
pj_ice_strans_update_check_list(pj_ice_strans * ice_st,const pj_str_t * rem_ufrag,const pj_str_t * rem_passwd,unsigned rem_cand_cnt,const pj_ice_sess_cand rem_cand[],pj_bool_t rcand_end)1632 PJ_DEF(pj_status_t) pj_ice_strans_update_check_list(
1633 					 pj_ice_strans *ice_st,
1634 					 const pj_str_t *rem_ufrag,
1635 					 const pj_str_t *rem_passwd,
1636 					 unsigned rem_cand_cnt,
1637 					 const pj_ice_sess_cand rem_cand[],
1638 					 pj_bool_t rcand_end)
1639 {
1640     pj_bool_t checklist_created;
1641     pj_status_t status;
1642 
1643     PJ_ASSERT_RETURN(ice_st && ((rem_cand_cnt==0) ||
1644 			        (rem_ufrag && rem_passwd && rem_cand)),
1645 		     PJ_EINVAL);
1646     PJ_ASSERT_RETURN(ice_st->ice, PJ_EINVALIDOP);
1647 
1648     pj_grp_lock_acquire(ice_st->grp_lock);
1649 
1650     checklist_created = ice_st->ice->tx_ufrag.slen > 0;
1651 
1652     /* Create checklist (if not yet) */
1653     if (rem_ufrag && !checklist_created) {
1654 	status = pj_ice_sess_create_check_list(ice_st->ice, rem_ufrag,
1655 					       rem_passwd, rem_cand_cnt,
1656 					       rem_cand);
1657 	if (status != PJ_SUCCESS) {
1658 	    PJ_PERROR(4,(ice_st->obj_name, status,
1659 			 "Failed setting up remote ufrag"));
1660 	    pj_grp_lock_release(ice_st->grp_lock);
1661 	    return status;
1662 	}
1663     }
1664 
1665     /* Update checklist for trickling ICE */
1666     if (ice_st->ice->is_trickling) {
1667 	if (rcand_end && !ice_st->rem_cand_end)
1668 	    ice_st->rem_cand_end = PJ_TRUE;
1669 
1670 	status = pj_ice_sess_update_check_list(
1671 			    ice_st->ice, rem_ufrag, rem_passwd,
1672 			    (checklist_created? rem_cand_cnt:0), rem_cand,
1673 			    (ice_st->rem_cand_end && ice_st->loc_cand_end));
1674 	if (status != PJ_SUCCESS) {
1675 	    PJ_PERROR(4,(ice_st->obj_name, status,
1676 			 "Failed updating checklist"));
1677 	    pj_grp_lock_release(ice_st->grp_lock);
1678 	    return status;
1679 	}
1680     }
1681 
1682     /* Update TURN permissions if periodic check has been started. */
1683     if (pj_ice_strans_sess_is_running(ice_st)) {
1684 	status = setup_turn_perm(ice_st);
1685 	if (status != PJ_SUCCESS) {
1686 	    PJ_PERROR(4,(ice_st->obj_name, status,
1687 			 "Failed setting up TURN permission"));
1688 	    pj_grp_lock_release(ice_st->grp_lock);
1689 	    return status;
1690 	}
1691     }
1692 
1693     pj_grp_lock_release(ice_st->grp_lock);
1694 
1695     return PJ_SUCCESS;
1696 }
1697 
1698 
1699 /*
1700  * Get valid pair.
1701  */
1702 PJ_DEF(const pj_ice_sess_check*)
pj_ice_strans_get_valid_pair(const pj_ice_strans * ice_st,unsigned comp_id)1703 pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
1704 			     unsigned comp_id)
1705 {
1706     PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt,
1707 		     NULL);
1708 
1709     if (ice_st->ice == NULL)
1710 	return NULL;
1711 
1712     return ice_st->ice->comp[comp_id-1].valid_check;
1713 }
1714 
1715 /*
1716  * Stop ICE!
1717  */
pj_ice_strans_stop_ice(pj_ice_strans * ice_st)1718 PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
1719 {
1720     PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
1721 
1722     /* Protect with group lock, since this may cause race condition with
1723      * pj_ice_strans_sendto2().
1724      * See ticket #1877.
1725      */
1726     pj_grp_lock_acquire(ice_st->grp_lock);
1727 
1728     if (ice_st->ice) {
1729 	pj_ice_sess_destroy(ice_st->ice);
1730 	ice_st->ice = NULL;
1731     }
1732 
1733     ice_st->state = PJ_ICE_STRANS_STATE_INIT;
1734 
1735     pj_grp_lock_release(ice_st->grp_lock);
1736 
1737     return PJ_SUCCESS;
1738 }
1739 
use_buffer(pj_ice_strans * ice_st,unsigned comp_id,const void * data,pj_size_t data_len,const pj_sockaddr_t * dst_addr,int dst_addr_len,void ** buffer)1740 static pj_status_t use_buffer( pj_ice_strans *ice_st,
1741 			       unsigned comp_id,
1742 			       const void *data,
1743 			       pj_size_t data_len,
1744 			       const pj_sockaddr_t *dst_addr,
1745 			       int dst_addr_len,
1746 			       void **buffer )
1747 {
1748     unsigned idx;
1749     pj_status_t status;
1750 
1751     /* Allocate send buffer, if necessary. */
1752     status = alloc_send_buf(ice_st, data_len);
1753     if (status != PJ_SUCCESS)
1754     	return status;
1755 
1756     if (ice_st->is_pending && ice_st->empty_idx == ice_st->buf_idx) {
1757     	/* We don't use buffer or there's no more empty buffer. */
1758     	return PJ_EBUSY;
1759     }
1760 
1761     idx = ice_st->empty_idx;
1762     ice_st->empty_idx = (ice_st->empty_idx + 1) % ice_st->num_buf;
1763     ice_st->send_buf[idx].comp_id = comp_id;
1764     ice_st->send_buf[idx].data_len = data_len;
1765     pj_assert(ice_st->buf_size >= data_len);
1766     pj_memcpy(ice_st->send_buf[idx].buffer, data, data_len);
1767     pj_sockaddr_cp(&ice_st->send_buf[idx].dst_addr, dst_addr);
1768     ice_st->send_buf[idx].dst_addr_len = dst_addr_len;
1769     *buffer = ice_st->send_buf[idx].buffer;
1770 
1771     if (ice_st->is_pending) {
1772         /* We'll continue later since there's still a pending send. */
1773     	return PJ_EPENDING;
1774     }
1775 
1776     ice_st->is_pending = PJ_TRUE;
1777     ice_st->buf_idx = idx;
1778 
1779     return PJ_SUCCESS;
1780 }
1781 
1782 /*
1783  * Application wants to send outgoing packet.
1784  */
send_data(pj_ice_strans * ice_st,unsigned comp_id,const void * data,pj_size_t data_len,const pj_sockaddr_t * dst_addr,int dst_addr_len,pj_bool_t use_buf,pj_bool_t call_cb)1785 static pj_status_t send_data(pj_ice_strans *ice_st,
1786 			     unsigned comp_id,
1787 		      	     const void *data,
1788 		      	     pj_size_t data_len,
1789 			     const pj_sockaddr_t *dst_addr,
1790 			     int dst_addr_len,
1791 			     pj_bool_t use_buf,
1792 			     pj_bool_t call_cb)
1793 {
1794     pj_ice_strans_comp *comp;
1795     pj_ice_sess_cand *def_cand;
1796     void *buf = (void *)data;
1797     pj_status_t status;
1798 
1799     PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1800 		     dst_addr && dst_addr_len, PJ_EINVAL);
1801 
1802     comp = ice_st->comp[comp_id-1];
1803 
1804     /* Check that default candidate for the component exists */
1805     if (comp->default_cand >= comp->cand_cnt) {
1806 	status = PJ_EINVALIDOP;
1807 	if (call_cb)
1808     	    on_data_sent(ice_st, -status);
1809     	return status;
1810     }
1811 
1812     /* Protect with group lock, since this may cause race condition with
1813      * pj_ice_strans_stop_ice().
1814      * See ticket #1877.
1815      */
1816     pj_grp_lock_acquire(ice_st->grp_lock);
1817 
1818     if (use_buf && ice_st->num_buf > 0) {
1819     	status = use_buffer(ice_st, comp_id, data, data_len, dst_addr,
1820     			    dst_addr_len, &buf);
1821 
1822     	if (status == PJ_EPENDING || status != PJ_SUCCESS) {
1823     	    pj_grp_lock_release(ice_st->grp_lock);
1824     	    return status;
1825     	}
1826     }
1827 
1828     /* If ICE is available, send data with ICE. If ICE nego is not completed
1829      * yet, ICE will try to send using any valid candidate pair. For any
1830      * failure, it will fallback to sending with the default candidate
1831      * selected during initialization.
1832      *
1833      * https://trac.pjsip.org/repos/ticket/1416:
1834      * Once ICE has failed, also send data with the default candidate.
1835      */
1836     if (ice_st->ice && ice_st->state <= PJ_ICE_STRANS_STATE_RUNNING) {
1837 	status = pj_ice_sess_send_data(ice_st->ice, comp_id, buf, data_len);
1838 	if (status == PJ_SUCCESS || status == PJ_EPENDING) {
1839 	    pj_grp_lock_release(ice_st->grp_lock);
1840 	    goto on_return;
1841 	}
1842     }
1843 
1844     pj_grp_lock_release(ice_st->grp_lock);
1845 
1846     def_cand = &comp->cand_list[comp->default_cand];
1847 
1848     if (def_cand->status == PJ_SUCCESS) {
1849 	unsigned tp_idx = GET_TP_IDX(def_cand->transport_id);
1850 
1851 	if (def_cand->type == PJ_ICE_CAND_TYPE_RELAYED) {
1852 
1853 	    enum {
1854 		msg_disable_ind = 0xFFFF &
1855 				  ~(PJ_STUN_SESS_LOG_TX_IND|
1856 				    PJ_STUN_SESS_LOG_RX_IND)
1857 	    };
1858 
1859 	    /* https://trac.pjsip.org/repos/ticket/1316 */
1860 	    if (comp->turn[tp_idx].sock == NULL) {
1861 		/* TURN socket error */
1862 		status = PJ_EINVALIDOP;
1863 		goto on_return;
1864 	    }
1865 
1866 	    if (!comp->turn[tp_idx].log_off) {
1867 		/* Disable logging for Send/Data indications */
1868 		PJ_LOG(5,(ice_st->obj_name,
1869 			  "Disabling STUN Indication logging for "
1870 			  "component %d", comp->comp_id));
1871 		pj_turn_sock_set_log(comp->turn[tp_idx].sock,
1872 				     msg_disable_ind);
1873 		comp->turn[tp_idx].log_off = PJ_TRUE;
1874 	    }
1875 
1876 	    status = pj_turn_sock_sendto(comp->turn[tp_idx].sock,
1877 					 (const pj_uint8_t*)buf,
1878 					 (unsigned)data_len,
1879 					 dst_addr, dst_addr_len);
1880 	    goto on_return;
1881 	} else {
1882     	    const pj_sockaddr_t *dest_addr;
1883     	    unsigned dest_addr_len;
1884 
1885     	    if (comp->ipv4_mapped) {
1886     	    	if (comp->synth_addr_len == 0 ||
1887     	    	    pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0)
1888     	    	{
1889     	    	    status = pj_sockaddr_synthesize(pj_AF_INET6(),
1890     	    					    &comp->synth_addr,
1891     	    					    dst_addr);
1892     	    	    if (status != PJ_SUCCESS)
1893     	            	goto on_return;
1894 
1895     	    	    pj_sockaddr_cp(&comp->dst_addr, dst_addr);
1896     	    	    comp->synth_addr_len = pj_sockaddr_get_len(
1897     	    	    			       &comp->synth_addr);
1898     	    	}
1899 	    	dest_addr = &comp->synth_addr;
1900     	    	dest_addr_len = comp->synth_addr_len;
1901     	    } else {
1902     		dest_addr = dst_addr;
1903     		dest_addr_len = dst_addr_len;
1904     	    }
1905 
1906 	    status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, buf,
1907 					 (unsigned)data_len, 0, dest_addr,
1908 					 dest_addr_len);
1909 	    goto on_return;
1910 	}
1911 
1912     } else
1913 	status = PJ_EINVALIDOP;
1914 
1915 on_return:
1916     /* We continue later in on_data_sent() callback. */
1917     if (status == PJ_EPENDING)
1918     	return status;
1919 
1920     if (call_cb) {
1921     	on_data_sent(ice_st, (status == PJ_SUCCESS? data_len: -status));
1922     } else {
1923     	check_pending_send(ice_st);
1924     }
1925 
1926     return status;
1927 }
1928 
1929 
1930 #if !DEPRECATED_FOR_TICKET_2229
1931 /*
1932  * Application wants to send outgoing packet.
1933  */
pj_ice_strans_sendto(pj_ice_strans * ice_st,unsigned comp_id,const void * data,pj_size_t data_len,const pj_sockaddr_t * dst_addr,int dst_addr_len)1934 PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
1935 					  unsigned comp_id,
1936 					  const void *data,
1937 					  pj_size_t data_len,
1938 					  const pj_sockaddr_t *dst_addr,
1939 					  int dst_addr_len)
1940 {
1941     pj_status_t status;
1942 
1943     PJ_LOG(1, (ice_st->obj_name, "pj_ice_strans_sendto() is deprecated. "
1944     				 "Application is recommended to use "
1945     				 "pj_ice_strans_sendto2() instead."));
1946     status = send_data(ice_st, comp_id, data, data_len, dst_addr,
1947     		       dst_addr_len, PJ_TRUE, PJ_FALSE);
1948     if (status == PJ_EPENDING)
1949     	status = PJ_SUCCESS;
1950 
1951     return status;
1952 }
1953 #endif
1954 
1955 
1956 /*
1957  * Application wants to send outgoing packet.
1958  */
pj_ice_strans_sendto2(pj_ice_strans * ice_st,unsigned comp_id,const void * data,pj_size_t data_len,const pj_sockaddr_t * dst_addr,int dst_addr_len)1959 PJ_DEF(pj_status_t) pj_ice_strans_sendto2(pj_ice_strans *ice_st,
1960 					  unsigned comp_id,
1961 					  const void *data,
1962 					  pj_size_t data_len,
1963 					  const pj_sockaddr_t *dst_addr,
1964 					  int dst_addr_len)
1965 {
1966     ice_st->call_send_cb = PJ_TRUE;
1967     return send_data(ice_st, comp_id, data, data_len, dst_addr,
1968     		     dst_addr_len, PJ_TRUE, PJ_FALSE);
1969 }
1970 
on_valid_pair(pj_ice_sess * ice)1971 static void on_valid_pair(pj_ice_sess *ice)
1972 {
1973     pj_time_val t;
1974     unsigned msec;
1975     pj_ice_strans *ice_st = (pj_ice_strans *)ice->user_data;
1976     pj_ice_strans_cb cb   = ice_st->cb;
1977     pj_status_t status    = PJ_SUCCESS;
1978 
1979     pj_grp_lock_add_ref(ice_st->grp_lock);
1980 
1981     pj_gettimeofday(&t);
1982     PJ_TIME_VAL_SUB(t, ice_st->start_time);
1983     msec = PJ_TIME_VAL_MSEC(t);
1984 
1985     if (cb.on_valid_pair) {
1986 	unsigned i;
1987 	enum {
1988 	    msg_disable_ind = 0xFFFF & ~(PJ_STUN_SESS_LOG_TX_IND |
1989 	                                 PJ_STUN_SESS_LOG_RX_IND)
1990 	};
1991 
1992 	PJ_LOG(4,
1993 	       (ice_st->obj_name, "First ICE candidate nominated in %ds:%03d",
1994 	        msec / 1000, msec % 1000));
1995 
1996 	for (i = 0; i < ice_st->comp_cnt; ++i) {
1997 	    const pj_ice_sess_check *check;
1998 	    pj_ice_strans_comp *comp = ice_st->comp[i];
1999 
2000 	    check = pj_ice_strans_get_valid_pair(ice_st, i + 1);
2001 	    if (check) {
2002 		char lip[PJ_INET6_ADDRSTRLEN + 10];
2003 		char rip[PJ_INET6_ADDRSTRLEN + 10];
2004 		unsigned tp_idx = GET_TP_IDX(check->lcand->transport_id);
2005 		unsigned tp_typ = GET_TP_TYPE(check->lcand->transport_id);
2006 
2007 		pj_sockaddr_print(&check->lcand->addr, lip, sizeof(lip), 3);
2008 		pj_sockaddr_print(&check->rcand->addr, rip, sizeof(rip), 3);
2009 
2010 		if (tp_typ == TP_TURN) {
2011 		    /* Activate channel binding for the remote address
2012 		     * for more efficient data transfer using TURN.
2013 		     */
2014 		    status = pj_turn_sock_bind_channel(
2015 		            comp->turn[tp_idx].sock, &check->rcand->addr,
2016 		            sizeof(check->rcand->addr));
2017 
2018 		    /* Disable logging for Send/Data indications */
2019 		    PJ_LOG(5, (ice_st->obj_name,
2020 		               "Disabling STUN Indication logging for "
2021 		               "component %d",
2022 		               i + 1));
2023 		    pj_turn_sock_set_log(comp->turn[tp_idx].sock,
2024 		                         msg_disable_ind);
2025 		    comp->turn[tp_idx].log_off = PJ_TRUE;
2026 		}
2027 
2028 		PJ_LOG(4, (ice_st->obj_name,
2029 		           " Comp %d: "
2030 		           "sending from %s candidate %s to "
2031 		           "%s candidate %s",
2032 		           i + 1, pj_ice_get_cand_type_name(check->lcand->type),
2033 		           lip, pj_ice_get_cand_type_name(check->rcand->type),
2034 		           rip));
2035 
2036 	    } else {
2037 		PJ_LOG(4, (ice_st->obj_name, "Comp %d: disabled", i + 1));
2038 	    }
2039 	}
2040 
2041 	ice_st->state = (status == PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING :
2042 	                                         PJ_ICE_STRANS_STATE_FAILED;
2043 
2044 	pj_log_push_indent();
2045 	(*cb.on_valid_pair)(ice_st);
2046 	pj_log_pop_indent();
2047     }
2048 
2049     pj_grp_lock_dec_ref(ice_st->grp_lock);
2050 }
2051 
2052 /*
2053  * Callback called by ICE session when ICE processing is complete, either
2054  * successfully or with failure.
2055  */
on_ice_complete(pj_ice_sess * ice,pj_status_t status)2056 static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
2057 {
2058     pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
2059     pj_time_val t;
2060     unsigned msec;
2061     pj_ice_strans_cb cb = ice_st->cb;
2062 
2063     pj_grp_lock_add_ref(ice_st->grp_lock);
2064 
2065     pj_gettimeofday(&t);
2066     PJ_TIME_VAL_SUB(t, ice_st->start_time);
2067     msec = PJ_TIME_VAL_MSEC(t);
2068 
2069     if (cb.on_ice_complete) {
2070 	if (status != PJ_SUCCESS) {
2071 	    PJ_PERROR(4,(ice_st->obj_name, status,
2072 			 "ICE negotiation failed after %ds:%03d",
2073 			 msec/1000, msec%1000));
2074 	} else {
2075 	    unsigned i;
2076 	    enum {
2077 		msg_disable_ind = 0xFFFF &
2078 				  ~(PJ_STUN_SESS_LOG_TX_IND|
2079 				    PJ_STUN_SESS_LOG_RX_IND)
2080 	    };
2081 
2082 	    PJ_LOG(4,(ice_st->obj_name,
2083 		      "ICE negotiation success after %ds:%03d",
2084 		      msec/1000, msec%1000));
2085 
2086 	    for (i=0; i<ice_st->comp_cnt; ++i) {
2087 		const pj_ice_sess_check *check;
2088 		pj_ice_strans_comp *comp = ice_st->comp[i];
2089 
2090 		check = pj_ice_strans_get_valid_pair(ice_st, i+1);
2091 		if (check) {
2092 		    char lip[PJ_INET6_ADDRSTRLEN+10];
2093 		    char rip[PJ_INET6_ADDRSTRLEN+10];
2094 		    unsigned tp_idx = GET_TP_IDX(check->lcand->transport_id);
2095 		    unsigned tp_typ = GET_TP_TYPE(check->lcand->transport_id);
2096 
2097 		    pj_sockaddr_print(&check->lcand->addr, lip,
2098 				      sizeof(lip), 3);
2099 		    pj_sockaddr_print(&check->rcand->addr, rip,
2100 				      sizeof(rip), 3);
2101 
2102 		    if (tp_typ == TP_TURN) {
2103 			/* Activate channel binding for the remote address
2104 			 * for more efficient data transfer using TURN.
2105 			 */
2106 			status = pj_turn_sock_bind_channel(
2107 					comp->turn[tp_idx].sock,
2108 					&check->rcand->addr,
2109 					sizeof(check->rcand->addr));
2110 
2111 			/* Disable logging for Send/Data indications */
2112 			PJ_LOG(5,(ice_st->obj_name,
2113 				  "Disabling STUN Indication logging for "
2114 				  "component %d", i+1));
2115 			pj_turn_sock_set_log(comp->turn[tp_idx].sock,
2116 					     msg_disable_ind);
2117 			comp->turn[tp_idx].log_off = PJ_TRUE;
2118 		    }
2119 
2120 		    PJ_LOG(4,(ice_st->obj_name, " Comp %d: "
2121 			      "sending from %s candidate %s to "
2122 			      "%s candidate %s",
2123 			      i+1,
2124 			      pj_ice_get_cand_type_name(check->lcand->type),
2125 			      lip,
2126 			      pj_ice_get_cand_type_name(check->rcand->type),
2127 			      rip));
2128 
2129 		} else {
2130 		    PJ_LOG(4,(ice_st->obj_name,
2131 			      "Comp %d: disabled", i+1));
2132 		}
2133 	    }
2134 	}
2135 
2136 	ice_st->state = (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING :
2137 					       PJ_ICE_STRANS_STATE_FAILED;
2138 
2139 	pj_log_push_indent();
2140 	(*cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION, status);
2141 	pj_log_pop_indent();
2142 
2143     }
2144 
2145     pj_grp_lock_dec_ref(ice_st->grp_lock);
2146 }
2147 
2148 /*
2149  * Callback called by ICE session when it wants to send outgoing packet.
2150  */
ice_tx_pkt(pj_ice_sess * ice,unsigned comp_id,unsigned transport_id,const void * pkt,pj_size_t size,const pj_sockaddr_t * dst_addr,unsigned dst_addr_len)2151 static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
2152 			      unsigned comp_id,
2153 			      unsigned transport_id,
2154 			      const void *pkt, pj_size_t size,
2155 			      const pj_sockaddr_t *dst_addr,
2156 			      unsigned dst_addr_len)
2157 {
2158     pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
2159     pj_ice_strans_comp *comp;
2160     pj_status_t status;
2161     void *buf = (void *)pkt;
2162     pj_bool_t use_buf = PJ_FALSE;
2163 #if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0)
2164     char daddr[PJ_INET6_ADDRSTRLEN];
2165 #endif
2166     unsigned tp_idx = GET_TP_IDX(transport_id);
2167     unsigned tp_typ = GET_TP_TYPE(transport_id);
2168 
2169     PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL);
2170 
2171     pj_grp_lock_acquire(ice_st->grp_lock);
2172     if (ice_st->num_buf > 0 &&
2173         (!ice_st->send_buf ||
2174          ice_st->send_buf[ice_st->buf_idx].buffer != pkt))
2175     {
2176         use_buf = PJ_TRUE;
2177     	status = use_buffer(ice_st, comp_id, pkt, size, dst_addr,
2178     			    dst_addr_len, &buf);
2179     	if (status == PJ_EPENDING || status != PJ_SUCCESS) {
2180     	    pj_grp_lock_release(ice_st->grp_lock);
2181     	    return status;
2182     	}
2183     }
2184     pj_grp_lock_release(ice_st->grp_lock);
2185 
2186     comp = ice_st->comp[comp_id-1];
2187 
2188     TRACE_PKT((comp->ice_st->obj_name,
2189 	       "Component %d TX packet to %s:%d with transport %d",
2190 	       comp_id,
2191 	       pj_sockaddr_print(dst_addr, daddr, sizeof(addr), 2),
2192 	       pj_sockaddr_get_port(dst_addr),
2193 	       tp_typ));
2194 
2195     if (tp_typ == TP_TURN) {
2196 	if (comp->turn[tp_idx].sock) {
2197 	    status = pj_turn_sock_sendto(comp->turn[tp_idx].sock,
2198 					 (const pj_uint8_t*)buf,
2199 					 (unsigned)size,
2200 					 dst_addr, dst_addr_len);
2201 	} else {
2202 	    status = PJ_EINVALIDOP;
2203 	}
2204     } else if (tp_typ == TP_STUN) {
2205     	const pj_sockaddr_t *dest_addr;
2206     	unsigned dest_addr_len;
2207 
2208     	if (comp->ipv4_mapped) {
2209     	    if (comp->synth_addr_len == 0 ||
2210     	    	pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0)
2211     	    {
2212     	    	status = pj_sockaddr_synthesize(pj_AF_INET6(),
2213     	    					&comp->synth_addr, dst_addr);
2214     	    	if (status != PJ_SUCCESS) {
2215     	    	    goto on_return;
2216     	    	}
2217 
2218     	    	pj_sockaddr_cp(&comp->dst_addr, dst_addr);
2219     	    	comp->synth_addr_len = pj_sockaddr_get_len(&comp->synth_addr);
2220     	    }
2221 	    dest_addr = &comp->synth_addr;
2222     	    dest_addr_len = comp->synth_addr_len;
2223     	} else {
2224     	    dest_addr = dst_addr;
2225     	    dest_addr_len = dst_addr_len;
2226     	}
2227 
2228 	status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL,
2229 				     buf, (unsigned)size, 0,
2230 				     dest_addr, dest_addr_len);
2231     } else {
2232 	pj_assert(!"Invalid transport ID");
2233 	status = PJ_EINVALIDOP;
2234     }
2235 
2236 on_return:
2237     if (use_buf && status != PJ_EPENDING) {
2238         pj_grp_lock_acquire(ice_st->grp_lock);
2239     	if (ice_st->num_buf > 0) {
2240     	    ice_st->buf_idx = (ice_st->buf_idx + 1) % ice_st->num_buf;
2241     	    pj_assert(ice_st->buf_idx == ice_st->empty_idx);
2242     	}
2243     	ice_st->is_pending = PJ_FALSE;
2244     	pj_grp_lock_release(ice_st->grp_lock);
2245     }
2246 
2247     return status;
2248 }
2249 
2250 /*
2251  * Callback called by ICE session when it receives application data.
2252  */
ice_rx_data(pj_ice_sess * ice,unsigned comp_id,unsigned transport_id,void * pkt,pj_size_t size,const pj_sockaddr_t * src_addr,unsigned src_addr_len)2253 static void ice_rx_data(pj_ice_sess *ice,
2254 		        unsigned comp_id,
2255 			unsigned transport_id,
2256 		        void *pkt, pj_size_t size,
2257 		        const pj_sockaddr_t *src_addr,
2258 		        unsigned src_addr_len)
2259 {
2260     pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
2261 
2262     PJ_UNUSED_ARG(transport_id);
2263 
2264     if (ice_st->cb.on_rx_data) {
2265 	(*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size,
2266 				 src_addr, src_addr_len);
2267     }
2268 }
2269 
check_pending_send(pj_ice_strans * ice_st)2270 static void check_pending_send(pj_ice_strans *ice_st)
2271 {
2272     pj_grp_lock_acquire(ice_st->grp_lock);
2273 
2274     if (ice_st->num_buf > 0)
2275         ice_st->buf_idx = (ice_st->buf_idx + 1) % ice_st->num_buf;
2276 
2277     if (ice_st->num_buf > 0 && ice_st->buf_idx != ice_st->empty_idx) {
2278 	/* There's some pending send. Send it one by one. */
2279         pending_send *ps = &ice_st->send_buf[ice_st->buf_idx];
2280 
2281 	pj_grp_lock_release(ice_st->grp_lock);
2282     	send_data(ice_st, ps->comp_id, ps->buffer, ps->data_len,
2283     	    	  &ps->dst_addr, ps->dst_addr_len, PJ_FALSE, PJ_TRUE);
2284     } else {
2285     	ice_st->is_pending = PJ_FALSE;
2286     	pj_grp_lock_release(ice_st->grp_lock);
2287     }
2288 }
2289 
2290 /* Notifification when asynchronous send operation via STUN/TURN
2291  * has completed.
2292  */
on_data_sent(pj_ice_strans * ice_st,pj_ssize_t sent)2293 static pj_bool_t on_data_sent(pj_ice_strans *ice_st, pj_ssize_t sent)
2294 {
2295     if (ice_st->destroy_req || !ice_st->is_pending)
2296 	return PJ_TRUE;
2297 
2298     if (ice_st->call_send_cb && ice_st->cb.on_data_sent) {
2299 	(*ice_st->cb.on_data_sent)(ice_st, sent);
2300     }
2301 
2302     check_pending_send(ice_st);
2303 
2304     return PJ_TRUE;
2305 }
2306 
2307 /* Notification when incoming packet has been received from
2308  * the STUN socket.
2309  */
stun_on_rx_data(pj_stun_sock * stun_sock,void * pkt,unsigned pkt_len,const pj_sockaddr_t * src_addr,unsigned addr_len)2310 static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
2311 				 void *pkt,
2312 				 unsigned pkt_len,
2313 				 const pj_sockaddr_t *src_addr,
2314 				 unsigned addr_len)
2315 {
2316     sock_user_data *data;
2317     pj_ice_strans_comp *comp;
2318     pj_ice_strans *ice_st;
2319     pj_status_t status;
2320 
2321     data = (sock_user_data*) pj_stun_sock_get_user_data(stun_sock);
2322     if (data == NULL) {
2323 	/* We have disassociated ourselves from the STUN socket */
2324 	return PJ_FALSE;
2325     }
2326 
2327     comp = data->comp;
2328     ice_st = comp->ice_st;
2329 
2330     pj_grp_lock_add_ref(ice_st->grp_lock);
2331 
2332     if (ice_st->ice == NULL) {
2333 	/* The ICE session is gone, but we're still receiving packets.
2334 	 * This could also happen if remote doesn't do ICE. So just
2335 	 * report this to application.
2336 	 */
2337 	if (ice_st->cb.on_rx_data) {
2338 	    (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, pkt, pkt_len,
2339 				     src_addr, addr_len);
2340 	}
2341 
2342     } else {
2343 
2344 	/* Hand over the packet to ICE session */
2345 	status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
2346 				       data->transport_id,
2347 				       pkt, pkt_len,
2348 				       src_addr, addr_len);
2349 
2350 	if (status != PJ_SUCCESS) {
2351 	    ice_st_perror(comp->ice_st, "Error processing packet",
2352 			  status);
2353 	}
2354     }
2355 
2356     return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
2357 }
2358 
2359 /* Notifification when asynchronous send operation to the STUN socket
2360  * has completed.
2361  */
stun_on_data_sent(pj_stun_sock * stun_sock,pj_ioqueue_op_key_t * send_key,pj_ssize_t sent)2362 static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
2363 				   pj_ioqueue_op_key_t *send_key,
2364 				   pj_ssize_t sent)
2365 {
2366     sock_user_data *data;
2367 
2368     PJ_UNUSED_ARG(send_key);
2369 
2370     data = (sock_user_data *)pj_stun_sock_get_user_data(stun_sock);
2371     if (!data || !data->comp || !data->comp->ice_st) return PJ_TRUE;
2372 
2373     return on_data_sent(data->comp->ice_st, sent);
2374 }
2375 
2376 /* Notification when the status of the STUN transport has changed. */
stun_on_status(pj_stun_sock * stun_sock,pj_stun_sock_op op,pj_status_t status)2377 static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
2378 				pj_stun_sock_op op,
2379 				pj_status_t status)
2380 {
2381     sock_user_data *data;
2382     pj_ice_strans_comp *comp;
2383     pj_ice_strans *ice_st;
2384     pj_ice_sess_cand *cand = NULL;
2385     unsigned i;
2386     int tp_idx;
2387 
2388     pj_assert(status != PJ_EPENDING);
2389 
2390     data = (sock_user_data*) pj_stun_sock_get_user_data(stun_sock);
2391     comp = data->comp;
2392     ice_st = comp->ice_st;
2393 
2394     pj_grp_lock_add_ref(ice_st->grp_lock);
2395 
2396     /* Wait until initialization completes */
2397     pj_grp_lock_acquire(ice_st->grp_lock);
2398 
2399     /* Find the srflx cancidate */
2400     for (i=0; i<comp->cand_cnt; ++i) {
2401 	if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX &&
2402 	    comp->cand_list[i].transport_id == data->transport_id)
2403 	{
2404 	    cand = &comp->cand_list[i];
2405 	    break;
2406 	}
2407     }
2408 
2409     pj_grp_lock_release(ice_st->grp_lock);
2410 
2411     /* It is possible that we don't have srflx candidate even though this
2412      * callback is called. This could happen when we cancel adding srflx
2413      * candidate due to initialization error.
2414      */
2415     if (cand == NULL) {
2416 	return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
2417     }
2418 
2419     tp_idx = GET_TP_IDX(data->transport_id);
2420 
2421     switch (op) {
2422     case PJ_STUN_SOCK_DNS_OP:
2423 	if (status != PJ_SUCCESS) {
2424 	    /* May not have cand, e.g. when error during init */
2425 	    if (cand)
2426 		cand->status = status;
2427 	    if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error) {
2428 		sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
2429 		          "DNS resolution failed", status);
2430 	    } else {
2431 		PJ_LOG(4,(ice_st->obj_name,
2432 			  "STUN error is ignored for comp %d",
2433 			  comp->comp_id));
2434 	    }
2435 	}
2436 	break;
2437     case PJ_STUN_SOCK_BINDING_OP:
2438     case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
2439 	if (status == PJ_SUCCESS) {
2440 	    pj_stun_sock_info info;
2441 
2442 	    status = pj_stun_sock_get_info(stun_sock, &info);
2443 	    if (status == PJ_SUCCESS) {
2444 		char ipaddr[PJ_INET6_ADDRSTRLEN+10];
2445 		const char *op_name = (op==PJ_STUN_SOCK_BINDING_OP) ?
2446 				    "Binding discovery complete" :
2447 				    "srflx address changed";
2448 		pj_bool_t dup = PJ_FALSE;
2449 		pj_bool_t init_done;
2450 
2451 		if (info.mapped_addr.addr.sa_family == pj_AF_INET() &&
2452 		    cand->base_addr.addr.sa_family == pj_AF_INET6())
2453 		{
2454 		    /* We get an IPv4 mapped address for our IPv6
2455 		     * host address.
2456 		     */
2457 		    comp->ipv4_mapped = PJ_TRUE;
2458 
2459 		    /* Find other host candidates with the same (IPv6)
2460 		     * address, and replace it with the new (IPv4)
2461 		     * mapped address.
2462 		     */
2463 		    for (i = 0; i < comp->cand_cnt; ++i) {
2464 		        pj_sockaddr *a1, *a2;
2465 
2466 		        if (comp->cand_list[i].type != PJ_ICE_CAND_TYPE_HOST)
2467 		            continue;
2468 
2469 		        a1 = &comp->cand_list[i].addr;
2470 		        a2 = &cand->base_addr;
2471 		        if (pj_memcmp(pj_sockaddr_get_addr(a1),
2472 		       		      pj_sockaddr_get_addr(a2),
2473 		       		      pj_sockaddr_get_addr_len(a1)) == 0)
2474 		       	{
2475 		       	    pj_uint16_t port = pj_sockaddr_get_port(a1);
2476 		       	    pj_sockaddr_cp(a1, &info.mapped_addr);
2477 		       	    if (port != pj_sockaddr_get_port(a2))
2478 		       	        pj_sockaddr_set_port(a1, port);
2479 		       	    pj_sockaddr_cp(&comp->cand_list[i].base_addr, a1);
2480 		       	}
2481 		    }
2482 		    pj_sockaddr_cp(&cand->base_addr, &info.mapped_addr);
2483 		    pj_sockaddr_cp(&cand->rel_addr, &info.mapped_addr);
2484 		}
2485 
2486 		/* Eliminate the srflx candidate if the address is
2487 		 * equal to other (host) candidates.
2488 		 */
2489 		for (i=0; i<comp->cand_cnt; ++i) {
2490 		    if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_HOST &&
2491 			pj_sockaddr_cmp(&comp->cand_list[i].addr,
2492 					&info.mapped_addr) == 0)
2493 		    {
2494 			dup = PJ_TRUE;
2495 			break;
2496 		    }
2497 		}
2498 
2499 		if (dup) {
2500 		    /* Duplicate found, remove the srflx candidate */
2501 		    unsigned idx = (unsigned)(cand - comp->cand_list);
2502 
2503 		    /* Update default candidate index */
2504 		    if (comp->default_cand > idx) {
2505 			--comp->default_cand;
2506 		    } else if (comp->default_cand == idx) {
2507 			comp->default_cand = 0;
2508 		    }
2509 
2510 		    /* Remove srflx candidate */
2511 		    pj_array_erase(comp->cand_list, sizeof(comp->cand_list[0]),
2512 				   comp->cand_cnt, idx);
2513 		    --comp->cand_cnt;
2514 		} else {
2515 		    /* Otherwise update the address */
2516 		    pj_sockaddr_cp(&cand->addr, &info.mapped_addr);
2517 		    cand->status = PJ_SUCCESS;
2518 
2519 		    /* Add the candidate (for trickle ICE) */
2520 		    if (pj_ice_strans_has_sess(ice_st)) {
2521 			status = pj_ice_sess_add_cand(
2522 					ice_st->ice,
2523 					comp->comp_id,
2524 					cand->transport_id,
2525 					cand->type,
2526 					cand->local_pref,
2527 					&cand->foundation,
2528 					&cand->addr,
2529 					&cand->base_addr,
2530 					&cand->rel_addr,
2531 					pj_sockaddr_get_len(&cand->addr),
2532 					NULL);
2533 		    }
2534 		}
2535 
2536 		PJ_LOG(4,(comp->ice_st->obj_name,
2537 			  "Comp %d: %s, "
2538 			  "srflx address is %s",
2539 			  comp->comp_id, op_name,
2540 			  pj_sockaddr_print(&info.mapped_addr, ipaddr,
2541 					     sizeof(ipaddr), 3)));
2542 
2543 		sess_init_update(ice_st);
2544 
2545 		/* Invoke on_new_candidate() callback */
2546 		init_done = (ice_st->state==PJ_ICE_STRANS_STATE_READY);
2547 		if (op == PJ_STUN_SOCK_BINDING_OP && status == PJ_SUCCESS &&
2548 		    ice_st->cb.on_new_candidate && (!dup || init_done))
2549 		{
2550 		    (*ice_st->cb.on_new_candidate)
2551 					(ice_st, (dup? NULL:cand), init_done);
2552 		}
2553 
2554 		if (op == PJ_STUN_SOCK_MAPPED_ADDR_CHANGE &&
2555 		    ice_st->cb.on_ice_complete)
2556 		{
2557 		    (*ice_st->cb.on_ice_complete)(ice_st,
2558 		    				  PJ_ICE_STRANS_OP_ADDR_CHANGE,
2559 		    				  status);
2560 		}
2561 	    }
2562 	}
2563 
2564 	if (status != PJ_SUCCESS) {
2565 	    /* May not have cand, e.g. when error during init */
2566 	    if (cand)
2567 		cand->status = status;
2568 	    if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error ||
2569 		comp->cand_cnt==1)
2570 	    {
2571 		sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
2572 			  "STUN binding request failed", status);
2573 	    } else {
2574 		pj_bool_t init_done;
2575 
2576 		PJ_LOG(4,(ice_st->obj_name,
2577 			  "STUN error is ignored for comp %d",
2578 			  comp->comp_id));
2579 
2580 		if (cand) {
2581 		    unsigned idx = (unsigned)(cand - comp->cand_list);
2582 
2583 		    /* Update default candidate index */
2584 		    if (comp->default_cand == idx) {
2585 			comp->default_cand = !idx;
2586 		    }
2587 		}
2588 
2589 		sess_init_update(ice_st);
2590 
2591 		/* Invoke on_new_candidate() callback */
2592 		init_done = (ice_st->state==PJ_ICE_STRANS_STATE_READY);
2593 		if (op == PJ_STUN_SOCK_BINDING_OP &&
2594 		    ice_st->cb.on_new_candidate && init_done)
2595 		{
2596 		    (*ice_st->cb.on_new_candidate) (ice_st, NULL, PJ_TRUE);
2597 		}
2598 	    }
2599 	}
2600 	break;
2601     case PJ_STUN_SOCK_KEEP_ALIVE_OP:
2602 	if (status != PJ_SUCCESS) {
2603 	    pj_assert(cand != NULL);
2604 	    cand->status = status;
2605 	    if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error) {
2606 		sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
2607 			  "STUN keep-alive failed", status);
2608 	    } else {
2609 		PJ_LOG(4,(ice_st->obj_name, "STUN error is ignored"));
2610 	    }
2611 	}
2612 	break;
2613     }
2614 
2615     return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE;
2616 }
2617 
2618 /* Callback when TURN socket has received a packet */
turn_on_rx_data(pj_turn_sock * turn_sock,void * pkt,unsigned pkt_len,const pj_sockaddr_t * peer_addr,unsigned addr_len)2619 static void turn_on_rx_data(pj_turn_sock *turn_sock,
2620 			    void *pkt,
2621 			    unsigned pkt_len,
2622 			    const pj_sockaddr_t *peer_addr,
2623 			    unsigned addr_len)
2624 {
2625     pj_ice_strans_comp *comp;
2626     sock_user_data *data;
2627     pj_status_t status;
2628 
2629     data = (sock_user_data*) pj_turn_sock_get_user_data(turn_sock);
2630     if (data == NULL) {
2631 	/* We have disassociated ourselves from the TURN socket */
2632 	return;
2633     }
2634 
2635     comp = data->comp;
2636 
2637     pj_grp_lock_add_ref(comp->ice_st->grp_lock);
2638 
2639     if (comp->ice_st->ice == NULL) {
2640 	/* The ICE session is gone, but we're still receiving packets.
2641 	 * This could also happen if remote doesn't do ICE and application
2642 	 * specifies TURN as the default address in SDP.
2643 	 * So in this case just give the packet to application.
2644 	 */
2645 	if (comp->ice_st->cb.on_rx_data) {
2646 	    (*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt,
2647 					   pkt_len, peer_addr, addr_len);
2648 	}
2649 
2650     } else {
2651 
2652 	/* Hand over the packet to ICE */
2653 	status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
2654 				       data->transport_id, pkt, pkt_len,
2655 				       peer_addr, addr_len);
2656 
2657 	if (status != PJ_SUCCESS) {
2658 	    ice_st_perror(comp->ice_st,
2659 			  "Error processing packet from TURN relay",
2660 			  status);
2661 	}
2662     }
2663 
2664     pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
2665 }
2666 
2667 /* Notifification when asynchronous send operation to the TURN socket
2668  * has completed.
2669  */
turn_on_data_sent(pj_turn_sock * turn_sock,pj_ssize_t sent)2670 static pj_bool_t turn_on_data_sent(pj_turn_sock *turn_sock,
2671 				   pj_ssize_t sent)
2672 {
2673     sock_user_data *data;
2674 
2675     data = (sock_user_data *)pj_turn_sock_get_user_data(turn_sock);
2676     if (!data || !data->comp || !data->comp->ice_st) return PJ_TRUE;
2677 
2678     return on_data_sent(data->comp->ice_st, sent);
2679 }
2680 
2681 /* Callback when TURN client state has changed */
turn_on_state(pj_turn_sock * turn_sock,pj_turn_state_t old_state,pj_turn_state_t new_state)2682 static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
2683 			  pj_turn_state_t new_state)
2684 {
2685     pj_ice_strans_comp *comp;
2686     sock_user_data *data;
2687     int tp_idx;
2688 
2689     data = (sock_user_data*) pj_turn_sock_get_user_data(turn_sock);
2690     if (data == NULL) {
2691 	/* Not interested in further state notification once the relay is
2692 	 * disconnecting.
2693 	 */
2694 	return;
2695     }
2696 
2697     comp = data->comp;
2698     tp_idx = GET_TP_IDX(data->transport_id);
2699 
2700     PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s",
2701 	      pj_turn_state_name(old_state), pj_turn_state_name(new_state)));
2702     pj_log_push_indent();
2703 
2704     pj_grp_lock_add_ref(comp->ice_st->grp_lock);
2705 
2706     if (new_state == PJ_TURN_STATE_READY) {
2707 	pj_turn_session_info rel_info;
2708 	char ipaddr[PJ_INET6_ADDRSTRLEN+8];
2709 	pj_ice_sess_cand *cand = NULL;
2710 	unsigned i, cand_idx = 0xFF;
2711 
2712 	comp->turn[tp_idx].err_cnt = 0;
2713 
2714 	/* Get allocation info */
2715 	pj_turn_sock_get_info(turn_sock, &rel_info);
2716 
2717 	/* Wait until initialization completes */
2718 	pj_grp_lock_acquire(comp->ice_st->grp_lock);
2719 
2720 	/* Find relayed candidate in the component */
2721 	for (i=0; i<comp->cand_cnt; ++i) {
2722 	    if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED &&
2723 		comp->cand_list[i].transport_id == data->transport_id)
2724 	    {
2725 		cand = &comp->cand_list[i];
2726 		cand_idx = i;
2727 		break;
2728 	    }
2729 	}
2730 
2731 	pj_grp_lock_release(comp->ice_st->grp_lock);
2732 
2733 	if (cand == NULL)
2734 	    goto on_return;
2735 
2736 	/* Update candidate */
2737 	pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr);
2738 	pj_sockaddr_cp(&cand->base_addr, &rel_info.relay_addr);
2739 	pj_sockaddr_cp(&cand->rel_addr, &rel_info.mapped_addr);
2740 	pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation,
2741 			       PJ_ICE_CAND_TYPE_RELAYED,
2742 			       &rel_info.relay_addr);
2743 	cand->status = PJ_SUCCESS;
2744 
2745 	/* Set default candidate to relay */
2746 	if (comp->cand_list[comp->default_cand].type!=PJ_ICE_CAND_TYPE_RELAYED
2747 	    || (comp->ice_st->cfg.af != pj_AF_UNSPEC() &&
2748 	        comp->cand_list[comp->default_cand].addr.addr.sa_family
2749 	        != comp->ice_st->cfg.af))
2750 	{
2751 	    comp->default_cand = (unsigned)(cand - comp->cand_list);
2752 	}
2753 
2754 	/* Prefer IPv4 relay as default candidate for better connectivity
2755 	 * with IPv4 endpoints.
2756 	 */
2757 	/*
2758 	if (cand->addr.addr.sa_family != pj_AF_INET()) {
2759 	    for (i=0; i<comp->cand_cnt; ++i) {
2760 		if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED &&
2761 		    comp->cand_list[i].addr.addr.sa_family == pj_AF_INET() &&
2762 		    comp->cand_list[i].status == PJ_SUCCESS)
2763 		{
2764 		    comp->default_cand = i;
2765 		    break;
2766 		}
2767 	    }
2768 	}
2769 	*/
2770 
2771 	PJ_LOG(4,(comp->ice_st->obj_name,
2772 		  "Comp %d/%d: TURN allocation (tpid=%d) complete, "
2773 		  "relay address is %s",
2774 		  comp->comp_id, cand_idx, cand->transport_id,
2775 		  pj_sockaddr_print(&rel_info.relay_addr, ipaddr,
2776 				     sizeof(ipaddr), 3)));
2777 
2778 	/* For trickle ICE, add the candidate to ICE session and setup TURN
2779 	 * permission for remote candidates.
2780 	 */
2781 	if (comp->ice_st->cfg.opt.trickle != PJ_ICE_SESS_TRICKLE_DISABLED &&
2782 	    pj_ice_strans_has_sess(comp->ice_st))
2783 	{
2784 	    pj_sockaddr addrs[PJ_ICE_ST_MAX_CAND];
2785 	    pj_ice_sess *sess = comp->ice_st->ice;
2786 	    unsigned j, count=0;
2787 	    pj_status_t status;
2788 
2789 	    /* Add the candidate */
2790 	    status = pj_ice_sess_add_cand(comp->ice_st->ice,
2791 					  comp->comp_id,
2792 					  cand->transport_id,
2793 					  cand->type,
2794 					  cand->local_pref,
2795 					  &cand->foundation,
2796 					  &cand->addr,
2797 					  &cand->base_addr,
2798 					  &cand->rel_addr,
2799 					  pj_sockaddr_get_len(&cand->addr),
2800 					  NULL);
2801 	    if (status != PJ_SUCCESS) {
2802 		PJ_PERROR(4,(comp->ice_st->obj_name, status,
2803 			  "Comp %d/%d: failed to add TURN (tpid=%d) to ICE",
2804 			  comp->comp_id, cand_idx, cand->transport_id));
2805 		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
2806 			  "adding TURN candidate failed", status);
2807 	    }
2808 
2809 	    /* Gather remote addresses for this component */
2810 	    for (j=0; j<sess->rcand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) {
2811 		if (sess->rcand[j].addr.addr.sa_family==
2812 		    rel_info.relay_addr.addr.sa_family)
2813 		{
2814 		    pj_sockaddr_cp(&addrs[count++], &sess->rcand[j].addr);
2815 		}
2816 	    }
2817 
2818 	    if (count) {
2819 		status = pj_turn_sock_set_perm(turn_sock, count, addrs, 0);
2820 		if (status != PJ_SUCCESS) {
2821 		    PJ_PERROR(4,(comp->ice_st->obj_name, status,
2822 			      "Comp %d/%d: TURN set perm (tpid=%d) failed",
2823 			      comp->comp_id, cand_idx, cand->transport_id));
2824 		    sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
2825 			      "TURN set permission failed", status);
2826 		}
2827 	    }
2828 	}
2829 
2830 	sess_init_update(comp->ice_st);
2831 
2832 	/* Invoke on_new_candidate() callback */
2833 	if (comp->ice_st->cb.on_new_candidate) {
2834 	    (*comp->ice_st->cb.on_new_candidate)
2835 			(comp->ice_st, cand,
2836 			 (comp->ice_st->state==PJ_ICE_STRANS_STATE_READY));
2837 	}
2838 
2839     } else if ((old_state == PJ_TURN_STATE_RESOLVING ||
2840                 old_state == PJ_TURN_STATE_RESOLVED ||
2841                 old_state == PJ_TURN_STATE_ALLOCATING) &&
2842 	       new_state >= PJ_TURN_STATE_DEALLOCATING)
2843     {
2844 	pj_ice_sess_cand *cand = NULL;
2845 	unsigned i, cand_idx = 0xFF;
2846 
2847 	/* DNS resolution or TURN transport creation/allocation
2848 	 * has failed.
2849 	 */
2850 	++comp->turn[tp_idx].err_cnt;
2851 
2852 	/* Unregister ourself from the TURN relay */
2853 	pj_turn_sock_set_user_data(turn_sock, NULL);
2854 	comp->turn[tp_idx].sock = NULL;
2855 
2856 	/* Wait until initialization completes */
2857 	pj_grp_lock_acquire(comp->ice_st->grp_lock);
2858 
2859 	/* Find relayed candidate in the component */
2860 	for (i=0; i<comp->cand_cnt; ++i) {
2861 	    if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED &&
2862 		comp->cand_list[i].transport_id == data->transport_id)
2863 	    {
2864 		cand = &comp->cand_list[i];
2865 		cand_idx = i;
2866 		break;
2867 	    }
2868 	}
2869 
2870 	pj_grp_lock_release(comp->ice_st->grp_lock);
2871 
2872 	/* If the error happens during pj_turn_sock_create() or
2873 	 * pj_turn_sock_alloc(), the candidate hasn't been added
2874 	 * to the list.
2875 	 */
2876 	if (cand) {
2877 	    pj_turn_session_info info;
2878 
2879 	    pj_turn_sock_get_info(turn_sock, &info);
2880 	    cand->status = (old_state == PJ_TURN_STATE_RESOLVING)?
2881 	    		   PJ_ERESOLVE : info.last_status;
2882 	    PJ_LOG(4,(comp->ice_st->obj_name,
2883 		      "Comp %d/%d: TURN error (tpid=%d) during state %s",
2884 		      comp->comp_id, cand_idx, cand->transport_id,
2885 		      pj_turn_state_name(old_state)));
2886 	}
2887 
2888 	sess_init_update(comp->ice_st);
2889 
2890 	/* Invoke on_new_candidate() callback */
2891 	if (comp->ice_st->cb.on_new_candidate &&
2892 	    comp->ice_st->state==PJ_ICE_STRANS_STATE_READY)
2893 	{
2894 	    (*comp->ice_st->cb.on_new_candidate)(comp->ice_st, NULL, PJ_TRUE);
2895 	}
2896 
2897     } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
2898 	pj_turn_session_info info;
2899 
2900 	++comp->turn[tp_idx].err_cnt;
2901 
2902 	pj_turn_sock_get_info(turn_sock, &info);
2903 
2904 	/* Unregister ourself from the TURN relay */
2905 	pj_turn_sock_set_user_data(turn_sock, NULL);
2906 	comp->turn[tp_idx].sock = NULL;
2907 
2908 	/* Set session to fail on error. last_status PJ_SUCCESS means normal
2909 	 * deallocation, which should not trigger sess_fail as it may have
2910 	 * been initiated by ICE destroy
2911 	 */
2912 	if (info.last_status != PJ_SUCCESS) {
2913 	    if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
2914 		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
2915 			  "TURN allocation failed", info.last_status);
2916 	    } else if (comp->turn[tp_idx].err_cnt > 1) {
2917 		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE,
2918 			  "TURN refresh failed", info.last_status);
2919 	    } else {
2920 		PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status,
2921 			  "Comp %d: TURN allocation failed, retrying",
2922 			  comp->comp_id));
2923 		add_update_turn(comp->ice_st, comp, tp_idx,
2924 				PJ_ICE_ST_MAX_CAND - comp->cand_cnt);
2925 	    }
2926 	}
2927     }
2928 
2929 on_return:
2930     pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
2931 
2932     pj_log_pop_indent();
2933 }
2934 
2935