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 <pjmedia/transport_ice.h>
21 #include <pjnath/errno.h>
22 #include <pj/assert.h>
23 #include <pj/log.h>
24 #include <pj/pool.h>
25 #include <pj/rand.h>
26 
27 #define THIS_FILE   "transport_ice.c"
28 #if 0
29 #   define TRACE__(expr)    PJ_LOG(5,expr)
30 #else
31 #   define TRACE__(expr)
32 #endif
33 
34 enum oa_role
35 {
36     ROLE_NONE,
37     ROLE_OFFERER,
38     ROLE_ANSWERER
39 };
40 
41 struct sdp_state
42 {
43     unsigned		match_comp_cnt;	/* Matching number of components    */
44     pj_bool_t		ice_mismatch;	/* Address doesn't match candidates */
45     pj_bool_t		ice_restart;	/* Offer to restart ICE		    */
46     pj_ice_sess_role	local_role;	/* Our role			    */
47     pj_bool_t		has_trickle;	/* Has trickle ICE attribute	    */
48 };
49 
50 /* ICE listener */
51 typedef struct ice_listener
52 {
53     PJ_DECL_LIST_MEMBER(struct ice_listener);
54     pjmedia_ice_cb	 cb;
55     void		*user_data;
56 } ice_listener;
57 
58 struct transport_ice
59 {
60     pjmedia_transport	 base;
61     pj_pool_t		*pool;
62     unsigned		 options;	/**< Transport options.		    */
63 
64     unsigned		 comp_cnt;
65     pj_ice_strans	*ice_st;
66 
67     pjmedia_ice_cb	 cb;
68     ice_listener	 listener;
69     ice_listener	 listener_empty;
70     unsigned		 media_option;
71 
72     pj_bool_t		 initial_sdp;
73     enum oa_role	 oa_role;	/**< Last role in SDP offer/answer  */
74     struct sdp_state	 rem_offer_state;/**< Describes the remote offer    */
75 
76     void		*stream;
77     pj_sockaddr		 remote_rtp;
78     pj_sockaddr		 remote_rtcp;
79     unsigned		 addr_len;	/**< Length of addresses.	    */
80 
81     pj_bool_t		 use_ice;
82     pj_sockaddr		 rtp_src_addr;	/**< Actual source RTP address.	    */
83     unsigned		 rtp_src_cnt;   /**< How many pkt from this addr.   */
84     pj_sockaddr		 rtcp_src_addr;	/**< Actual source RTCP address.    */
85     unsigned		 rtcp_src_cnt;  /**< How many pkt from this addr.   */
86     pj_bool_t		 enable_rtcp_mux;/**< Enable RTP& RTCP multiplexing?*/
87     pj_bool_t		 use_rtcp_mux;	/**< Use RTP & RTCP multiplexing?   */
88 
89     unsigned		 tx_drop_pct;	/**< Percent of tx pkts to drop.    */
90     unsigned		 rx_drop_pct;	/**< Percent of rx pkts to drop.    */
91 
92     pj_ice_sess_trickle	 trickle_ice;	/**< Trickle ICE mode.		    */
93     unsigned		 last_send_cand_cnt[PJ_ICE_MAX_COMP];
94 					/**< Last local candidate count.    */
95     pj_bool_t		 end_of_cand;	/**< Local cand gathering done?	    */
96     pj_str_t		 sdp_mid;	/**< SDP "a=mid" attribute.	    */
97 
98     void	       (*rtp_cb)(void*,
99 			         void*,
100 				 pj_ssize_t);
101     void	       (*rtp_cb2)(pjmedia_tp_cb_param*);
102     void	       (*rtcp_cb)(void*,
103 				  void*,
104 				  pj_ssize_t);
105 };
106 
107 
108 /*
109  * These are media transport operations.
110  */
111 static pj_status_t transport_get_info (pjmedia_transport *tp,
112 				       pjmedia_transport_info *info);
113 static pj_status_t transport_attach   (pjmedia_transport *tp,
114 				       void *user_data,
115 				       const pj_sockaddr_t *rem_addr,
116 				       const pj_sockaddr_t *rem_rtcp,
117 				       unsigned addr_len,
118 				       void (*rtp_cb)(void*,
119 						      void*,
120 						      pj_ssize_t),
121 				       void (*rtcp_cb)(void*,
122 						       void*,
123 						       pj_ssize_t));
124 static pj_status_t transport_attach2  (pjmedia_transport *tp,
125 				       pjmedia_transport_attach_param
126 				           *att_param);
127 static void	   transport_detach   (pjmedia_transport *tp,
128 				       void *strm);
129 static pj_status_t transport_send_rtp( pjmedia_transport *tp,
130 				       const void *pkt,
131 				       pj_size_t size);
132 static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
133 				       const void *pkt,
134 				       pj_size_t size);
135 static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
136 				       const pj_sockaddr_t *addr,
137 				       unsigned addr_len,
138 				       const void *pkt,
139 				       pj_size_t size);
140 static pj_status_t transport_media_create(pjmedia_transport *tp,
141 				       pj_pool_t *pool,
142 				       unsigned options,
143 				       const pjmedia_sdp_session *rem_sdp,
144 				       unsigned media_index);
145 static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
146 				        pj_pool_t *tmp_pool,
147 				        pjmedia_sdp_session *sdp_local,
148 				        const pjmedia_sdp_session *rem_sdp,
149 				        unsigned media_index);
150 static pj_status_t transport_media_start(pjmedia_transport *tp,
151 				       pj_pool_t *pool,
152 				       const pjmedia_sdp_session *sdp_local,
153 				       const pjmedia_sdp_session *rem_sdp,
154 				       unsigned media_index);
155 static pj_status_t transport_media_stop(pjmedia_transport *tp);
156 static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
157 				       pjmedia_dir dir,
158 				       unsigned pct_lost);
159 static pj_status_t transport_destroy  (pjmedia_transport *tp);
160 
161 /*
162  * And these are ICE callbacks.
163  */
164 static void ice_on_rx_data(pj_ice_strans *ice_st,
165 			   unsigned comp_id,
166 			   void *pkt, pj_size_t size,
167 			   const pj_sockaddr_t *src_addr,
168 			   unsigned src_addr_len);
169 static void ice_on_ice_complete(pj_ice_strans *ice_st,
170 				pj_ice_strans_op op,
171 			        pj_status_t status);
172 static void ice_on_new_candidate(pj_ice_strans *ice_st,
173 				 const pj_ice_sess_cand *cand,
174 			         pj_bool_t last);
175 
176 /*
177  * Clean up ICE resources.
178  */
179 static void tp_ice_on_destroy(void *arg);
180 
181 
182 static pjmedia_transport_op transport_ice_op =
183 {
184     &transport_get_info,
185     &transport_attach,
186     &transport_detach,
187     &transport_send_rtp,
188     &transport_send_rtcp,
189     &transport_send_rtcp2,
190     &transport_media_create,
191     &transport_encode_sdp,
192     &transport_media_start,
193     &transport_media_stop,
194     &transport_simulate_lost,
195     &transport_destroy,
196     &transport_attach2
197 };
198 
199 static const pj_str_t STR_CANDIDATE	= { "candidate", 9};
200 static const pj_str_t STR_REM_CAND	= { "remote-candidates", 17 };
201 static const pj_str_t STR_ICE_LITE	= { "ice-lite", 8};
202 static const pj_str_t STR_ICE_MISMATCH	= { "ice-mismatch", 12};
203 static const pj_str_t STR_ICE_UFRAG	= { "ice-ufrag", 9 };
204 static const pj_str_t STR_ICE_PWD	= { "ice-pwd", 7 };
205 static const pj_str_t STR_IP4		= { "IP4", 3 };
206 static const pj_str_t STR_IP6		= { "IP6", 3 };
207 static const pj_str_t STR_RTCP		= { "rtcp", 4 };
208 static const pj_str_t STR_RTCP_MUX	= { "rtcp-mux", 8 };
209 static const pj_str_t STR_BANDW_RR	= { "RR", 2 };
210 static const pj_str_t STR_BANDW_RS	= { "RS", 2 };
211 static const pj_str_t STR_ICE_OPTIONS	= { "ice-options", 11 };
212 static const pj_str_t STR_TRICKLE	= { "trickle", 7 };
213 static const pj_str_t STR_END_OF_CAND	= { "end-of-candidates", 17 };
214 
215 enum {
216     COMP_RTP = 1,
217     COMP_RTCP = 2
218 };
219 
220 
221 /* Forward declaration of internal functions */
222 
223 static int print_sdp_cand_attr(char *buffer, int max_len,
224 			       const pj_ice_sess_cand *cand);
225 static void get_ice_attr(const pjmedia_sdp_session *rem_sdp,
226 			 const pjmedia_sdp_media *rem_m,
227 			 const pjmedia_sdp_attr **p_ice_ufrag,
228 			 const pjmedia_sdp_attr **p_ice_pwd);
229 static pj_status_t parse_cand(const char *obj_name,
230 			      pj_pool_t *pool,
231 			      const pj_str_t *orig_input,
232 			      pj_ice_sess_cand *cand);
233 
234 
235 /*
236  * Create ICE media transport.
237  */
pjmedia_ice_create(pjmedia_endpt * endpt,const char * name,unsigned comp_cnt,const pj_ice_strans_cfg * cfg,const pjmedia_ice_cb * cb,pjmedia_transport ** p_tp)238 PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
239 				       const char *name,
240 				       unsigned comp_cnt,
241 				       const pj_ice_strans_cfg *cfg,
242 				       const pjmedia_ice_cb *cb,
243 	    			       pjmedia_transport **p_tp)
244 {
245     return pjmedia_ice_create2(endpt, name, comp_cnt, cfg, cb, 0, p_tp);
246 }
247 
248 /*
249  * Create ICE media transport.
250  */
pjmedia_ice_create2(pjmedia_endpt * endpt,const char * name,unsigned comp_cnt,const pj_ice_strans_cfg * cfg,const pjmedia_ice_cb * cb,unsigned options,pjmedia_transport ** p_tp)251 PJ_DEF(pj_status_t) pjmedia_ice_create2(pjmedia_endpt *endpt,
252 				        const char *name,
253 				        unsigned comp_cnt,
254 				        const pj_ice_strans_cfg *cfg,
255 				        const pjmedia_ice_cb *cb,
256 					unsigned options,
257 	    			        pjmedia_transport **p_tp)
258 {
259     return pjmedia_ice_create3(endpt, name, comp_cnt, cfg, cb,
260                                options, NULL, p_tp);
261 }
262 
263 /*
264  * Create ICE media transport.
265  */
pjmedia_ice_create3(pjmedia_endpt * endpt,const char * name,unsigned comp_cnt,const pj_ice_strans_cfg * cfg,const pjmedia_ice_cb * cb,unsigned options,void * user_data,pjmedia_transport ** p_tp)266 PJ_DEF(pj_status_t) pjmedia_ice_create3(pjmedia_endpt *endpt,
267 				        const char *name,
268 				        unsigned comp_cnt,
269 				        const pj_ice_strans_cfg *cfg,
270 				        const pjmedia_ice_cb *cb,
271 					unsigned options,
272 					void *user_data,
273 	    			        pjmedia_transport **p_tp)
274 {
275     pj_pool_t *pool;
276     pj_ice_strans_cb ice_st_cb;
277     pj_ice_strans_cfg ice_st_cfg;
278     struct transport_ice *tp_ice;
279     pj_status_t status;
280 
281     PJ_ASSERT_RETURN(endpt && comp_cnt && cfg && p_tp, PJ_EINVAL);
282 
283     /* Create transport instance */
284     pool = pjmedia_endpt_create_pool(endpt, name, 512, 512);
285     tp_ice = PJ_POOL_ZALLOC_T(pool, struct transport_ice);
286     tp_ice->pool = pool;
287     tp_ice->options = options;
288     tp_ice->comp_cnt = comp_cnt;
289     pj_ansi_strcpy(tp_ice->base.name, pool->obj_name);
290     tp_ice->base.op = &transport_ice_op;
291     tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE;
292     tp_ice->base.user_data = user_data;
293     tp_ice->initial_sdp = PJ_TRUE;
294     tp_ice->oa_role = ROLE_NONE;
295     tp_ice->use_ice = PJ_FALSE;
296     tp_ice->trickle_ice = cfg->opt.trickle;
297     pj_list_init(&tp_ice->listener);
298     pj_list_init(&tp_ice->listener_empty);
299 
300     pj_memcpy(&ice_st_cfg, cfg, sizeof(pj_ice_strans_cfg));
301     if (cb)
302 	pj_memcpy(&tp_ice->cb, cb, sizeof(pjmedia_ice_cb));
303 
304     /* Assign return value first because ICE might call callback
305      * in create()
306      */
307     *p_tp = &tp_ice->base;
308 
309     /* Configure ICE callbacks */
310     pj_bzero(&ice_st_cb, sizeof(ice_st_cb));
311     ice_st_cb.on_ice_complete = &ice_on_ice_complete;
312     ice_st_cb.on_rx_data = &ice_on_rx_data;
313     ice_st_cb.on_new_candidate = &ice_on_new_candidate;
314 
315     /* Configure RTP socket buffer settings, if not set */
316     if (ice_st_cfg.comp[COMP_RTP-1].so_rcvbuf_size == 0) {
317 	ice_st_cfg.comp[COMP_RTP-1].so_rcvbuf_size =
318 			    PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE;
319     }
320     if (ice_st_cfg.comp[COMP_RTP-1].so_sndbuf_size == 0) {
321 	ice_st_cfg.comp[COMP_RTP-1].so_sndbuf_size =
322 			    PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE;
323     }
324     if (ice_st_cfg.send_buf_size == 0)
325     	ice_st_cfg.send_buf_size = PJMEDIA_MAX_MTU;
326 
327     /* Create ICE */
328     status = pj_ice_strans_create(name, &ice_st_cfg, comp_cnt, tp_ice,
329 				  &ice_st_cb, &tp_ice->ice_st);
330     if (status != PJ_SUCCESS) {
331 	pj_pool_release(pool);
332 	*p_tp = NULL;
333 	return status;
334     }
335 
336     /* Sync to ICE */
337     {
338 	pj_grp_lock_t *grp_lock = pj_ice_strans_get_grp_lock(tp_ice->ice_st);
339 	pj_grp_lock_add_ref(grp_lock);
340 	pj_grp_lock_add_handler(grp_lock, pool, tp_ice, &tp_ice_on_destroy);
341     }
342 
343     /* Done */
344     return PJ_SUCCESS;
345 }
346 
pjmedia_ice_get_grp_lock(pjmedia_transport * tp)347 PJ_DEF(pj_grp_lock_t *) pjmedia_ice_get_grp_lock(pjmedia_transport *tp)
348 {
349     PJ_ASSERT_RETURN(tp, NULL);
350     return pj_ice_strans_get_grp_lock(((struct transport_ice *)tp)->ice_st);
351 }
352 
353 
354 /*
355  * Add application to receive ICE notifications from the specified ICE media
356  * transport.
357  */
pjmedia_ice_add_ice_cb(pjmedia_transport * tp,const pjmedia_ice_cb * cb,void * user_data)358 PJ_DEF(pj_status_t) pjmedia_ice_add_ice_cb( pjmedia_transport *tp,
359 					    const pjmedia_ice_cb *cb,
360 					    void *user_data)
361 {
362     struct transport_ice *tp_ice = (struct transport_ice*)tp;
363     ice_listener *il;
364     pj_grp_lock_t *grp_lock;
365 
366     PJ_ASSERT_RETURN(tp && cb, PJ_EINVAL);
367     grp_lock = pjmedia_ice_get_grp_lock(tp);
368     PJ_ASSERT_RETURN(grp_lock, PJ_EINVAL);
369 
370     pj_grp_lock_acquire(grp_lock);
371 
372     if (!pj_list_empty(&tp_ice->listener_empty)) {
373 	il = tp_ice->listener_empty.next;
374 	pj_list_erase(il);
375 	il->cb = *cb;
376 	il->user_data = user_data;
377 	pj_list_push_back(&tp_ice->listener, il);
378     } else {
379 	il = PJ_POOL_ZALLOC_T(tp_ice->pool, ice_listener);
380 	pj_list_init(il);
381 	il->cb = *cb;
382 	il->user_data = user_data;
383 	pj_list_push_back(&tp_ice->listener, il);
384     }
385 
386     pj_grp_lock_release(grp_lock);
387 
388     return PJ_SUCCESS;
389 }
390 
391 
392 /*
393  * Remove application to stop receiving ICE notifications the specified
394  * ICE media transport.
395  */
pjmedia_ice_remove_ice_cb(pjmedia_transport * tp,const pjmedia_ice_cb * cb,void * user_data)396 PJ_DEF(pj_status_t) pjmedia_ice_remove_ice_cb( pjmedia_transport *tp,
397 					       const pjmedia_ice_cb *cb,
398 					       void *user_data)
399 {
400     struct transport_ice *tp_ice = (struct transport_ice*)tp;
401     ice_listener *il;
402     pj_grp_lock_t *grp_lock;
403 
404     PJ_ASSERT_RETURN(tp && cb, PJ_EINVAL);
405     grp_lock = pjmedia_ice_get_grp_lock(tp);
406     PJ_ASSERT_RETURN(grp_lock, PJ_EINVAL);
407 
408     pj_grp_lock_acquire(grp_lock);
409 
410     for (il=tp_ice->listener.next; il!=&tp_ice->listener; il=il->next) {
411 	if (pj_memcmp(&il->cb, cb, sizeof(cb))==0 && il->user_data==user_data)
412 	    break;
413     }
414     if (il != &tp_ice->listener) {
415 	pj_list_erase(il);
416 	pj_list_push_back(&tp_ice->listener_empty, il);
417     }
418 
419     pj_grp_lock_release(grp_lock);
420 
421     return (il != &tp_ice->listener? PJ_SUCCESS : PJ_ENOTFOUND);
422 }
423 
424 
425 /* Check if trickle support is signalled in the specified SDP. */
pjmedia_ice_sdp_has_trickle(const pjmedia_sdp_session * sdp,unsigned med_idx)426 PJ_DEF(pj_bool_t) pjmedia_ice_sdp_has_trickle( const pjmedia_sdp_session *sdp,
427 					       unsigned med_idx)
428 {
429     const pjmedia_sdp_media *m;
430     const pjmedia_sdp_attr *a;
431 
432     PJ_ASSERT_RETURN(sdp && med_idx < sdp->media_count, PJ_EINVAL);
433 
434     /* Find in media level */
435     m = sdp->media[med_idx];
436     a = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_ICE_OPTIONS, NULL);
437     if (a && pj_strstr(&a->value, &STR_TRICKLE))
438 	return PJ_TRUE;
439 
440     /* Find in session level */
441     a = pjmedia_sdp_attr_find(sdp->attr_count, sdp->attr, &STR_ICE_OPTIONS,
442 			      NULL);
443     if (a && pj_strstr(&a->value, &STR_TRICKLE))
444 	return PJ_TRUE;
445 
446     return PJ_FALSE;
447 }
448 
449 
450 /* Update check list after discovering and conveying new local ICE candidate,
451  * or receiving update of remote ICE candidates in trickle ICE.
452  */
pjmedia_ice_trickle_update(pjmedia_transport * tp,const pj_str_t * rem_ufrag,const pj_str_t * rem_passwd,unsigned rcand_cnt,const pj_ice_sess_cand rcand[],pj_bool_t rcand_end)453 PJ_DEF(pj_status_t) pjmedia_ice_trickle_update(
454 					     pjmedia_transport *tp,
455 					     const pj_str_t *rem_ufrag,
456 					     const pj_str_t *rem_passwd,
457 					     unsigned rcand_cnt,
458 					     const pj_ice_sess_cand rcand[],
459 					     pj_bool_t rcand_end)
460 {
461     struct transport_ice *tp_ice = (struct transport_ice*)tp;
462     pj_status_t status;
463 
464     PJ_ASSERT_RETURN(tp_ice && tp_ice->ice_st, PJ_EINVAL);
465     PJ_ASSERT_RETURN(tp_ice->trickle_ice != PJ_ICE_SESS_TRICKLE_DISABLED,
466 		     PJ_EINVALIDOP);
467 
468 
469     /* Update the checklist */
470     status = pj_ice_strans_update_check_list(tp_ice->ice_st,
471 					     rem_ufrag, rem_passwd,
472 					     rcand_cnt, rcand, rcand_end);
473     if (status != PJ_SUCCESS)
474 	return status;
475 
476     /* Start ICE if both sides have sent their (initial) SDPs */
477     if (!pj_ice_strans_sess_is_running(tp_ice->ice_st)) {
478 	unsigned i, comp_cnt;
479 
480 	comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st);
481 	for (i = 0; i < comp_cnt; ++i) {
482 	    if (tp_ice->last_send_cand_cnt[i] > 0)
483 		break;
484 	}
485 	if (i != comp_cnt) {
486 	    pj_str_t rufrag;
487 	    pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, NULL, NULL,
488 					&rufrag, NULL);
489 	    if (rufrag.slen > 0) {
490 		PJ_LOG(3,(THIS_FILE,"Trickle ICE starts connectivity check"));
491 		status = pj_ice_strans_start_ice(tp_ice->ice_st, NULL, NULL,
492 						 0, NULL);
493 	    }
494 	}
495     }
496 
497     return status;
498 }
499 
500 
501 /* Fetch trickle ICE info from the specified SDP. */
pjmedia_ice_trickle_decode_sdp(const pjmedia_sdp_session * sdp,unsigned media_index,pj_str_t * mid,pj_str_t * ufrag,pj_str_t * passwd,unsigned * cand_cnt,pj_ice_sess_cand cand[],pj_bool_t * end_of_cand)502 PJ_DEF(pj_status_t) pjmedia_ice_trickle_decode_sdp(
503 					    const pjmedia_sdp_session *sdp,
504 					    unsigned media_index,
505 					    pj_str_t *mid,
506 					    pj_str_t *ufrag,
507 					    pj_str_t *passwd,
508 					    unsigned *cand_cnt,
509 					    pj_ice_sess_cand cand[],
510 					    pj_bool_t *end_of_cand)
511 {
512     const pjmedia_sdp_media *m;
513     const pjmedia_sdp_attr *a;
514 
515     PJ_ASSERT_RETURN(sdp && media_index < sdp->media_count, PJ_EINVAL);
516 
517     m = sdp->media[media_index];
518 
519     if (mid) {
520 	a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "mid", NULL);
521 	if (a) {
522 	    *mid = a->value;
523 	} else {
524 	    pj_bzero(mid, sizeof(*mid));
525 	}
526     }
527 
528     if (ufrag && passwd) {
529 	const pjmedia_sdp_attr *a_ufrag, *a_pwd;
530 	get_ice_attr(sdp, m, &a_ufrag, &a_pwd);
531 	if (a_ufrag && a_pwd) {
532 	    *ufrag = a_ufrag->value;
533 	    *passwd = a_pwd->value;
534 	} else {
535 	    pj_bzero(ufrag, sizeof(*ufrag));
536 	    pj_bzero(passwd, sizeof(*passwd));
537 	}
538     }
539 
540     if (cand_cnt && cand && *cand_cnt > 0) {
541 	pj_status_t status;
542 	unsigned i, cnt = 0;
543 
544 	for (i=0; i<m->attr_count && cnt<*cand_cnt; ++i) {
545 	    a = m->attr[i];
546 	    if (pj_strcmp(&a->name, &STR_CANDIDATE)!=0)
547 		continue;
548 
549 	    /* Parse candidate */
550 	    status = parse_cand("trickle-ice", NULL, &a->value, &cand[cnt]);
551 	    if (status != PJ_SUCCESS) {
552 		PJ_PERROR(4,("trickle-ice", status,
553 			     "Error in parsing SDP candidate attribute '%.*s', "
554 			     "candidate is ignored",
555 			     (int)a->value.slen, a->value.ptr));
556 		continue;
557 	    }
558 	    ++cnt;
559 	}
560 	*cand_cnt = cnt;
561     }
562 
563     if (end_of_cand) {
564 	a = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_END_OF_CAND,
565 				  NULL);
566 	if (!a) {
567 	    a = pjmedia_sdp_attr_find(sdp->attr_count, sdp->attr,
568 				      &STR_END_OF_CAND, NULL);
569 	}
570 	*end_of_cand = (a != NULL);
571     }
572     return PJ_SUCCESS;
573 }
574 
575 
576 /* Generate SDP attributes for trickle ICE in the specified SDP. */
pjmedia_ice_trickle_encode_sdp(pj_pool_t * sdp_pool,pjmedia_sdp_session * sdp,const pj_str_t * mid,const pj_str_t * ufrag,const pj_str_t * passwd,unsigned cand_cnt,const pj_ice_sess_cand cand[],pj_bool_t end_of_cand)577 PJ_DEF(pj_status_t) pjmedia_ice_trickle_encode_sdp(
578 					    pj_pool_t *sdp_pool,
579 					    pjmedia_sdp_session *sdp,
580 					    const pj_str_t *mid,
581 					    const pj_str_t *ufrag,
582 					    const pj_str_t *passwd,
583 					    unsigned cand_cnt,
584 					    const pj_ice_sess_cand cand[],
585 					    pj_bool_t end_of_cand)
586 {
587     pjmedia_sdp_media *m = NULL;
588     pjmedia_sdp_attr *a;
589     unsigned i;
590 
591     PJ_ASSERT_RETURN(sdp_pool && sdp, PJ_EINVAL);
592 
593     /* Find media by checking "a=mid"*/
594     for (i = 0; i < sdp->media_count; ++i) {
595 	m = sdp->media[i];
596 	a = pjmedia_sdp_media_find_attr2(m, "mid", NULL);
597 	if (a && pj_strcmp(&a->value, mid)==0)
598 	    break;
599     }
600 
601     /* Media not exist, try to add it */
602     if (i == sdp->media_count) {
603 	if (sdp->media_count >= PJMEDIA_MAX_SDP_MEDIA) {
604 	    PJ_LOG(3,(THIS_FILE,"Trickle ICE failed to encode candidates, "
605 				"the specified SDP has too many media"));
606 	    return PJ_ETOOMANY;
607 	}
608 
609 	/* Add a new media to the SDP */
610 	m = PJ_POOL_ZALLOC_T(sdp_pool, pjmedia_sdp_media);
611 	m->desc.media = pj_str("audio");
612 	m->desc.fmt_count = 1;
613 	m->desc.fmt[0] = pj_str("0");
614 	m->desc.transport = pj_str("RTP/AVP");
615 	sdp->media[sdp->media_count++] = m;
616 
617 	/* Add media ID attribute "a=mid" */
618 	a = pjmedia_sdp_attr_create(sdp_pool, "mid", mid);
619 	pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
620     }
621 
622     /* Add "a=ice-options:trickle" in session level */
623     a = pjmedia_sdp_attr_find(sdp->attr_count, sdp->attr, &STR_ICE_OPTIONS,
624 			      NULL);
625     if (!a || !pj_strstr(&a->value, &STR_TRICKLE)) {
626 	a = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_OPTIONS.ptr,
627 				    &STR_TRICKLE);
628 	pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
629     }
630 
631     /* Add "a=ice-options:trickle" in media level */
632     /*
633     a = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_ICE_OPTIONS,
634 			      NULL);
635     if (!a || !pj_strstr(&a->value, &STR_TRICKLE)) {
636 	a = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_OPTIONS.ptr,
637 				    &STR_TRICKLE);
638 	pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
639     }
640     */
641 
642     /* Add ice-ufrag & ice-pwd attributes */
643     if (ufrag && passwd &&
644 	!pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_ICE_UFRAG, NULL))
645     {
646 	a = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, ufrag);
647 	pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
648 
649 	a = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, passwd);
650 	pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
651     }
652 
653     /* Add candidates */
654     for (i=0; i<cand_cnt; ++i) {
655 	enum {
656 	    ATTR_BUF_LEN = 160,	/* Max len of a=candidate attr */
657 	    RATTR_BUF_LEN= 160	/* Max len of a=remote-candidates attr */
658 	};
659 	char attr_buf[ATTR_BUF_LEN];
660 	pj_str_t value;
661 
662 	value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN, &cand[i]);
663 	if (value.slen < 0) {
664 	    pj_assert(!"Not enough attr_buf to print candidate");
665 	    return PJ_EBUG;
666 	}
667 
668 	value.ptr = attr_buf;
669 	a = pjmedia_sdp_attr_create(sdp_pool, STR_CANDIDATE.ptr, &value);
670 	pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
671     }
672 
673     /* Add "a=end-of-candidates" */
674     if (end_of_cand) {
675 	a = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_END_OF_CAND,
676 				  NULL);
677 	if (!a) {
678 	    a = pjmedia_sdp_attr_create(sdp_pool, STR_END_OF_CAND.ptr, NULL);
679 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
680 	}
681     }
682 
683     return PJ_SUCCESS;
684 }
685 
686 
pjmedia_ice_trickle_has_new_cand(pjmedia_transport * tp)687 PJ_DEF(pj_bool_t) pjmedia_ice_trickle_has_new_cand(pjmedia_transport *tp)
688 {
689     struct transport_ice *tp_ice = (struct transport_ice*)tp;
690     unsigned i, comp_cnt;
691 
692     /* Make sure ICE transport has session already */
693     if (!tp_ice->ice_st || !pj_ice_strans_has_sess(tp_ice->ice_st))
694 	return PJ_FALSE;
695 
696     /* Count all local candidates */
697     comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st);
698     for (i = 0; i < comp_cnt; ++i) {
699 	if (tp_ice->last_send_cand_cnt[i] <
700 	    pj_ice_strans_get_cands_count(tp_ice->ice_st, i+1))
701 	{
702 	    return PJ_TRUE;
703 	}
704     }
705     return PJ_FALSE;
706 }
707 
708 
709 /* Add any new local candidates to the specified SDP to be conveyed to
710  * remote (e.g: via SIP INFO).
711  */
pjmedia_ice_trickle_send_local_cand(pjmedia_transport * tp,pj_pool_t * sdp_pool,pjmedia_sdp_session * sdp,pj_bool_t * p_end_of_cand)712 PJ_DEF(pj_status_t) pjmedia_ice_trickle_send_local_cand(
713 					    pjmedia_transport *tp,
714 					    pj_pool_t *sdp_pool,
715 					    pjmedia_sdp_session *sdp,
716 					    pj_bool_t *p_end_of_cand)
717 {
718     struct transport_ice *tp_ice = (struct transport_ice*)tp;
719     pj_str_t ufrag, pwd;
720     pj_ice_sess_cand cand[PJ_ICE_MAX_CAND];
721     unsigned cand_cnt, i, comp_cnt;
722     pj_bool_t end_of_cand;
723     pj_status_t status;
724 
725     PJ_ASSERT_RETURN(tp && sdp_pool && sdp, PJ_EINVAL);
726 
727     /* Make sure ICE transport has session already */
728     if (!tp_ice->ice_st || !pj_ice_strans_has_sess(tp_ice->ice_st))
729 	return PJ_EINVALIDOP;
730 
731     end_of_cand = tp_ice->end_of_cand;
732 
733     /* Get ufrag and pwd from current session */
734     pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, &ufrag, &pwd, NULL, NULL);
735 
736     cand_cnt = 0;
737     comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st);
738     for (i = 0; i < comp_cnt; ++i) {
739 	unsigned cnt = PJ_ICE_MAX_CAND - cand_cnt;
740 
741 	/* Get all local candidates for this comp */
742 	status = pj_ice_strans_enum_cands(tp_ice->ice_st, i+1,
743 					  &cnt, &cand[cand_cnt]);
744 	if (status != PJ_SUCCESS) {
745 	    PJ_PERROR(3,(tp_ice->base.name, status,
746 			 "Failed enumerating local candidates for comp-id=%d",
747 			 i+1));
748 	    continue;
749 	}
750 	cand_cnt += cnt;
751 
752 	tp_ice->last_send_cand_cnt[i] = cnt;
753     }
754 
755     /* Update the SDP with all local candidates (not just the new ones).
756      * https://tools.ietf.org/html/draft-ietf-mmusic-trickle-ice-sip-18:
757      * 4.4. Delivering Candidates in INFO Requests: the agent MUST
758      * repeat in the INFO request body all candidates that were previously
759      * sent under the same combination of "a=ice-pwd:" and "a=ice-ufrag:"
760      * in the same order as they were sent before.
761      */
762     status = pjmedia_ice_trickle_encode_sdp(sdp_pool, sdp, &tp_ice->sdp_mid,
763 					    &ufrag, &pwd, cand_cnt, cand,
764 					    end_of_cand);
765     if (status != PJ_SUCCESS) {
766 	PJ_PERROR(3,(tp_ice->base.name, status,
767 		     "Failed encoding local candidates to SDP"));
768     }
769 
770     if (p_end_of_cand)
771 	*p_end_of_cand = end_of_cand;
772 
773     return PJ_SUCCESS;
774 }
775 
776 
777 /* Disable ICE when SDP from remote doesn't contain a=candidate line */
set_no_ice(struct transport_ice * tp_ice,const char * reason,pj_status_t err)778 static void set_no_ice(struct transport_ice *tp_ice, const char *reason,
779 		       pj_status_t err)
780 {
781     if (err != PJ_SUCCESS) {
782 	PJ_PERROR(4,(tp_ice->base.name, err,
783 		     "Stopping ICE, reason=%s", reason));
784     } else {
785 	PJ_LOG(4,(tp_ice->base.name,
786 		  "Stopping ICE, reason=%s", reason));
787     }
788 
789     if (tp_ice->ice_st) {
790 	pj_ice_strans_stop_ice(tp_ice->ice_st);
791     }
792 
793     tp_ice->use_ice = PJ_FALSE;
794 }
795 
796 
797 /* Create SDP candidate attribute */
print_sdp_cand_attr(char * buffer,int max_len,const pj_ice_sess_cand * cand)798 static int print_sdp_cand_attr(char *buffer, int max_len,
799 			       const pj_ice_sess_cand *cand)
800 {
801     char ipaddr[PJ_INET6_ADDRSTRLEN+2];
802     int len, len2;
803 
804     len = pj_ansi_snprintf( buffer, max_len,
805 			    "%.*s %u UDP %u %s %u typ ",
806 			    (int)cand->foundation.slen,
807 			    cand->foundation.ptr,
808 			    (unsigned)cand->comp_id,
809 			    cand->prio,
810 			    pj_sockaddr_print(&cand->addr, ipaddr,
811 					      sizeof(ipaddr), 0),
812 			    (unsigned)pj_sockaddr_get_port(&cand->addr));
813     if (len < 1 || len >= max_len)
814 	return -1;
815 
816     switch (cand->type) {
817     case PJ_ICE_CAND_TYPE_HOST:
818 	len2 = pj_ansi_snprintf(buffer+len, max_len-len, "host");
819 	break;
820     case PJ_ICE_CAND_TYPE_SRFLX:
821     case PJ_ICE_CAND_TYPE_RELAYED:
822     case PJ_ICE_CAND_TYPE_PRFLX:
823 	len2 = pj_ansi_snprintf(buffer+len, max_len-len,
824 			        "%s raddr %s rport %d",
825 				pj_ice_get_cand_type_name(cand->type),
826 				pj_sockaddr_print(&cand->rel_addr, ipaddr,
827 						  sizeof(ipaddr), 0),
828 				(int)pj_sockaddr_get_port(&cand->rel_addr));
829 	break;
830     default:
831 	pj_assert(!"Invalid candidate type");
832 	len2 = -1;
833 	break;
834     }
835     if (len2 < 1 || len2 >= max_len-len)
836 	return -1;
837 
838     return len+len2;
839 }
840 
841 
842 /* Get ice-ufrag and ice-pwd attribute */
get_ice_attr(const pjmedia_sdp_session * rem_sdp,const pjmedia_sdp_media * rem_m,const pjmedia_sdp_attr ** p_ice_ufrag,const pjmedia_sdp_attr ** p_ice_pwd)843 static void get_ice_attr(const pjmedia_sdp_session *rem_sdp,
844 			 const pjmedia_sdp_media *rem_m,
845 			 const pjmedia_sdp_attr **p_ice_ufrag,
846 			 const pjmedia_sdp_attr **p_ice_pwd)
847 {
848     pjmedia_sdp_attr *attr;
849 
850     /* Find ice-ufrag attribute in media descriptor */
851     attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,
852 				 &STR_ICE_UFRAG, NULL);
853     if (attr == NULL) {
854 	/* Find ice-ufrag attribute in session descriptor */
855 	attr = pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
856 				     &STR_ICE_UFRAG, NULL);
857     }
858     *p_ice_ufrag = attr;
859 
860     /* Find ice-pwd attribute in media descriptor */
861     attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,
862 				 &STR_ICE_PWD, NULL);
863     if (attr == NULL) {
864 	/* Find ice-pwd attribute in session descriptor */
865 	attr = pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
866 				     &STR_ICE_PWD, NULL);
867     }
868     *p_ice_pwd = attr;
869 }
870 
871 
872 /* Encode and add "a=ice-mismatch" attribute in the SDP */
encode_ice_mismatch(pj_pool_t * sdp_pool,pjmedia_sdp_session * sdp_local,unsigned media_index)873 static void encode_ice_mismatch(pj_pool_t *sdp_pool,
874 				pjmedia_sdp_session *sdp_local,
875 				unsigned media_index)
876 {
877     pjmedia_sdp_attr *attr;
878     pjmedia_sdp_media *m = sdp_local->media[media_index];
879 
880     attr = PJ_POOL_ALLOC_T(sdp_pool, pjmedia_sdp_attr);
881     attr->name = STR_ICE_MISMATCH;
882     attr->value.slen = 0;
883     pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
884 }
885 
886 
887 /* Encode ICE information in SDP */
encode_session_in_sdp(struct transport_ice * tp_ice,pj_pool_t * sdp_pool,pjmedia_sdp_session * sdp_local,unsigned media_index,unsigned comp_cnt,pj_bool_t restart_session,pj_bool_t rtcp_mux,pj_bool_t trickle)888 static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice,
889 					 pj_pool_t *sdp_pool,
890 					 pjmedia_sdp_session *sdp_local,
891 					 unsigned media_index,
892 					 unsigned comp_cnt,
893 					 pj_bool_t restart_session,
894 					 pj_bool_t rtcp_mux,
895 					 pj_bool_t trickle)
896 {
897     enum {
898 	ATTR_BUF_LEN = 160,	/* Max len of a=candidate attr */
899 	RATTR_BUF_LEN= 160	/* Max len of a=remote-candidates attr */
900     };
901     pjmedia_sdp_media *m = sdp_local->media[media_index];
902     pj_str_t local_ufrag, local_pwd;
903     pjmedia_sdp_attr *attr;
904     pj_status_t status;
905 
906     /* Must have a session */
907     PJ_ASSERT_RETURN(pj_ice_strans_has_sess(tp_ice->ice_st), PJ_EBUG);
908 
909     /* Get ufrag and pwd from current session */
910     pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, &local_ufrag, &local_pwd,
911 				NULL, NULL);
912 
913     /* The listing of candidates depends on whether ICE has completed
914      * or not. When ICE has completed:
915      *
916      * 9.1.2.2: Existing Media Streams with ICE Completed
917      *   The agent MUST include a candidate attributes for candidates
918      *   matching the default destination for each component of the
919      *   media stream, and MUST NOT include any other candidates.
920      *
921      * When ICE has not completed, we shall include all candidates.
922      *
923      * Except when we have detected that remote is offering to restart
924      * the session, in this case we will answer with full ICE SDP and
925      * new ufrag/pwd pair.
926      */
927     if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st) &&
928 	pj_ice_strans_get_state(tp_ice->ice_st) != PJ_ICE_STRANS_STATE_FAILED)
929     {
930 	const pj_ice_sess_check *check;
931 	char *attr_buf;
932 	pjmedia_sdp_conn *conn;
933 	pjmedia_sdp_attr *a_rtcp;
934 	pj_str_t rem_cand;
935 	unsigned comp;
936 
937 	/* Encode ice-ufrag attribute */
938 	attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr,
939 				       &local_ufrag);
940 	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
941 
942 	/* Encode ice-pwd attribute */
943 	attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr,
944 				       &local_pwd);
945 	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
946 
947 	/* Prepare buffer */
948 	attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN);
949 	rem_cand.ptr = (char*) pj_pool_alloc(sdp_pool, RATTR_BUF_LEN);
950 	rem_cand.slen = 0;
951 
952 	/* 9.1.2.2: Existing Media Streams with ICE Completed
953 	 *   The default destination for media (i.e., the values of
954 	 *   the IP addresses and ports in the m and c line used for
955 	 *   that media stream) MUST be the local candidate from the
956 	 *   highest priority nominated pair in the valid list for each
957 	 *   component.
958 	 */
959 	check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 1);
960 	if (check == NULL) {
961 	    pj_assert(!"Shouldn't happen");
962 	    return PJ_EBUG;
963 	}
964 
965 	/* Override connection line address and media port number */
966 	conn = m->conn;
967 	if (conn == NULL)
968 	    conn = sdp_local->conn;
969 
970 	conn->addr.ptr = (char*) pj_pool_alloc(sdp_pool,
971 					       PJ_INET6_ADDRSTRLEN);
972 	pj_sockaddr_print(&check->lcand->addr, conn->addr.ptr,
973 			  PJ_INET6_ADDRSTRLEN, 0);
974 	conn->addr.slen = pj_ansi_strlen(conn->addr.ptr);
975 	m->desc.port = pj_sockaddr_get_port(&check->lcand->addr);
976 
977 	/* Override address RTCP attribute if it's present */
978 	if (comp_cnt == 2 &&
979 	    (check = pj_ice_strans_get_valid_pair(tp_ice->ice_st,
980 						  COMP_RTCP)) != NULL &&
981 	    (a_rtcp = pjmedia_sdp_attr_find(m->attr_count, m->attr,
982 					    &STR_RTCP, 0)) != NULL)
983 	{
984 	    pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a_rtcp);
985 
986 	    a_rtcp = pjmedia_sdp_attr_create_rtcp(sdp_pool,
987 						  &check->lcand->addr);
988 	    if (a_rtcp)
989 		pjmedia_sdp_attr_add(&m->attr_count, m->attr, a_rtcp);
990 	}
991 
992 	/* Encode only candidates matching the default destination
993 	 * for each component
994 	 */
995 	for (comp=0; comp < comp_cnt; ++comp) {
996 	    int len;
997 	    pj_str_t value;
998 
999 	    /* Get valid pair for this component */
1000 	    check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, comp+1);
1001 	    if (check == NULL)
1002 		continue;
1003 
1004 	    /* Print and add local candidate in the pair */
1005 	    value.ptr = attr_buf;
1006 	    value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN,
1007 					     check->lcand);
1008 	    if (value.slen < 0) {
1009 		pj_assert(!"Not enough attr_buf to print candidate");
1010 		return PJ_EBUG;
1011 	    }
1012 
1013 	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_CANDIDATE.ptr,
1014 					   &value);
1015 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1016 
1017 	    /* Append to a=remote-candidates attribute */
1018 	    if (pj_ice_strans_get_role(tp_ice->ice_st) ==
1019 				    PJ_ICE_SESS_ROLE_CONTROLLING)
1020 	    {
1021 		char rem_addr[PJ_INET6_ADDRSTRLEN];
1022 
1023 		pj_sockaddr_print(&check->rcand->addr, rem_addr,
1024 				  sizeof(rem_addr), 0);
1025 		len = pj_ansi_snprintf(
1026 			   rem_cand.ptr + rem_cand.slen,
1027 			   RATTR_BUF_LEN - rem_cand.slen,
1028 			   "%s%u %s %u",
1029 			   (rem_cand.slen==0? "" : " "),
1030 			   comp+1, rem_addr,
1031 			   pj_sockaddr_get_port(&check->rcand->addr)
1032 			   );
1033 		if (len < 1 || len >= RATTR_BUF_LEN - rem_cand.slen) {
1034 		    pj_assert(!"Not enough buffer to print "
1035 			       "remote-candidates");
1036 		    return PJ_EBUG;
1037 		}
1038 
1039 		rem_cand.slen += len;
1040 	    }
1041 	}
1042 
1043 	/* 9.1.2.2: Existing Media Streams with ICE Completed
1044 	 *   In addition, if the agent is controlling, it MUST include
1045 	 *   the a=remote-candidates attribute for each media stream
1046 	 *   whose check list is in the Completed state.  The attribute
1047 	 *   contains the remote candidates from the highest priority
1048 	 *   nominated pair in the valid list for each component of that
1049 	 *   media stream.
1050 	 */
1051 	if (pj_ice_strans_get_role(tp_ice->ice_st) ==
1052 				    PJ_ICE_SESS_ROLE_CONTROLLING)
1053 	{
1054 	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_REM_CAND.ptr,
1055 					   &rem_cand);
1056 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1057 	}
1058 
1059     } else if (pj_ice_strans_has_sess(tp_ice->ice_st) &&
1060 	       (restart_session || pj_ice_strans_get_state(tp_ice->ice_st) !=
1061 		PJ_ICE_STRANS_STATE_FAILED))
1062     {
1063 	/* Encode all candidates to SDP media */
1064 	char *attr_buf;
1065 	unsigned comp;
1066 
1067 	/* If ICE is not restarted, encode current ICE ufrag/pwd.
1068 	 * Otherwise generate new one.
1069 	 */
1070 	if (!restart_session) {
1071 	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr,
1072 					   &local_ufrag);
1073 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1074 
1075 	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr,
1076 					   &local_pwd);
1077 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1078 
1079 	} else {
1080 	    pj_str_t str;
1081 
1082 	    str.slen = PJ_ICE_UFRAG_LEN;
1083 	    str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen);
1084 	    pj_create_random_string(str.ptr, str.slen);
1085 	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, &str);
1086 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1087 
1088 	    str.slen = PJ_ICE_PWD_LEN;
1089 	    str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen);
1090 	    pj_create_random_string(str.ptr, str.slen);
1091 	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, &str);
1092 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1093 	}
1094 
1095 	/* Create buffer to encode candidates as SDP attribute */
1096 	attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN);
1097 
1098 	for (comp=0; comp < comp_cnt; ++comp) {
1099 	    unsigned cand_cnt;
1100 	    pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND];
1101 	    unsigned i;
1102 
1103 	    cand_cnt = PJ_ARRAY_SIZE(cand);
1104 	    status = pj_ice_strans_enum_cands(tp_ice->ice_st, comp+1,
1105 					      &cand_cnt, cand);
1106 	    if (status != PJ_SUCCESS)
1107 		return status;
1108 
1109 	    for (i=0; i<cand_cnt; ++i) {
1110 		pj_str_t value;
1111 
1112 		value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN,
1113 						 &cand[i]);
1114 		if (value.slen < 0) {
1115 		    pj_assert(!"Not enough attr_buf to print candidate");
1116 		    return PJ_EBUG;
1117 		}
1118 
1119 		value.ptr = attr_buf;
1120 		attr = pjmedia_sdp_attr_create(sdp_pool,
1121 					       STR_CANDIDATE.ptr,
1122 					       &value);
1123 		pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1124 	    }
1125 	}
1126     } else {
1127 	/* ICE has failed, application should have terminated this call */
1128     }
1129 
1130     /* Removing a=rtcp line when there is only one component. */
1131     if (comp_cnt == 1) {
1132 	attr = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_RTCP, NULL);
1133 	if (attr)
1134 	    pjmedia_sdp_attr_remove(&m->attr_count, m->attr, attr);
1135         /* If RTCP is not in use, we MUST send b=RS:0 and b=RR:0. */
1136         pj_assert(m->bandw_count + 2 <= PJ_ARRAY_SIZE(m->bandw));
1137         if (m->bandw_count + 2 <= PJ_ARRAY_SIZE(m->bandw)) {
1138             m->bandw[m->bandw_count] = PJ_POOL_ZALLOC_T(sdp_pool,
1139                                                         pjmedia_sdp_bandw);
1140             pj_memcpy(&m->bandw[m->bandw_count]->modifier, &STR_BANDW_RS,
1141                       sizeof(pj_str_t));
1142             m->bandw_count++;
1143             m->bandw[m->bandw_count] = PJ_POOL_ZALLOC_T(sdp_pool,
1144                                                         pjmedia_sdp_bandw);
1145             pj_memcpy(&m->bandw[m->bandw_count]->modifier, &STR_BANDW_RR,
1146                       sizeof(pj_str_t));
1147             m->bandw_count++;
1148         }
1149     }
1150 
1151     /* Add a=rtcp-mux attribute */
1152     if (rtcp_mux) {
1153 	pjmedia_sdp_attr *add_attr;
1154 
1155 	add_attr = PJ_POOL_ZALLOC_T(sdp_pool, pjmedia_sdp_attr);
1156     	add_attr->name = STR_RTCP_MUX;
1157     	m->attr[m->attr_count++] = add_attr;
1158     }
1159 
1160     /* Add trickle ICE attributes */
1161     if (trickle) {
1162 	pj_bool_t end_of_cand;
1163 
1164 	/* Add media ID attribute "a=mid" */
1165 	attr = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "mid", NULL);
1166 	if (!attr) {
1167 	    attr = pjmedia_sdp_attr_create(sdp_pool, "mid", &tp_ice->sdp_mid);
1168 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1169 	}
1170 
1171 	end_of_cand = tp_ice->end_of_cand;
1172 	status = pjmedia_ice_trickle_encode_sdp(sdp_pool, sdp_local,
1173 						&tp_ice->sdp_mid, NULL, NULL,
1174 						0, NULL, end_of_cand);
1175 	if (status != PJ_SUCCESS) {
1176 	    PJ_PERROR(3,(tp_ice->base.name, status,
1177 			 "Failed in adding trickle ICE attributes"));
1178 	    return status;
1179 	}
1180     }
1181 
1182     return PJ_SUCCESS;
1183 }
1184 
1185 
1186 /* Parse a=candidate line */
parse_cand(const char * obj_name,pj_pool_t * pool,const pj_str_t * orig_input,pj_ice_sess_cand * cand)1187 static pj_status_t parse_cand(const char *obj_name,
1188 			      pj_pool_t *pool,
1189 			      const pj_str_t *orig_input,
1190 			      pj_ice_sess_cand *cand)
1191 {
1192     pj_str_t token, delim, host;
1193     int af;
1194     pj_ssize_t found_idx;
1195     pj_status_t status = PJNATH_EICEINCANDSDP;
1196 
1197     pj_bzero(cand, sizeof(*cand));
1198 
1199     PJ_UNUSED_ARG(obj_name);
1200 
1201     /* Foundation */
1202     delim = pj_str(" ");
1203     found_idx = pj_strtok(orig_input, &delim, &token, 0);
1204     if (found_idx == orig_input->slen) {
1205 	TRACE__((obj_name, "Expecting ICE foundation in candidate"));
1206 	goto on_return;
1207     }
1208     if (pool) {
1209 	pj_strdup(pool, &cand->foundation, &token);
1210     } else {
1211 	cand->foundation = token;
1212     }
1213 
1214     /* Component ID */
1215     found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
1216     if (found_idx == orig_input->slen) {
1217 	TRACE__((obj_name, "Expecting ICE component ID in candidate"));
1218 	goto on_return;
1219     }
1220     cand->comp_id = (pj_uint8_t)pj_strtoul(&token);
1221 
1222     /* Transport */
1223     found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
1224     if (found_idx == orig_input->slen) {
1225 	TRACE__((obj_name, "Expecting ICE transport in candidate"));
1226 	goto on_return;
1227     }
1228     if (pj_stricmp2(&token, "UDP") != 0) {
1229 	TRACE__((obj_name,
1230 		 "Expecting ICE UDP transport only in candidate"));
1231 	goto on_return;
1232     }
1233 
1234     /* Priority */
1235     found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
1236     if (found_idx == orig_input->slen) {
1237 	TRACE__((obj_name, "Expecting ICE priority in candidate"));
1238 	goto on_return;
1239     }
1240     cand->prio = pj_strtoul(&token);
1241 
1242     /* Host */
1243     found_idx = pj_strtok(orig_input, &delim, &host, found_idx + token.slen);
1244     if (found_idx == orig_input->slen) {
1245 	TRACE__((obj_name, "Expecting ICE host in candidate"));
1246 	goto on_return;
1247     }
1248     /* Detect address family */
1249     if (pj_strchr(&host, ':'))
1250 	af = pj_AF_INET6();
1251     else
1252 	af = pj_AF_INET();
1253     /* Assign address */
1254     if (pj_sockaddr_init(af, &cand->addr, &host, 0)) {
1255 	TRACE__((obj_name, "Invalid ICE candidate address"));
1256 	goto on_return;
1257     }
1258 
1259     /* Port */
1260     found_idx = pj_strtok(orig_input, &delim, &token, found_idx + host.slen);
1261     if (found_idx == orig_input->slen) {
1262 	TRACE__((obj_name, "Expecting ICE port number in candidate"));
1263 	goto on_return;
1264     }
1265     pj_sockaddr_set_port(&cand->addr, (pj_uint16_t)pj_strtoul(&token));
1266 
1267     /* typ */
1268     found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
1269     if (found_idx == orig_input->slen) {
1270 	TRACE__((obj_name, "Expecting ICE \"typ\" in candidate"));
1271 	goto on_return;
1272     }
1273     if (pj_stricmp2(&token, "typ") != 0) {
1274 	TRACE__((obj_name, "Expecting ICE \"typ\" in candidate"));
1275 	goto on_return;
1276     }
1277 
1278     /* candidate type */
1279     found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
1280     if (found_idx == orig_input->slen) {
1281 	TRACE__((obj_name, "Expecting ICE candidate type in candidate"));
1282 	goto on_return;
1283     }
1284 
1285     if (pj_stricmp2(&token, "host") == 0) {
1286 	cand->type = PJ_ICE_CAND_TYPE_HOST;
1287 
1288     } else if (pj_stricmp2(&token, "srflx") == 0) {
1289 	cand->type = PJ_ICE_CAND_TYPE_SRFLX;
1290 
1291     } else if (pj_stricmp2(&token, "relay") == 0) {
1292 	cand->type = PJ_ICE_CAND_TYPE_RELAYED;
1293 
1294     } else if (pj_stricmp2(&token, "prflx") == 0) {
1295 	cand->type = PJ_ICE_CAND_TYPE_PRFLX;
1296 
1297     } else {
1298 	PJ_LOG(5,(obj_name, "Invalid ICE candidate type %.*s in candidate",
1299 		  token.slen, token.ptr));
1300 	goto on_return;
1301     }
1302 
1303     status = PJ_SUCCESS;
1304 
1305 on_return:
1306     return status;
1307 }
1308 
1309 
1310 /* Create initial SDP offer */
create_initial_offer(struct transport_ice * tp_ice,pj_pool_t * sdp_pool,pjmedia_sdp_session * loc_sdp,unsigned media_index)1311 static pj_status_t create_initial_offer(struct transport_ice *tp_ice,
1312 					pj_pool_t *sdp_pool,
1313 					pjmedia_sdp_session *loc_sdp,
1314 					unsigned media_index)
1315 {
1316     pj_status_t status;
1317 
1318     /* Encode ICE in SDP */
1319     status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
1320 				   tp_ice->comp_cnt, PJ_FALSE,
1321 				   tp_ice->enable_rtcp_mux,
1322 				   tp_ice->trickle_ice !=
1323 					PJ_ICE_SESS_TRICKLE_DISABLED);
1324     if (status != PJ_SUCCESS) {
1325 	set_no_ice(tp_ice, "Error encoding SDP answer", status);
1326 	return status;
1327     }
1328 
1329     return PJ_SUCCESS;
1330 }
1331 
1332 
1333 /* Verify incoming offer */
verify_ice_sdp(struct transport_ice * tp_ice,pj_pool_t * tmp_pool,const pjmedia_sdp_session * rem_sdp,unsigned media_index,pj_ice_sess_role current_ice_role,struct sdp_state * sdp_state)1334 static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice,
1335 				  pj_pool_t *tmp_pool,
1336 				  const pjmedia_sdp_session *rem_sdp,
1337 				  unsigned media_index,
1338 				  pj_ice_sess_role current_ice_role,
1339 				  struct sdp_state *sdp_state)
1340 {
1341     const pjmedia_sdp_media *rem_m;
1342     const pjmedia_sdp_attr *ufrag_attr, *pwd_attr;
1343     const pjmedia_sdp_conn *rem_conn;
1344     pj_bool_t comp1_found=PJ_FALSE, comp2_found=PJ_FALSE, has_rtcp=PJ_FALSE;
1345     pj_sockaddr rem_conn_addr, rtcp_addr;
1346     unsigned i;
1347     int rem_af = 0;
1348     pj_status_t status;
1349 
1350     rem_m = rem_sdp->media[media_index];
1351 
1352     /* Check if remote wants RTCP mux */
1353     if (tp_ice->enable_rtcp_mux) {
1354         pjmedia_sdp_attr *attr;
1355 
1356 	attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,
1357 				     &STR_RTCP_MUX, NULL);
1358 	tp_ice->use_rtcp_mux = (attr? PJ_TRUE: PJ_FALSE);
1359     }
1360 
1361     /* Get the "ice-ufrag" and "ice-pwd" attributes */
1362     get_ice_attr(rem_sdp, rem_m, &ufrag_attr, &pwd_attr);
1363 
1364     /* If "ice-ufrag" or "ice-pwd" are not found, disable ICE */
1365     if (ufrag_attr==NULL || pwd_attr==NULL) {
1366 	sdp_state->match_comp_cnt = 0;
1367 	return PJ_SUCCESS;
1368     }
1369 
1370     /* Verify that default target for each component matches one of the
1371      * candidate for the component. Otherwise stop ICE with ICE ice_mismatch
1372      * error.
1373      */
1374 
1375     /* Component 1 is the c= line */
1376     rem_conn = rem_m->conn;
1377     if (rem_conn == NULL)
1378 	rem_conn = rem_sdp->conn;
1379     if (!rem_conn)
1380 	return PJMEDIA_SDP_EMISSINGCONN;
1381 
1382     /* Verify address family matches */
1383     /*
1384     if ((tp_ice->af==pj_AF_INET() &&
1385 	 pj_strcmp(&rem_conn->addr_type, &STR_IP4)!=0) ||
1386 	(tp_ice->af==pj_AF_INET6() &&
1387 	 pj_strcmp(&rem_conn->addr_type, &STR_IP6)!=0))
1388     {
1389 	return PJMEDIA_SDP_ETPORTNOTEQUAL;
1390     }
1391     */
1392 
1393     /* Get remote address family */
1394     if (pj_strcmp(&rem_conn->addr_type, &STR_IP4)==0)
1395 	rem_af = pj_AF_INET();
1396     else if (pj_strcmp(&rem_conn->addr_type, &STR_IP6)==0)
1397 	rem_af = pj_AF_INET6();
1398     else
1399 	pj_assert(!"Unsupported address family");
1400 
1401     /* Assign remote connection address */
1402     status = pj_sockaddr_init(rem_af, &rem_conn_addr, &rem_conn->addr,
1403 			      (pj_uint16_t)rem_m->desc.port);
1404     if (status != PJ_SUCCESS)
1405 	return status;
1406 
1407     if (tp_ice->comp_cnt > 1) {
1408 	const pjmedia_sdp_attr *attr;
1409 
1410 	/* Get default RTCP candidate from a=rtcp line, if present, otherwise
1411 	 * calculate default RTCP candidate from default RTP target.
1412 	 */
1413 	attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,
1414 				     &STR_RTCP, NULL);
1415 	has_rtcp = (attr != NULL);
1416 
1417 	if (attr) {
1418 	    pjmedia_sdp_rtcp_attr rtcp_attr;
1419 
1420 	    status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp_attr);
1421 	    if (status != PJ_SUCCESS) {
1422 		/* Error parsing a=rtcp attribute */
1423 		return status;
1424 	    }
1425 
1426 	    if (rtcp_attr.addr.slen) {
1427 		/* Verify address family matches */
1428 		/*
1429 		if ((tp_ice->af==pj_AF_INET() &&
1430 		     pj_strcmp(&rtcp_attr.addr_type, &STR_IP4)!=0) ||
1431 		    (tp_ice->af==pj_AF_INET6() &&
1432 		     pj_strcmp(&rtcp_attr.addr_type, &STR_IP6)!=0))
1433 		{
1434 		    return PJMEDIA_SDP_ETPORTNOTEQUAL;
1435 		}
1436 		*/
1437 
1438 		/* Assign RTCP address */
1439 		status = pj_sockaddr_init(rem_af, &rtcp_addr,
1440 					  &rtcp_attr.addr,
1441 					  (pj_uint16_t)rtcp_attr.port);
1442 		if (status != PJ_SUCCESS) {
1443 		    return PJMEDIA_SDP_EINRTCP;
1444 		}
1445 	    } else {
1446 		/* Assign RTCP address */
1447 		status = pj_sockaddr_init(rem_af, &rtcp_addr,
1448 					  NULL,
1449 					  (pj_uint16_t)rtcp_attr.port);
1450 		if (status != PJ_SUCCESS) {
1451 		    return PJMEDIA_SDP_EINRTCP;
1452 		}
1453 		pj_sockaddr_copy_addr(&rtcp_addr, &rem_conn_addr);
1454 	    }
1455 	} else {
1456 	    unsigned rtcp_port;
1457 
1458 	    rtcp_port = pj_sockaddr_get_port(&rem_conn_addr) + 1;
1459 	    pj_sockaddr_cp(&rtcp_addr, &rem_conn_addr);
1460 	    pj_sockaddr_set_port(&rtcp_addr, (pj_uint16_t)rtcp_port);
1461 	}
1462     }
1463 
1464     /* Find the default addresses in a=candidate attributes.
1465      */
1466     for (i=0; i<rem_m->attr_count; ++i) {
1467 	pj_ice_sess_cand cand;
1468         unsigned disable_ice_mismatch = tp_ice->options &
1469                                         PJMEDIA_ICE_DISABLE_ICE_MISMATCH;
1470 
1471 	if (pj_strcmp(&rem_m->attr[i]->name, &STR_CANDIDATE)!=0)
1472 	    continue;
1473 
1474 	status = parse_cand(tp_ice->base.name, tmp_pool,
1475 			    &rem_m->attr[i]->value, &cand);
1476 	if (status != PJ_SUCCESS) {
1477 	    PJ_PERROR(4,(tp_ice->base.name, status,
1478 			 "Error in parsing SDP candidate attribute '%.*s', "
1479 			 "candidate is ignored",
1480 			 (int)rem_m->attr[i]->value.slen,
1481 			 rem_m->attr[i]->value.ptr));
1482 	    continue;
1483 	}
1484 
1485 	if (!comp1_found && cand.comp_id==COMP_RTP)
1486 	{
1487             if ((disable_ice_mismatch) ||
1488                 (pj_sockaddr_cmp(&rem_conn_addr, &cand.addr) == 0))
1489             {
1490                 comp1_found = PJ_TRUE;
1491             }
1492 	} else if (!comp2_found && cand.comp_id==COMP_RTCP)
1493 	{
1494             if ((disable_ice_mismatch) ||
1495                 (pj_sockaddr_cmp(&rtcp_addr, &cand.addr) == 0))
1496             {
1497                 comp2_found = PJ_TRUE;
1498             }
1499 	}
1500 
1501 	if (cand.comp_id == COMP_RTCP)
1502 	    has_rtcp = PJ_TRUE;
1503 
1504 	if (comp1_found && (comp2_found || tp_ice->comp_cnt==1))
1505 	    break;
1506     }
1507 
1508     /* Check matched component count and ice_mismatch */
1509     if (comp1_found &&
1510         (tp_ice->comp_cnt==1 || !has_rtcp || tp_ice->use_rtcp_mux))
1511     {
1512 	sdp_state->match_comp_cnt = 1;
1513 	sdp_state->ice_mismatch = PJ_FALSE;
1514     } else if (comp1_found && comp2_found) {
1515 	sdp_state->match_comp_cnt = 2;
1516 	sdp_state->ice_mismatch = PJ_FALSE;
1517     } else {
1518 	sdp_state->match_comp_cnt = (tp_ice->comp_cnt > 1 && has_rtcp)? 2 : 1;
1519 	sdp_state->ice_mismatch = PJ_TRUE;
1520     }
1521 
1522 
1523     /* Detect remote restarting session */
1524     if (pj_ice_strans_has_sess(tp_ice->ice_st) &&
1525 	(pj_ice_strans_sess_is_running(tp_ice->ice_st) ||
1526 	 pj_ice_strans_sess_is_complete(tp_ice->ice_st)))
1527     {
1528 	pj_str_t rem_run_ufrag, rem_run_pwd;
1529 	pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, NULL, NULL,
1530 				    &rem_run_ufrag, &rem_run_pwd);
1531 	if (pj_strcmp(&ufrag_attr->value, &rem_run_ufrag) ||
1532 	    pj_strcmp(&pwd_attr->value, &rem_run_pwd))
1533 	{
1534 	    /* Remote offers to restart ICE */
1535 	    sdp_state->ice_restart = PJ_TRUE;
1536 	} else {
1537 	    sdp_state->ice_restart = PJ_FALSE;
1538 	}
1539     } else {
1540 	sdp_state->ice_restart = PJ_FALSE;
1541     }
1542 
1543     /* Detect our role */
1544     if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
1545 			      &STR_ICE_LITE, NULL) != NULL)
1546     {
1547 	/* Remote is ICE lite, set our role as controlling */
1548 	sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING;
1549     } else {
1550 	if (current_ice_role==PJ_ICE_SESS_ROLE_CONTROLLING) {
1551 	    sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING;
1552 	} else {
1553 	    sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLED;
1554 	}
1555     }
1556 
1557     /* Check trickle ICE indication */
1558     if (tp_ice->trickle_ice != PJ_ICE_SESS_TRICKLE_DISABLED) {
1559 	sdp_state->has_trickle = pjmedia_ice_sdp_has_trickle(rem_sdp,
1560 							     media_index);
1561 
1562 	/* Reset ICE mismatch flag if conn addr is default address */
1563 	if (sdp_state->ice_mismatch && sdp_state->has_trickle) {
1564 	    pj_sockaddr def_addr;
1565 	    pj_sockaddr_init(rem_af, &def_addr, NULL, 9);
1566 	    if (pj_sockaddr_cmp(&rem_conn_addr, &def_addr)==0)
1567 		sdp_state->ice_mismatch = PJ_FALSE;
1568 	}
1569     } else {
1570 	sdp_state->has_trickle = PJ_FALSE;
1571     }
1572 
1573     PJ_LOG(4,(tp_ice->base.name,
1574 	      "Processing SDP: support ICE=%u, common comp_cnt=%u, "
1575 	      "ice_mismatch=%u, ice_restart=%u, local_role=%s, trickle=%u",
1576 	      (sdp_state->match_comp_cnt != 0),
1577 	      sdp_state->match_comp_cnt,
1578 	      sdp_state->ice_mismatch,
1579 	      sdp_state->ice_restart,
1580 	      pj_ice_sess_role_name(sdp_state->local_role),
1581 	      sdp_state->has_trickle));
1582 
1583     return PJ_SUCCESS;
1584 
1585 }
1586 
1587 /* Encode information in SDP if ICE is not used */
encode_no_ice_in_sdp(struct transport_ice * tp_ice,pj_pool_t * pool,pjmedia_sdp_session * sdp_local,const pjmedia_sdp_session * rem_sdp,unsigned media_index)1588 static pj_status_t encode_no_ice_in_sdp( struct transport_ice *tp_ice,
1589 					 pj_pool_t *pool,
1590 					 pjmedia_sdp_session *sdp_local,
1591 					 const pjmedia_sdp_session *rem_sdp,
1592 					 unsigned media_index)
1593 {
1594     if (tp_ice->enable_rtcp_mux) {
1595         pjmedia_sdp_media *m = sdp_local->media[media_index];
1596         pjmedia_sdp_attr *attr;
1597         pj_bool_t add_rtcp_mux = PJ_TRUE;
1598 
1599 	if (rem_sdp)
1600 	    add_rtcp_mux = tp_ice->use_rtcp_mux;
1601 	else {
1602 	    /* For subsequent offer, set it to false first since
1603 	     * we are still waiting for remote answer.
1604 	     */
1605 	    tp_ice->use_rtcp_mux = PJ_FALSE;
1606 	}
1607 
1608         /* Remove RTCP attribute because for subsequent offers/answers,
1609          * the address (obtained from transport_get_info() ) may be
1610          * incorrect if we are not yet confirmed to use RTCP mux
1611          * (because we are still waiting for remote answer) or
1612          * if remote rejects it.
1613          */
1614         pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, "rtcp");
1615 
1616 	if (!tp_ice->use_rtcp_mux && tp_ice->comp_cnt > 1) {
1617 	    pj_ice_sess_cand cand;
1618 	    pj_status_t status;
1619 
1620 	    status = pj_ice_strans_get_def_cand(tp_ice->ice_st, 2, &cand);
1621 	    if (status == PJ_SUCCESS) {
1622 	   	/* Add RTCP attribute if the remote doesn't offer or
1623 	    	 * rejects it.
1624 	    	 */
1625 	    	attr = pjmedia_sdp_attr_create_rtcp(pool, &cand.addr);
1626 	    	if (attr)
1627 	            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
1628 	    }
1629 	}
1630 
1631 	/* Add a=rtcp-mux attribute. */
1632 	if (add_rtcp_mux) {
1633 	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
1634     	    attr->name = STR_RTCP_MUX;
1635     	    m->attr[m->attr_count++] = attr;
1636 	}
1637     }
1638     return PJ_SUCCESS;
1639 }
1640 
1641 
1642 /* Verify incoming offer and create initial answer */
create_initial_answer(struct transport_ice * tp_ice,pj_pool_t * sdp_pool,pjmedia_sdp_session * loc_sdp,const pjmedia_sdp_session * rem_sdp,unsigned media_index)1643 static pj_status_t create_initial_answer(struct transport_ice *tp_ice,
1644 					 pj_pool_t *sdp_pool,
1645 					 pjmedia_sdp_session *loc_sdp,
1646 					 const pjmedia_sdp_session *rem_sdp,
1647 					 unsigned media_index)
1648 {
1649     const pjmedia_sdp_media *rem_m = rem_sdp->media[media_index];
1650     pj_bool_t with_trickle;
1651     pj_status_t status;
1652 
1653     /* Check if media is removed (just in case) */
1654     if (rem_m->desc.port == 0) {
1655 	return PJ_SUCCESS;
1656     }
1657 
1658     /* Verify the offer */
1659     status = verify_ice_sdp(tp_ice, sdp_pool, rem_sdp, media_index,
1660 			    PJ_ICE_SESS_ROLE_CONTROLLED,
1661 			    &tp_ice->rem_offer_state);
1662     if (status != PJ_SUCCESS) {
1663 	set_no_ice(tp_ice, "Invalid SDP offer", status);
1664 	return status;
1665     }
1666 
1667     /* Does remote support ICE? */
1668     if (tp_ice->rem_offer_state.match_comp_cnt==0) {
1669 	set_no_ice(tp_ice, "No ICE found in SDP offer", PJ_SUCCESS);
1670 	encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, rem_sdp,
1671 			     media_index);
1672 	return PJ_SUCCESS;
1673     }
1674 
1675     /* ICE ice_mismatch? */
1676     if (tp_ice->rem_offer_state.ice_mismatch) {
1677 	set_no_ice(tp_ice, "ICE ice_mismatch in remote offer", PJ_SUCCESS);
1678 	encode_ice_mismatch(sdp_pool, loc_sdp, media_index);
1679 	return PJ_SUCCESS;
1680     }
1681 
1682     /* Encode ICE in SDP */
1683     with_trickle = tp_ice->rem_offer_state.has_trickle &&
1684 		   tp_ice->trickle_ice != PJ_ICE_SESS_TRICKLE_DISABLED;
1685     status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
1686 				   tp_ice->rem_offer_state.match_comp_cnt,
1687 				   PJ_FALSE, tp_ice->use_rtcp_mux,
1688 				   with_trickle);
1689     if (status != PJ_SUCCESS) {
1690 	set_no_ice(tp_ice, "Error encoding SDP answer", status);
1691 	return status;
1692     }
1693 
1694     return PJ_SUCCESS;
1695 }
1696 
1697 
1698 /* Create subsequent SDP offer */
create_subsequent_offer(struct transport_ice * tp_ice,pj_pool_t * sdp_pool,pjmedia_sdp_session * loc_sdp,unsigned media_index)1699 static pj_status_t create_subsequent_offer(struct transport_ice *tp_ice,
1700 					   pj_pool_t *sdp_pool,
1701 					   pjmedia_sdp_session *loc_sdp,
1702 					   unsigned media_index)
1703 {
1704     unsigned comp_cnt;
1705 
1706     if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) {
1707 	/* We don't have ICE */
1708 	encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, NULL, media_index);
1709 	return PJ_SUCCESS;
1710     }
1711 
1712     comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st);
1713     return encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
1714 				 comp_cnt, PJ_FALSE, tp_ice->enable_rtcp_mux,
1715 				 PJ_FALSE);
1716 }
1717 
1718 
1719 /* Create subsequent SDP answer */
create_subsequent_answer(struct transport_ice * tp_ice,pj_pool_t * sdp_pool,pjmedia_sdp_session * loc_sdp,const pjmedia_sdp_session * rem_sdp,unsigned media_index)1720 static pj_status_t create_subsequent_answer(struct transport_ice *tp_ice,
1721 					    pj_pool_t *sdp_pool,
1722 					    pjmedia_sdp_session *loc_sdp,
1723 					    const pjmedia_sdp_session *rem_sdp,
1724 					    unsigned media_index)
1725 {
1726     pj_status_t status;
1727 
1728     /* We have a session */
1729     status = verify_ice_sdp(tp_ice, sdp_pool, rem_sdp, media_index,
1730 			    PJ_ICE_SESS_ROLE_CONTROLLED,
1731 			    &tp_ice->rem_offer_state);
1732     if (status != PJ_SUCCESS) {
1733 	/* Something wrong with the offer */
1734 	return status;
1735     }
1736 
1737     if (pj_ice_strans_has_sess(tp_ice->ice_st)) {
1738 	/*
1739 	 * Received subsequent offer while we have ICE active.
1740 	 */
1741 
1742 	if (tp_ice->rem_offer_state.match_comp_cnt == 0) {
1743 	    /* Remote no longer offers ICE */
1744 	    encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, rem_sdp,
1745 			     	 media_index);
1746 	    return PJ_SUCCESS;
1747 	}
1748 
1749 	if (tp_ice->rem_offer_state.ice_mismatch) {
1750 	    encode_ice_mismatch(sdp_pool, loc_sdp, media_index);
1751 	    return PJ_SUCCESS;
1752 	}
1753 
1754 	status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
1755 				       tp_ice->rem_offer_state.match_comp_cnt,
1756 				       tp_ice->rem_offer_state.ice_restart,
1757 				       tp_ice->use_rtcp_mux, PJ_FALSE);
1758 	if (status != PJ_SUCCESS)
1759 	    return status;
1760 
1761 	/* Done */
1762 
1763     } else {
1764 	pj_bool_t with_trickle;
1765 
1766 	/*
1767 	 * Received subsequent offer while we DON'T have ICE active.
1768 	 */
1769 
1770 	if (tp_ice->rem_offer_state.match_comp_cnt == 0) {
1771 	    /* Remote does not support ICE */
1772 	    encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, rem_sdp,
1773 			     	 media_index);
1774 	    return PJ_SUCCESS;
1775 	}
1776 
1777 	if (tp_ice->rem_offer_state.ice_mismatch) {
1778 	    encode_ice_mismatch(sdp_pool, loc_sdp, media_index);
1779 	    return PJ_SUCCESS;
1780 	}
1781 
1782 	/* Looks like now remote is offering ICE, so we need to create
1783 	 * ICE session now.
1784 	 */
1785 	status = pj_ice_strans_init_ice(tp_ice->ice_st,
1786 					PJ_ICE_SESS_ROLE_CONTROLLED,
1787 					NULL, NULL);
1788 	if (status != PJ_SUCCESS) {
1789 	    /* Fail to create new ICE session */
1790 	    return status;
1791 	}
1792 
1793 	with_trickle = tp_ice->rem_offer_state.has_trickle &&
1794 		       tp_ice->trickle_ice != PJ_ICE_SESS_TRICKLE_DISABLED;
1795 	status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
1796 				       tp_ice->rem_offer_state.match_comp_cnt,
1797 				       tp_ice->rem_offer_state.ice_restart,
1798 				       tp_ice->use_rtcp_mux,
1799 				       with_trickle);
1800 	if (status != PJ_SUCCESS)
1801 	    return status;
1802 
1803 	/* Done */
1804     }
1805 
1806     return PJ_SUCCESS;
1807 }
1808 
1809 
1810 /*
1811  * For both UAC and UAS, pass in the SDP before sending it to remote.
1812  * This will add ICE attributes to the SDP.
1813  */
transport_media_create(pjmedia_transport * tp,pj_pool_t * sdp_pool,unsigned options,const pjmedia_sdp_session * rem_sdp,unsigned media_index)1814 static pj_status_t transport_media_create(pjmedia_transport *tp,
1815 				          pj_pool_t *sdp_pool,
1816 					  unsigned options,
1817 					  const pjmedia_sdp_session *rem_sdp,
1818 					  unsigned media_index)
1819 {
1820     struct transport_ice *tp_ice = (struct transport_ice*)tp;
1821     pj_ice_sess_role ice_role;
1822     pj_status_t status;
1823 
1824     PJ_UNUSED_ARG(media_index);
1825     PJ_UNUSED_ARG(sdp_pool);
1826 
1827     tp_ice->media_option = options;
1828     tp_ice->enable_rtcp_mux = ((options & PJMEDIA_TPMED_RTCP_MUX) != 0);
1829     tp_ice->oa_role = ROLE_NONE;
1830     tp_ice->initial_sdp = PJ_TRUE;
1831 
1832     /* Init SDP "a=mid" attribute. Get from remote SDP for answerer or
1833      * generate one for offerer (or if remote doesn't specify).
1834      */
1835     tp_ice->sdp_mid.slen = 0;
1836     if (rem_sdp) {
1837 	pjmedia_sdp_media *m = rem_sdp->media[media_index];
1838 	pjmedia_sdp_attr *a;
1839 	a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "mid", NULL);
1840 	if (a) {
1841 	    pj_strdup(tp_ice->pool, &tp_ice->sdp_mid, &a->value);
1842 	}
1843     }
1844     if (tp_ice->sdp_mid.slen == 0) {
1845 	char tmp_buf[8];
1846 	pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf), "%d", media_index+1);
1847 	tp_ice->sdp_mid = pj_strdup3(tp_ice->pool, tmp_buf);
1848     }
1849 
1850     /* If RTCP mux is being used, set component count to 1 */
1851     if (rem_sdp && tp_ice->enable_rtcp_mux) {
1852 	pjmedia_sdp_media *rem_m = rem_sdp->media[media_index];
1853         pjmedia_sdp_attr *attr;
1854 	attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,
1855 				     &STR_RTCP_MUX, NULL);
1856 	tp_ice->use_rtcp_mux = (attr? PJ_TRUE: PJ_FALSE);
1857     }
1858     if (tp_ice->use_rtcp_mux &&
1859 	pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st)>1)
1860     {
1861 	pj_ice_strans_update_comp_cnt(tp_ice->ice_st, 1);
1862     }
1863 
1864     /* Init ICE, the initial role is set now based on availability of
1865      * rem_sdp, but it will be checked again later.
1866      */
1867     ice_role = (rem_sdp==NULL ? PJ_ICE_SESS_ROLE_CONTROLLING :
1868 				PJ_ICE_SESS_ROLE_CONTROLLED);
1869     status = pj_ice_strans_init_ice(tp_ice->ice_st, ice_role, NULL, NULL);
1870 
1871     /* For trickle ICE, if remote SDP has been received, process any remote
1872      * ICE info now (ICE user fragment and/or initial ICE candidate list).
1873      */
1874     if (rem_sdp && status == PJ_SUCCESS) {
1875 	if (tp_ice->trickle_ice != PJ_ICE_SESS_TRICKLE_DISABLED &&
1876 	    pjmedia_ice_sdp_has_trickle(rem_sdp, media_index))
1877 	{
1878 	    pj_str_t ufrag, pwd;
1879 	    unsigned cand_cnt = PJ_ICE_ST_MAX_CAND;
1880 	    pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND];
1881 	    pj_bool_t end_of_cand;
1882 
1883 	    status = pjmedia_ice_trickle_decode_sdp(rem_sdp, media_index,
1884 						    NULL, &ufrag, &pwd,
1885 						    &cand_cnt, cand,
1886 						    &end_of_cand);
1887 	    if (status == PJ_SUCCESS)
1888 		status = pj_ice_strans_update_check_list(
1889 					    tp_ice->ice_st, &ufrag, &pwd,
1890 					    cand_cnt, cand, end_of_cand);
1891 	    if (status != PJ_SUCCESS) {
1892 		PJ_PERROR(1,(tp_ice->base.name, status,
1893 			     "Failed create checklist for trickling ICE"));
1894 		return status;
1895 	    }
1896 	}
1897     }
1898 
1899     /* Done */
1900     return status;
1901 }
1902 
1903 
transport_encode_sdp(pjmedia_transport * tp,pj_pool_t * sdp_pool,pjmedia_sdp_session * sdp_local,const pjmedia_sdp_session * rem_sdp,unsigned media_index)1904 static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
1905 				        pj_pool_t *sdp_pool,
1906 				        pjmedia_sdp_session *sdp_local,
1907 				        const pjmedia_sdp_session *rem_sdp,
1908 				        unsigned media_index)
1909 {
1910     struct transport_ice *tp_ice = (struct transport_ice*)tp;
1911     pj_status_t status;
1912 
1913     /* Validate media transport */
1914     /* This transport only support RTP/AVP transport, unless if
1915      * transport checking is disabled
1916      */
1917     if ((tp_ice->media_option & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) {
1918 	pjmedia_sdp_media *m_rem, *m_loc;
1919 	pj_uint32_t tp_proto_loc, tp_proto_rem;
1920 
1921 	m_rem = rem_sdp? rem_sdp->media[media_index] : NULL;
1922 	m_loc = sdp_local->media[media_index];
1923 
1924 	tp_proto_loc = pjmedia_sdp_transport_get_proto(&m_loc->desc.transport);
1925 	tp_proto_rem = m_rem?
1926 		pjmedia_sdp_transport_get_proto(&m_rem->desc.transport) : 0;
1927 	PJMEDIA_TP_PROTO_TRIM_FLAG(tp_proto_loc, PJMEDIA_TP_PROFILE_RTCP_FB);
1928 	PJMEDIA_TP_PROTO_TRIM_FLAG(tp_proto_rem, PJMEDIA_TP_PROFILE_RTCP_FB);
1929 
1930 	if ((tp_proto_loc != PJMEDIA_TP_PROTO_RTP_AVP) ||
1931 	    (m_rem && tp_proto_rem != PJMEDIA_TP_PROTO_RTP_AVP))
1932 	{
1933 	    pjmedia_sdp_media_deactivate(sdp_pool, m_loc);
1934 	    return PJMEDIA_SDP_EINPROTO;
1935 	}
1936     }
1937 
1938     if (tp_ice->initial_sdp) {
1939 	if (rem_sdp) {
1940 	    status = create_initial_answer(tp_ice, sdp_pool, sdp_local,
1941 					   rem_sdp, media_index);
1942 	} else {
1943 	    status = create_initial_offer(tp_ice, sdp_pool, sdp_local,
1944 					  media_index);
1945 	}
1946     } else {
1947 	if (rem_sdp) {
1948 	    status = create_subsequent_answer(tp_ice, sdp_pool, sdp_local,
1949 					      rem_sdp, media_index);
1950 	} else {
1951 	    status = create_subsequent_offer(tp_ice, sdp_pool, sdp_local,
1952 					     media_index);
1953 	}
1954     }
1955 
1956     if (status==PJ_SUCCESS) {
1957 	if (rem_sdp)
1958 	    tp_ice->oa_role = ROLE_ANSWERER;
1959 	else
1960 	    tp_ice->oa_role = ROLE_OFFERER;
1961 
1962 	if (tp_ice->use_ice) {
1963 	    /* Update last local candidate count, so trickle ICE can identify
1964 	     * if there is any new local candidate.
1965 	     */
1966 	    unsigned i, comp_cnt;
1967 	    comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st);
1968 	    for (i = 0; i < comp_cnt; ++i) {
1969 		tp_ice->last_send_cand_cnt[i] =
1970 			pj_ice_strans_get_cands_count(tp_ice->ice_st, i+1);
1971 	    }
1972 	}
1973     }
1974 
1975     return status;
1976 }
1977 
1978 
1979 /* Start ICE session with the specified remote SDP */
start_ice(struct transport_ice * tp_ice,pj_pool_t * tmp_pool,const pjmedia_sdp_session * rem_sdp,unsigned media_index)1980 static pj_status_t start_ice(struct transport_ice *tp_ice,
1981 			     pj_pool_t *tmp_pool,
1982 			     const pjmedia_sdp_session *rem_sdp,
1983 			     unsigned media_index)
1984 {
1985     pjmedia_sdp_media *rem_m = rem_sdp->media[media_index];
1986     const pjmedia_sdp_attr *ufrag_attr, *pwd_attr;
1987     pj_ice_sess_cand *cand;
1988     unsigned i, cand_cnt;
1989     pj_status_t status;
1990 
1991     get_ice_attr(rem_sdp, rem_m, &ufrag_attr, &pwd_attr);
1992 
1993     /* Allocate candidate array */
1994     cand = (pj_ice_sess_cand*)
1995 	   pj_pool_calloc(tmp_pool, PJ_ICE_MAX_CAND,
1996 			  sizeof(pj_ice_sess_cand));
1997 
1998     /* Get all candidates in the media */
1999     cand_cnt = 0;
2000     for (i=0; i<rem_m->attr_count && cand_cnt < PJ_ICE_MAX_CAND; ++i) {
2001 	pjmedia_sdp_attr *attr;
2002 
2003 	attr = rem_m->attr[i];
2004 
2005 	if (pj_strcmp(&attr->name, &STR_CANDIDATE)!=0)
2006 	    continue;
2007 
2008 	/* Parse candidate */
2009 	status = parse_cand(tp_ice->base.name, tmp_pool, &attr->value,
2010 			    &cand[cand_cnt]);
2011 	if (status != PJ_SUCCESS) {
2012 	    PJ_PERROR(4,(tp_ice->base.name, status,
2013 			 "Error in parsing SDP candidate attribute '%.*s', "
2014 			 "candidate is ignored",
2015 			 (int)attr->value.slen, attr->value.ptr));
2016 	    continue;
2017 	}
2018 
2019 	if (!tp_ice->use_rtcp_mux || cand[cand_cnt].comp_id < 2)
2020 	    cand_cnt++;
2021     }
2022 
2023     /* Start ICE */
2024     return pj_ice_strans_start_ice(tp_ice->ice_st, &ufrag_attr->value,
2025 				   &pwd_attr->value, cand_cnt, cand);
2026 }
2027 
2028 
2029 /*
2030  * Start ICE checks when both offer and answer have been negotiated
2031  * by SDP negotiator.
2032  */
transport_media_start(pjmedia_transport * tp,pj_pool_t * tmp_pool,const pjmedia_sdp_session * sdp_local,const pjmedia_sdp_session * rem_sdp,unsigned media_index)2033 static pj_status_t transport_media_start(pjmedia_transport *tp,
2034 				         pj_pool_t *tmp_pool,
2035 				         const pjmedia_sdp_session *sdp_local,
2036 				         const pjmedia_sdp_session *rem_sdp,
2037 				         unsigned media_index)
2038 {
2039     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2040     pjmedia_sdp_media *rem_m;
2041     enum oa_role current_oa_role;
2042     pj_bool_t initial_oa;
2043     pj_status_t status;
2044 
2045     PJ_ASSERT_RETURN(tp && tmp_pool && rem_sdp, PJ_EINVAL);
2046     PJ_ASSERT_RETURN(media_index < rem_sdp->media_count, PJ_EINVAL);
2047 
2048     rem_m = rem_sdp->media[media_index];
2049 
2050     initial_oa = tp_ice->initial_sdp;
2051     current_oa_role = tp_ice->oa_role;
2052 
2053     /* SDP has been negotiated */
2054     tp_ice->initial_sdp = PJ_FALSE;
2055     tp_ice->oa_role = ROLE_NONE;
2056 
2057     /* Nothing to do if we don't have ICE session */
2058     if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) {
2059 	return PJ_SUCCESS;
2060     }
2061 
2062     /* Special case for Session Timer. The re-INVITE for session refresh
2063      * doesn't call transport_encode_sdp(), causing current_oa_role to
2064      * be set to ROLE_NONE. This is a workaround.
2065      */
2066     if (current_oa_role == ROLE_NONE) {
2067 	current_oa_role = ROLE_OFFERER;
2068     }
2069 
2070     /* Processing depends on the offer/answer role */
2071     if (current_oa_role == ROLE_OFFERER) {
2072 	/*
2073 	 * We are offerer. So this will be the first time we see the
2074 	 * remote's SDP.
2075 	 */
2076 	struct sdp_state answer_state;
2077 
2078 	/* Verify the answer */
2079 	status = verify_ice_sdp(tp_ice, tmp_pool, rem_sdp, media_index,
2080 				PJ_ICE_SESS_ROLE_CONTROLLING, &answer_state);
2081 	if (status != PJ_SUCCESS) {
2082 	    /* Something wrong in the SDP answer */
2083 	    set_no_ice(tp_ice, "Invalid remote SDP answer", status);
2084 	    return status;
2085 	}
2086 
2087 	/* Does it have ICE? */
2088 	if (answer_state.match_comp_cnt == 0) {
2089 	    /* Remote doesn't support ICE */
2090 	    set_no_ice(tp_ice, "Remote answer doesn't support ICE",
2091 		       PJ_SUCCESS);
2092 	    return PJ_SUCCESS;
2093 	}
2094 
2095 	/* Check if remote has reported ice-mismatch */
2096 	if (pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,
2097 				  &STR_ICE_MISMATCH, NULL) != NULL)
2098 	{
2099 	    /* Remote has reported ice-mismatch */
2100 	    set_no_ice(tp_ice,
2101 		       "Remote answer contains 'ice-mismatch' attribute",
2102 		       PJ_SUCCESS);
2103 	    return PJ_SUCCESS;
2104 	}
2105 
2106 	/* Check if remote has indicated a restart */
2107 	if (answer_state.ice_restart) {
2108 	    PJ_LOG(2,(tp_ice->base.name,
2109 		      "Warning: remote has signalled ICE restart in SDP "
2110 		      "answer which is disallowed. Remote ICE negotiation"
2111 		      " may fail."));
2112 	}
2113 
2114 	/* Check if the answer itself is mismatched */
2115 	if (answer_state.ice_mismatch) {
2116 	    /* This happens either when a B2BUA modified remote answer but
2117 	     * strangely didn't modify our offer, or remote is not capable
2118 	     * of detecting mismatch in our offer (it didn't put
2119 	     * 'ice-mismatch' attribute in the answer).
2120 	     */
2121 	    PJ_LOG(2,(tp_ice->base.name,
2122 		      "Warning: remote answer mismatch, but it does not "
2123 		      "reject our offer with 'ice-mismatch'. ICE negotiation "
2124 		      "may fail"));
2125 	}
2126 
2127 	/* Do nothing if ICE is complete or running */
2128 	if (pj_ice_strans_sess_is_running(tp_ice->ice_st)) {
2129 	    PJ_LOG(4,(tp_ice->base.name,
2130 		      "Ignored offer/answer because ICE is running"));
2131 	    return PJ_SUCCESS;
2132 	}
2133 
2134 	if (pj_ice_strans_sess_is_complete(tp_ice->ice_st)) {
2135 	    PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged"));
2136 	    return PJ_SUCCESS;
2137 	}
2138 
2139 	/* Start ICE */
2140 
2141     } else {
2142 	/*
2143 	 * We are answerer. We've seen and negotiated remote's SDP
2144 	 * before, and the result is in "rem_offer_state".
2145 	 */
2146 	const pjmedia_sdp_attr *ufrag_attr, *pwd_attr;
2147 
2148 	/* Check for ICE in remote offer */
2149 	if (tp_ice->rem_offer_state.match_comp_cnt == 0) {
2150 	    /* No ICE attribute present */
2151 	    set_no_ice(tp_ice, "Remote no longer offers ICE",
2152 		       PJ_SUCCESS);
2153 	    return PJ_SUCCESS;
2154 	}
2155 
2156 	/* Check for ICE ice_mismatch condition in the offer */
2157 	if (tp_ice->rem_offer_state.ice_mismatch) {
2158 	    set_no_ice(tp_ice, "Remote offer mismatch: ",
2159 		       PJNATH_EICEMISMATCH);
2160 	    return PJ_SUCCESS;
2161 	}
2162 
2163 	/* If ICE is complete and remote doesn't request restart,
2164 	 * then leave the session as is.
2165 	 */
2166 	if (!initial_oa && tp_ice->rem_offer_state.ice_restart == PJ_FALSE) {
2167 	    /* Remote has not requested ICE restart, so session is
2168 	     * unchanged.
2169 	     */
2170 	    PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged"));
2171 	    return PJ_SUCCESS;
2172 	}
2173 
2174 	/* Either remote has requested ICE restart or this is our
2175 	 * first answer.
2176 	 */
2177 
2178 	/* Stop ICE */
2179 	if (!initial_oa) {
2180 	    set_no_ice(tp_ice, "restarting by remote request..", PJ_SUCCESS);
2181 
2182 	    /* We have put new ICE ufrag and pwd in the answer. Now
2183 	     * create a new ICE session with that ufrag/pwd pair.
2184 	     */
2185 	    get_ice_attr(sdp_local, sdp_local->media[media_index],
2186 			 &ufrag_attr, &pwd_attr);
2187 	    status = pj_ice_strans_init_ice(tp_ice->ice_st,
2188 					    tp_ice->rem_offer_state.local_role,
2189 					    &ufrag_attr->value,
2190 					    &pwd_attr->value);
2191 	    if (status != PJ_SUCCESS) {
2192 		PJ_PERROR(1,(tp_ice->base.name, status,
2193 			     "ICE re-initialization failed!"));
2194 		return status;
2195 	    }
2196 	}
2197 
2198 	/* Ticket #977: Update role if turns out we're supposed to be the
2199 	 * Controlling agent (e.g. when talking to ice-lite peer).
2200 	 */
2201 	if (tp_ice->rem_offer_state.local_role==PJ_ICE_SESS_ROLE_CONTROLLING &&
2202 	    pj_ice_strans_has_sess(tp_ice->ice_st))
2203 	{
2204 	    pj_ice_strans_change_role(tp_ice->ice_st,
2205 				      PJ_ICE_SESS_ROLE_CONTROLLING);
2206 	}
2207 
2208 	/* start ICE */
2209     }
2210 
2211     /* RFC 5245 section 8.1.1:
2212      * If its peer has a lite implementation, an agent MUST use
2213      * a regular nomination algorithm.
2214      */
2215     if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
2216 			      &STR_ICE_LITE, NULL) != NULL)
2217     {
2218         pj_ice_sess_options opt;
2219 	pj_ice_strans_get_options(tp_ice->ice_st, &opt);
2220 	if (opt.aggressive) {
2221 	    opt.aggressive = PJ_FALSE;
2222 	    pj_ice_strans_set_options(tp_ice->ice_st, &opt);
2223 	    PJ_LOG(4,(tp_ice->base.name, "Forcefully set ICE to use regular "
2224 		      "nomination as remote is lite implementation"));
2225 	}
2226     }
2227 
2228     /* Now start ICE, if not yet (trickle ICE may have started it earlier) */
2229     if (!pj_ice_strans_sess_is_running(tp_ice->ice_st) &&
2230 	!pj_ice_strans_sess_is_complete(tp_ice->ice_st))
2231     {
2232 	status = start_ice(tp_ice, tmp_pool, rem_sdp, media_index);
2233 	if (status != PJ_SUCCESS) {
2234 	    PJ_PERROR(1,(tp_ice->base.name, status, "ICE restart failed!"));
2235 	    return status;
2236 	}
2237     }
2238 
2239     /* Done */
2240     tp_ice->use_ice = PJ_TRUE;
2241 
2242     return PJ_SUCCESS;
2243 }
2244 
2245 
transport_media_stop(pjmedia_transport * tp)2246 static pj_status_t transport_media_stop(pjmedia_transport *tp)
2247 {
2248     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2249 
2250     set_no_ice(tp_ice, "media stop requested", PJ_SUCCESS);
2251 
2252     return PJ_SUCCESS;
2253 }
2254 
2255 
transport_get_info(pjmedia_transport * tp,pjmedia_transport_info * info)2256 static pj_status_t transport_get_info(pjmedia_transport *tp,
2257 				      pjmedia_transport_info *info)
2258 {
2259     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2260     pj_ice_sess_cand cand;
2261     pj_sockaddr_t *addr;
2262     pj_status_t status;
2263 
2264     pj_bzero(&info->sock_info, sizeof(info->sock_info));
2265     info->sock_info.rtp_sock = info->sock_info.rtcp_sock = PJ_INVALID_SOCKET;
2266 
2267     /* Get RTP default address */
2268     status = pj_ice_strans_get_def_cand(tp_ice->ice_st, 1, &cand);
2269     if (status != PJ_SUCCESS)
2270 	return status;
2271 
2272     /* Address of the default candidate may not be available (e.g:
2273      * STUN/TURN address is still being resolved), so let's find address
2274      * of any other candidate, if still not available, the draft RFC
2275      * seems to allow us using "0.0.0.0:9" in SDP.
2276      */
2277     addr = NULL;
2278     if (pj_sockaddr_has_addr(&cand.addr)) {
2279 	addr = &cand.addr;
2280     } else if (pj_ice_strans_has_sess(tp_ice->ice_st)) {
2281 	unsigned i, cnt = PJ_ICE_ST_MAX_CAND;
2282 	pj_ice_sess_cand cands[PJ_ICE_ST_MAX_CAND];
2283 	pj_ice_strans_enum_cands(tp_ice->ice_st, 1, &cnt, cands);
2284 	for (i = 0; i < cnt && !addr; ++i) {
2285 	    if (pj_sockaddr_has_addr(&cands[i].addr))
2286 		addr = &cands[i].addr;
2287 	}
2288     }
2289     if (addr) {
2290 	pj_sockaddr_cp(&info->sock_info.rtp_addr_name, addr);
2291     } else {
2292 	pj_sockaddr_init(PJ_AF_INET, &info->sock_info.rtp_addr_name, NULL, 9);
2293     }
2294 
2295     /* Get RTCP default address */
2296     if (tp_ice->use_rtcp_mux) {
2297 	pj_sockaddr_cp(&info->sock_info.rtcp_addr_name, addr);
2298     } else if (tp_ice->comp_cnt > 1) {
2299 	status = pj_ice_strans_get_def_cand(tp_ice->ice_st, 2, &cand);
2300 	if (status != PJ_SUCCESS)
2301 	    return status;
2302 
2303 	/* Address of the default candidate may not be available (e.g:
2304 	 * STUN/TURN address is still being resolved), so let's find address
2305 	 * of any other candidate. If none is available, SDP must not include
2306 	 * "a=rtcp" attribute.
2307 	 */
2308 	addr = NULL;
2309 	if (pj_sockaddr_has_addr(&cand.addr)) {
2310 	    addr = &cand.addr;
2311 	} else if (pj_ice_strans_has_sess(tp_ice->ice_st)) {
2312 	    unsigned i, cnt = PJ_ICE_ST_MAX_CAND;
2313 	    pj_ice_sess_cand cands[PJ_ICE_ST_MAX_CAND];
2314 	    pj_ice_strans_enum_cands(tp_ice->ice_st, 2, &cnt, cands);
2315 	    for (i = 0; i < cnt && !addr; ++i) {
2316 		if (pj_sockaddr_has_addr(&cands[i].addr))
2317 		    addr = &cands[i].addr;
2318 	    }
2319 	}
2320 	if (addr) {
2321 	    pj_sockaddr_cp(&info->sock_info.rtcp_addr_name, addr);
2322 	}
2323     }
2324 
2325     /* Set remote address originating RTP & RTCP if this transport has
2326      * ICE activated or received any packets.
2327      */
2328     if (tp_ice->use_ice || tp_ice->rtp_src_cnt) {
2329 	info->src_rtp_name = tp_ice->rtp_src_addr;
2330 	if (tp_ice->use_rtcp_mux)
2331 	    info->src_rtcp_name = tp_ice->rtp_src_addr;
2332     }
2333     if ((!tp_ice->use_rtcp_mux) &&
2334     	(tp_ice->use_ice || tp_ice->rtcp_src_cnt))
2335     {
2336 	info->src_rtcp_name = tp_ice->rtcp_src_addr;
2337     }
2338 
2339     /* Fill up transport specific info */
2340     if (info->specific_info_cnt < PJ_ARRAY_SIZE(info->spc_info)) {
2341 	pjmedia_transport_specific_info *tsi;
2342 	pjmedia_ice_transport_info *ii;
2343 	unsigned i;
2344 
2345 	pj_assert(sizeof(*ii) <= sizeof(tsi->buffer));
2346 	tsi = &info->spc_info[info->specific_info_cnt++];
2347 	tsi->type = PJMEDIA_TRANSPORT_TYPE_ICE;
2348 	tsi->cbsize = sizeof(*ii);
2349 
2350 	ii = (pjmedia_ice_transport_info*) tsi->buffer;
2351 	pj_bzero(ii, sizeof(*ii));
2352 
2353 	ii->active = tp_ice->use_ice;
2354 
2355 	if (pj_ice_strans_has_sess(tp_ice->ice_st))
2356 	    ii->role = pj_ice_strans_get_role(tp_ice->ice_st);
2357 	else
2358 	    ii->role = PJ_ICE_SESS_ROLE_UNKNOWN;
2359 	ii->sess_state = pj_ice_strans_get_state(tp_ice->ice_st);
2360 	ii->comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st);
2361 
2362 	for (i=1; i<=ii->comp_cnt && i<=PJ_ARRAY_SIZE(ii->comp); ++i) {
2363 	    const pj_ice_sess_check *chk;
2364 
2365 	    chk = pj_ice_strans_get_valid_pair(tp_ice->ice_st, i);
2366 	    if (chk) {
2367 		ii->comp[i-1].lcand_type = chk->lcand->type;
2368 		pj_sockaddr_cp(&ii->comp[i-1].lcand_addr,
2369 		               &chk->lcand->addr);
2370 		ii->comp[i-1].rcand_type = chk->rcand->type;
2371 		pj_sockaddr_cp(&ii->comp[i-1].rcand_addr,
2372 		               &chk->rcand->addr);
2373 	    }
2374 	}
2375     }
2376 
2377     return PJ_SUCCESS;
2378 }
2379 
2380 
transport_attach(pjmedia_transport * tp,void * stream,const pj_sockaddr_t * rem_addr,const pj_sockaddr_t * rem_rtcp,unsigned addr_len,void (* rtp_cb)(void *,void *,pj_ssize_t),void (* rtcp_cb)(void *,void *,pj_ssize_t))2381 static pj_status_t transport_attach  (pjmedia_transport *tp,
2382 				      void *stream,
2383 				      const pj_sockaddr_t *rem_addr,
2384 				      const pj_sockaddr_t *rem_rtcp,
2385 				      unsigned addr_len,
2386 				      void (*rtp_cb)(void*,
2387 						     void*,
2388 						     pj_ssize_t),
2389 				      void (*rtcp_cb)(void*,
2390 						      void*,
2391 						      pj_ssize_t))
2392 {
2393     pjmedia_transport_attach_param param;
2394 
2395     pj_bzero(&param, sizeof(param));
2396     param.user_data = stream;
2397     pj_sockaddr_cp(&param.rem_addr, rem_addr);
2398     pj_sockaddr_cp(&param.rem_rtcp, rem_rtcp);
2399     param.addr_len = addr_len;
2400     param.rtp_cb = rtp_cb;
2401     param.rtcp_cb = rtcp_cb;
2402     return transport_attach2(tp, &param);
2403 }
2404 
2405 
transport_attach2(pjmedia_transport * tp,pjmedia_transport_attach_param * att_param)2406 static pj_status_t transport_attach2  (pjmedia_transport *tp,
2407 				       pjmedia_transport_attach_param
2408 				           *att_param)
2409 {
2410     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2411 
2412     tp_ice->stream = att_param->user_data;
2413     tp_ice->rtp_cb = att_param->rtp_cb;
2414     tp_ice->rtp_cb2 = att_param->rtp_cb2;
2415     tp_ice->rtcp_cb = att_param->rtcp_cb;
2416 
2417     /* Check again if we are multiplexing RTP & RTCP. */
2418     tp_ice->use_rtcp_mux = (pj_sockaddr_has_addr(&att_param->rem_addr) &&
2419     			    pj_sockaddr_cmp(&att_param->rem_addr,
2420 					    &att_param->rem_rtcp) == 0);
2421 
2422     pj_memcpy(&tp_ice->remote_rtp, &att_param->rem_addr, att_param->addr_len);
2423     pj_memcpy(&tp_ice->remote_rtcp, &att_param->rem_rtcp, att_param->addr_len);
2424     tp_ice->addr_len = att_param->addr_len;
2425 
2426     /* Init source RTP & RTCP addresses and counter */
2427     tp_ice->rtp_src_addr = tp_ice->remote_rtp;
2428     pj_bzero(&tp_ice->rtcp_src_addr, sizeof(tp_ice->rtcp_src_addr));
2429     tp_ice->rtp_src_cnt = tp_ice->rtcp_src_cnt = 0;
2430 
2431     return PJ_SUCCESS;
2432 }
2433 
2434 
transport_detach(pjmedia_transport * tp,void * strm)2435 static void transport_detach(pjmedia_transport *tp,
2436 			     void *strm)
2437 {
2438     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2439 
2440     /* TODO: need to solve ticket #460 here */
2441 
2442     tp_ice->rtp_cb = NULL;
2443     tp_ice->rtp_cb2 = NULL;
2444     tp_ice->rtcp_cb = NULL;
2445     tp_ice->stream = NULL;
2446 
2447     PJ_UNUSED_ARG(strm);
2448 }
2449 
2450 
transport_send_rtp(pjmedia_transport * tp,const void * pkt,pj_size_t size)2451 static pj_status_t transport_send_rtp(pjmedia_transport *tp,
2452 				      const void *pkt,
2453 				      pj_size_t size)
2454 {
2455     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2456     pj_status_t status;
2457 
2458     /* Simulate packet lost on TX direction */
2459     if (tp_ice->tx_drop_pct) {
2460 	if ((pj_rand() % 100) <= (int)tp_ice->tx_drop_pct) {
2461 	    PJ_LOG(5,(tp_ice->base.name,
2462 		      "TX RTP packet dropped because of pkt lost "
2463 		      "simulation"));
2464 	    return PJ_SUCCESS;
2465 	}
2466     }
2467 
2468     status = pj_ice_strans_sendto2(tp_ice->ice_st, 1,
2469 			           pkt, size, &tp_ice->remote_rtp,
2470 				   tp_ice->addr_len);
2471     if (status == PJ_EPENDING)
2472         status = PJ_SUCCESS;
2473 
2474     return status;
2475 }
2476 
2477 
transport_send_rtcp(pjmedia_transport * tp,const void * pkt,pj_size_t size)2478 static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
2479 				       const void *pkt,
2480 				       pj_size_t size)
2481 {
2482     return transport_send_rtcp2(tp, NULL, 0, pkt, size);
2483 }
2484 
transport_send_rtcp2(pjmedia_transport * tp,const pj_sockaddr_t * addr,unsigned addr_len,const void * pkt,pj_size_t size)2485 static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
2486 				        const pj_sockaddr_t *addr,
2487 				        unsigned addr_len,
2488 				        const void *pkt,
2489 				        pj_size_t size)
2490 {
2491     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2492 
2493     if (tp_ice->comp_cnt > 1 || tp_ice->use_rtcp_mux) {
2494         pj_status_t status;
2495         unsigned comp_id = (tp_ice->use_rtcp_mux? 1: 2);
2496 
2497 	if (addr == NULL) {
2498 	    addr = &tp_ice->remote_rtcp;
2499 	    addr_len = pj_sockaddr_get_len(addr);
2500 	}
2501 
2502 	status = pj_ice_strans_sendto2(tp_ice->ice_st, comp_id, pkt, size,
2503 				       addr, addr_len);
2504 	if (status == PJ_EPENDING)
2505 	    status = PJ_SUCCESS;
2506 
2507 	return status;
2508     } else {
2509 	return PJ_SUCCESS;
2510     }
2511 }
2512 
2513 
ice_on_rx_data(pj_ice_strans * ice_st,unsigned comp_id,void * pkt,pj_size_t size,const pj_sockaddr_t * src_addr,unsigned src_addr_len)2514 static void ice_on_rx_data(pj_ice_strans *ice_st, unsigned comp_id,
2515 			   void *pkt, pj_size_t size,
2516 			   const pj_sockaddr_t *src_addr,
2517 			   unsigned src_addr_len)
2518 {
2519     struct transport_ice *tp_ice;
2520     pj_bool_t discard = PJ_FALSE;
2521 
2522     tp_ice = (struct transport_ice*) pj_ice_strans_get_user_data(ice_st);
2523     if (!tp_ice) {
2524 	/* Destroy on progress */
2525 	return;
2526     }
2527 
2528     if (comp_id == 1) {
2529         ++tp_ice->rtp_src_cnt;
2530     	pj_sockaddr_cp(&tp_ice->rtp_src_addr, src_addr);
2531     } else if (comp_id == 2) {
2532 	pj_sockaddr_cp(&tp_ice->rtcp_src_addr, src_addr);
2533     }
2534 
2535     if (comp_id==1 && (tp_ice->rtp_cb || tp_ice->rtp_cb2)) {
2536         pj_bool_t rem_switch = PJ_FALSE;
2537 
2538 	/* Simulate packet lost on RX direction */
2539 	if (tp_ice->rx_drop_pct) {
2540 	    if ((pj_rand() % 100) <= (int)tp_ice->rx_drop_pct) {
2541 		PJ_LOG(5,(tp_ice->base.name,
2542 			  "RX RTP packet dropped because of pkt lost "
2543 			  "simulation"));
2544 		return;
2545 	    }
2546 	}
2547 
2548 	if (!discard) {
2549 	    if (tp_ice->rtp_cb2) {
2550 		pjmedia_tp_cb_param param;
2551 
2552 	    	param.user_data = tp_ice->stream;
2553 	    	param.pkt = pkt;
2554 	    	param.size = size;
2555 	    	param.src_addr = (tp_ice->use_ice? NULL:
2556 	    			  (pj_sockaddr_t *)src_addr);
2557 	    	param.rem_switch = PJ_FALSE;
2558 	    	(*tp_ice->rtp_cb2)(&param);
2559 	    	rem_switch = param.rem_switch;
2560 	    } else {
2561 	    	(*tp_ice->rtp_cb)(tp_ice->stream, pkt, size);
2562 	    }
2563 	}
2564 
2565 #if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \
2566     (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1)
2567 	if (rem_switch &&
2568 	    (tp_ice->options & PJMEDIA_ICE_NO_SRC_ADDR_CHECKING)==0)
2569 	{
2570 	    char addr_text[PJ_INET6_ADDRSTRLEN+10];
2571 
2572 	    /* Set remote RTP address to source address */
2573 	    pj_sockaddr_cp(&tp_ice->rtp_src_addr, src_addr);
2574 	    pj_sockaddr_cp(&tp_ice->remote_rtp, src_addr);
2575 	    tp_ice->addr_len = pj_sockaddr_get_len(&tp_ice->remote_rtp);
2576 
2577 	    PJ_LOG(4,(tp_ice->base.name,
2578 		      "Remote RTP address switched to %s",
2579 		      pj_sockaddr_print(&tp_ice->remote_rtp, addr_text,
2580 					sizeof(addr_text), 3)));
2581 
2582 	    if (tp_ice->use_rtcp_mux) {
2583 	    	pj_sockaddr_cp(&tp_ice->remote_rtcp, &tp_ice->remote_rtp);
2584 	    } else if (!pj_sockaddr_has_addr(&tp_ice->rtcp_src_addr)) {
2585 	        /* Also update remote RTCP address if actual RTCP source
2586 	         * address is not heard yet.
2587 	         */
2588 		pj_uint16_t port;
2589 
2590 		pj_sockaddr_cp(&tp_ice->remote_rtcp, &tp_ice->remote_rtp);
2591 
2592 		port = (pj_uint16_t)
2593 		       (pj_sockaddr_get_port(&tp_ice->remote_rtp)+1);
2594 		pj_sockaddr_set_port(&tp_ice->remote_rtcp, port);
2595 
2596 		PJ_LOG(4,(tp_ice->base.name,
2597 			  "Remote RTCP address switched to predicted "
2598 			  "address %s",
2599 			  pj_sockaddr_print(&tp_ice->remote_rtcp,
2600 					    addr_text,
2601 					    sizeof(addr_text), 3)));
2602 	    }
2603 	}
2604 #endif
2605 
2606     } else if (comp_id==2 && tp_ice->rtcp_cb) {
2607 
2608 #if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \
2609     (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1)
2610 	/* Check if RTCP source address is the same as the configured
2611 	 * remote address, and switch the address when they are
2612 	 * different.
2613 	 */
2614 	if (!tp_ice->use_ice &&
2615 	    (tp_ice->options & PJMEDIA_ICE_NO_SRC_ADDR_CHECKING)==0)
2616 	{
2617 	    if (pj_sockaddr_cmp(&tp_ice->remote_rtcp, src_addr) == 0) {
2618 		tp_ice->rtcp_src_cnt = 0;
2619 	    } else {
2620 		char addr_text[PJ_INET6_ADDRSTRLEN+10];
2621 
2622 		++tp_ice->rtcp_src_cnt;
2623 		if (tp_ice->rtcp_src_cnt < PJMEDIA_RTCP_NAT_PROBATION_CNT) {
2624 		    discard = PJ_TRUE;
2625 		} else {
2626 		    tp_ice->rtcp_src_cnt = 0;
2627 		    pj_sockaddr_cp(&tp_ice->rtcp_src_addr, src_addr);
2628 		    pj_sockaddr_cp(&tp_ice->remote_rtcp, src_addr);
2629 
2630 		    pj_assert(tp_ice->addr_len==pj_sockaddr_get_len(src_addr));
2631 
2632 		    PJ_LOG(4,(tp_ice->base.name,
2633 			      "Remote RTCP address switched to %s",
2634 			      pj_sockaddr_print(&tp_ice->remote_rtcp,
2635 			                        addr_text, sizeof(addr_text),
2636 			                        3)));
2637 		}
2638 	    }
2639 	}
2640 #endif
2641 
2642 	if (!discard)
2643 	    (*tp_ice->rtcp_cb)(tp_ice->stream, pkt, size);
2644     }
2645 
2646     PJ_UNUSED_ARG(src_addr_len);
2647 }
2648 
2649 
ice_on_ice_complete(pj_ice_strans * ice_st,pj_ice_strans_op op,pj_status_t result)2650 static void ice_on_ice_complete(pj_ice_strans *ice_st,
2651 				pj_ice_strans_op op,
2652 			        pj_status_t result)
2653 {
2654     struct transport_ice *tp_ice;
2655     ice_listener *il;
2656 
2657     tp_ice = (struct transport_ice*) pj_ice_strans_get_user_data(ice_st);
2658     if (!tp_ice) {
2659 	/* Destroy on progress */
2660 	return;
2661     }
2662 
2663     /* Set the flag indicating that local candidate gathering is completed */
2664     if (op == PJ_ICE_STRANS_OP_INIT && result == PJ_SUCCESS)
2665 	tp_ice->end_of_cand = PJ_TRUE;
2666 
2667     pj_perror(5, tp_ice->base.name, result, "ICE operation complete"
2668 	      " (op=%d%s)", op,
2669 	      (op==PJ_ICE_STRANS_OP_INIT? "/initialization" :
2670 	      (op==PJ_ICE_STRANS_OP_NEGOTIATION? "/negotiation":"")));
2671 
2672     /* Notify application */
2673     if (tp_ice->cb.on_ice_complete)
2674 	(*tp_ice->cb.on_ice_complete)(&tp_ice->base, op, result);
2675 
2676     for (il=tp_ice->listener.next; il!=&tp_ice->listener; il=il->next) {
2677 	if (il->cb.on_ice_complete2) {
2678 	    (*il->cb.on_ice_complete2)(&tp_ice->base, op, result,
2679 				       il->user_data);
2680 	} else if (il->cb.on_ice_complete) {
2681 	    (*il->cb.on_ice_complete)(&tp_ice->base, op, result);
2682 	}
2683     }
2684 }
2685 
2686 
ice_on_new_candidate(pj_ice_strans * ice_st,const pj_ice_sess_cand * cand,pj_bool_t last)2687 static void ice_on_new_candidate(pj_ice_strans *ice_st,
2688 				 const pj_ice_sess_cand *cand,
2689 			         pj_bool_t last)
2690 {
2691     struct transport_ice *tp_ice;
2692     ice_listener *il;
2693 
2694     tp_ice = (struct transport_ice*) pj_ice_strans_get_user_data(ice_st);
2695     if (!tp_ice) {
2696 	/* Destroy on progress */
2697 	return;
2698     }
2699 
2700     /* Notify application */
2701     if (tp_ice->cb.on_new_candidate)
2702 	(*tp_ice->cb.on_new_candidate)(&tp_ice->base, cand, last);
2703 
2704     for (il=tp_ice->listener.next; il!=&tp_ice->listener; il=il->next) {
2705 	if (il->cb.on_new_candidate) {
2706 	    (*il->cb.on_new_candidate)(&tp_ice->base, cand, last);
2707 	}
2708     }
2709 }
2710 
2711 
2712 /* Simulate lost */
transport_simulate_lost(pjmedia_transport * tp,pjmedia_dir dir,unsigned pct_lost)2713 static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
2714 					   pjmedia_dir dir,
2715 					   unsigned pct_lost)
2716 {
2717     struct transport_ice *ice = (struct transport_ice*) tp;
2718 
2719     PJ_ASSERT_RETURN(tp && pct_lost <= 100, PJ_EINVAL);
2720 
2721     if (dir & PJMEDIA_DIR_ENCODING)
2722 	ice->tx_drop_pct = pct_lost;
2723 
2724     if (dir & PJMEDIA_DIR_DECODING)
2725 	ice->rx_drop_pct = pct_lost;
2726 
2727     return PJ_SUCCESS;
2728 }
2729 
tp_ice_on_destroy(void * arg)2730 static void tp_ice_on_destroy(void *arg)
2731 {
2732     struct transport_ice *tp_ice = (struct transport_ice*)arg;
2733     pj_pool_safe_release(&tp_ice->pool);
2734 }
2735 
2736 /*
2737  * Destroy ICE media transport.
2738  */
transport_destroy(pjmedia_transport * tp)2739 static pj_status_t transport_destroy(pjmedia_transport *tp)
2740 {
2741     struct transport_ice *tp_ice = (struct transport_ice*)tp;
2742 
2743     /* Reset callback and user data */
2744     pj_bzero(&tp_ice->cb, sizeof(tp_ice->cb));
2745     tp_ice->base.user_data = NULL;
2746     tp_ice->rtp_cb = NULL;
2747     tp_ice->rtp_cb2 = NULL;
2748     tp_ice->rtcp_cb = NULL;
2749 
2750     if (tp_ice->ice_st) {
2751 	pj_grp_lock_t *grp_lock = pj_ice_strans_get_grp_lock(tp_ice->ice_st);
2752 	pj_ice_strans_destroy(tp_ice->ice_st);
2753 	tp_ice->ice_st = NULL;
2754 	pj_grp_lock_dec_ref(grp_lock);
2755     } else {
2756 	tp_ice_on_destroy(tp);
2757     }
2758 
2759     return PJ_SUCCESS;
2760 }
2761 
2762