1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006  Belledonne Communications
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19 
20 
21 #if !defined(_WIN32) && !defined(_WIN32_WCE)
22 #ifdef __APPLE__
23 #include <sys/types.h>
24 #endif
25 #include <sys/socket.h>
26 #include <netdb.h>
27 #endif
28 
29 #include <inttypes.h>
30 
31 #include "mediastreamer2/stun.h"
32 #include "mediastreamer2/ice.h"
33 #include "ortp/ortp.h"
34 #include <bctoolbox/port.h>
35 
36 
37 #define ICE_MAX_NB_CANDIDATES		16
38 #define ICE_MAX_NB_CANDIDATE_PAIRS	100
39 
40 #define ICE_RTP_COMPONENT_ID	1
41 #define ICE_RTCP_COMPONENT_ID	2
42 
43 #define ICE_MIN_COMPONENTID		1
44 #define ICE_MAX_COMPONENTID		256
45 #define ICE_INVALID_COMPONENTID		0
46 #define ICE_MAX_UFRAG_LEN		256
47 #define ICE_MAX_PWD_LEN			256
48 #define ICE_DEFAULT_TA_DURATION		40	/* In milliseconds */
49 #define ICE_DEFAULT_RTO_DURATION	200	/* In milliseconds */
50 #define ICE_DEFAULT_KEEPALIVE_TIMEOUT   15	/* In seconds */
51 #define ICE_GATHERING_CANDIDATES_TIMEOUT	5000	/* In milliseconds */
52 #define ICE_NOMINATION_DELAY		1000	/* In milliseconds */
53 #define ICE_MAX_RETRANSMISSIONS		7
54 #define ICE_MAX_STUN_REQUEST_RETRANSMISSIONS	7
55 
56 
57 typedef struct _TransportAddress_ComponentID {
58 	const IceTransportAddress *ta;
59 	uint16_t componentID;
60 } TransportAddress_ComponentID;
61 
62 typedef struct _Type_ComponentID {
63 	IceCandidateType type;
64 	uint16_t componentID;
65 } Type_ComponentID;
66 
67 typedef struct _Foundation_Pair_Priority_ComponentID {
68 	const IcePairFoundation *foundation;
69 	IceCandidatePair *pair;
70 	uint64_t priority;
71 	uint16_t componentID;
72 } Foundation_Pair_Priority_ComponentID;
73 
74 typedef struct _CheckList_RtpSession {
75 	IceCheckList *cl;
76 	const RtpSession *rtp_session;
77 } CheckList_RtpSession;
78 
79 typedef struct _CheckList_RtpSession_Time {
80 	IceCheckList *cl;
81 	const RtpSession *rtp_session;
82 	MSTimeSpec time;
83 } CheckList_RtpSession_Time;
84 
85 typedef struct _CheckList_Bool {
86 	IceCheckList *cl;
87 	bool_t result;
88 } CheckList_Bool;
89 
90 typedef struct _CheckList_MSListPtr {
91 	const IceCheckList *cl;
92 	bctbx_list_t **list;
93 } CheckList_MSListPtr;
94 
95 typedef struct _LocalCandidate_RemoteCandidate {
96 	IceCandidate *local;
97 	IceCandidate *remote;
98 } LocalCandidate_RemoteCandidate;
99 
100 typedef struct _TransportAddresses {
101 	IceTransportAddress **rtp_taddr;
102 	IceTransportAddress **rtcp_taddr;
103 } TransportAddresses;
104 
105 typedef struct _Time_Bool {
106 	MSTimeSpec time;
107 	bool_t result;
108 } Time_Bool;
109 
110 typedef struct _Session_Index {
111 	IceSession *session;
112 	int index;
113 } Session_Index;
114 
115 typedef struct _LosingRemoteCandidate_InProgress_Failed {
116 	const IceCandidate *losing_remote_candidate;
117 	bool_t in_progress_candidates;
118 	bool_t failed_candidates;
119 } LosingRemoteCandidate_InProgress_Failed;
120 
121 typedef struct _ComponentID_Family {
122 	uint16_t componentID;
123 	int family;
124 } ComponentID_Family;
125 
126 
127 static MSTimeSpec ice_current_time(void);
128 static MSTimeSpec ice_add_ms(MSTimeSpec orig, uint32_t ms);
129 static int32_t ice_compare_time(MSTimeSpec ts1, MSTimeSpec ts2);
130 static void transactionID2string(const UInt96 *tr_id, char *tr_id_str);
131 static IceStunServerRequest * ice_stun_server_request_new(IceCheckList *cl, MSTurnContext *turn_context, RtpTransport *rtptp, int family, const char *srcaddr, int srcport, uint16_t stun_method);
132 static void ice_stun_server_request_transaction_free(IceStunServerRequestTransaction *transaction);
133 static void ice_stun_server_request_free(IceStunServerRequest *request);
134 static IceStunServerRequestTransaction * ice_send_stun_server_request(IceStunServerRequest *request, const struct sockaddr *server, socklen_t addrlen);
135 static void ice_check_list_deallocate_rtp_turn_candidate(IceCheckList *cl);
136 static void ice_check_list_deallocate_rtcp_turn_candidate(IceCheckList *cl);
137 static void ice_check_list_deallocate_turn_candidates(IceCheckList *cl);
138 static int ice_compare_transport_addresses(const IceTransportAddress *ta1, const IceTransportAddress *ta2);
139 static int ice_compare_pair_priorities(const IceCandidatePair *p1, const IceCandidatePair *p2);
140 static int ice_compare_pairs(const IceCandidatePair *p1, const IceCandidatePair *p2);
141 static int ice_compare_candidates(const IceCandidate *c1, const IceCandidate *c2);
142 static int ice_find_host_candidate(const IceCandidate *candidate, const ComponentID_Family *cf);
143 static int ice_find_candidate_from_type_and_componentID(const IceCandidate *candidate, const Type_ComponentID *tc);
144 static int ice_find_use_candidate_valid_pair_from_componentID(const IceValidCandidatePair* valid_pair, const uint16_t* componentID);
145 static int ice_find_nominated_valid_pair_from_componentID(const IceValidCandidatePair* valid_pair, const uint16_t* componentID);
146 static int ice_find_selected_valid_pair_from_componentID(const IceValidCandidatePair* valid_pair, const uint16_t* componentID);
147 static void ice_find_selected_valid_pair_for_componentID(const uint16_t *componentID, CheckList_Bool *cb);
148 static int ice_find_pair_in_valid_list(IceValidCandidatePair *valid_pair, IceCandidatePair *pair);
149 static void ice_pair_set_state(IceCandidatePair *pair, IceCandidatePairState state);
150 static void ice_compute_candidate_foundation(IceCandidate *candidate, IceCheckList *cl);
151 static void ice_set_credentials(char **ufrag, char **pwd, const char *ufrag_str, const char *pwd_str);
152 static void ice_conclude_processing(IceCheckList* cl, RtpSession* rtp_session);
153 static void ice_check_list_stop_gathering(IceCheckList *cl);
154 static void ice_check_list_remove_stun_server_request(IceCheckList *cl, UInt96 *tr_id);
155 static IceStunServerRequest * ice_check_list_get_stun_server_request(IceCheckList *cl, UInt96 *tr_id);
156 static void ice_transport_address_to_printable_ip_address(const IceTransportAddress *taddr, char *printable_ip, size_t printable_ip_size);
157 static void ice_stun_server_request_add_transaction(IceStunServerRequest *request, IceStunServerRequestTransaction *transaction);
158 
159 
160 /******************************************************************************
161  * CONSTANTS DEFINITIONS                                                      *
162  *****************************************************************************/
163 
164 static const char * const role_values[] = {
165 	"Controlling",	/* IR_Controlling */
166 	"Controlled",	/* IR_Controlled */
167 };
168 
169 static const char * const candidate_type_values[] = {
170 	"host",		/* ICT_HostCandidate */
171 	"srflx",	/* ICT_ServerReflexiveCandidate */
172 	"prflx",	/* ICT_PeerReflexiveCandidate */
173 	"relay"		/* ICT_RelayedCandidate */
174 };
175 
176 /**
177  * ICE candidate type preference values as recommended in 4.1.1.2.
178  */
179 static const uint8_t type_preference_values[] = {
180 	126,	/* ICT_HostCandidate */
181 	100,	/* ICT_ServerReflexiveCandidate */
182 	110,	/* ICT_PeerReflexiveCandidate */
183 	0	/* ICT_RelayedCandidate */
184 };
185 
186 static const char * const candidate_pair_state_values[] = {
187 	"Waiting",	/* ICP_Waiting */
188 	"In-Progress",	/* ICP_InProgress */
189 	"Succeeded",	/* ICP_Succeeded */
190 	"Failed",	/* ICP_Failed */
191 	"Frozen"	/* ICP_Frozen */
192 };
193 
194 
195 /******************************************************************************
196  * SESSION INITIALISATION AND DEINITIALISATION                                *
197  *****************************************************************************/
198 
generate_tie_breaker(void)199 static uint64_t generate_tie_breaker(void)
200 {
201 	return (((uint64_t)ortp_random()) << 32) | (((uint64_t)ortp_random()) & 0xffffffff);
202 }
203 
generate_ufrag(void)204 static char * generate_ufrag(void)
205 {
206 	return ms_strdup_printf("%08x", (int)ortp_random());
207 }
208 
generate_pwd(void)209 static char * generate_pwd(void)
210 {
211 	return ms_strdup_printf("%08x%08x%08x", (int)ortp_random(), (int)ortp_random(), (int)ortp_random());
212 }
213 
ice_session_init(IceSession * session)214 static void ice_session_init(IceSession *session)
215 {
216 	session->state = IS_Stopped;
217 	session->role = IR_Controlling;
218 	session->tie_breaker = generate_tie_breaker();
219 	session->ta = ICE_DEFAULT_TA_DURATION;
220 	session->keepalive_timeout = ICE_DEFAULT_KEEPALIVE_TIMEOUT;
221 	session->max_connectivity_checks = ICE_MAX_NB_CANDIDATE_PAIRS;
222 	session->local_ufrag = generate_ufrag();
223 	session->local_pwd = generate_pwd();
224 	session->remote_ufrag = NULL;
225 	session->remote_pwd = NULL;
226 	session->send_event = FALSE;
227 	session->gathering_start_ts.tv_sec = session->gathering_start_ts.tv_nsec = -1;
228 	session->gathering_end_ts.tv_sec = session->gathering_end_ts.tv_nsec = -1;
229 	session->check_message_integrity=TRUE;
230 	session->default_types[0] = ICT_RelayedCandidate;
231 	session->default_types[1] = ICT_ServerReflexiveCandidate;
232 	session->default_types[2] = ICT_HostCandidate;
233 	session->default_types[2] = ICT_CandidateInvalid;
234 }
235 
ice_session_new(void)236 IceSession * ice_session_new(void)
237 {
238 	IceSession *session = ms_new0(IceSession, 1);
239 	if (session == NULL) {
240 		ms_error("ice: Memory allocation of ICE session failed");
241 		return NULL;
242 	}
243 	ice_session_init(session);
244 	return session;
245 }
246 
ice_session_destroy(IceSession * session)247 void ice_session_destroy(IceSession *session)
248 {
249 	int i;
250 	if (session != NULL) {
251 		for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
252 			if (session->streams[i] != NULL) {
253 				ice_check_list_destroy(session->streams[i]);
254 				session->streams[i] = NULL;
255 			}
256 		}
257 		if (session->local_ufrag) ms_free(session->local_ufrag);
258 		if (session->local_pwd) ms_free(session->local_pwd);
259 		if (session->remote_ufrag) ms_free(session->remote_ufrag);
260 		if (session->remote_pwd) ms_free(session->remote_pwd);
261 		ms_free(session);
262 	}
263 }
264 
ice_session_set_default_candidates_types(IceSession * session,const IceCandidateType types[ICT_CandidateTypeMax])265 void ice_session_set_default_candidates_types(IceSession *session, const IceCandidateType types[ICT_CandidateTypeMax]){
266 	memcpy(session->default_types, types, sizeof(session->default_types));
267 }
268 
ice_session_enable_message_integrity_check(IceSession * session,bool_t enable)269 void ice_session_enable_message_integrity_check(IceSession *session,bool_t enable) {
270 	session->check_message_integrity=enable;
271 }
272 
273 /******************************************************************************
274  * CHECK LIST INITIALISATION AND DEINITIALISATION                             *
275  *****************************************************************************/
276 
ice_check_list_init(IceCheckList * cl)277 static void ice_check_list_init(IceCheckList *cl)
278 {
279 	cl->session = NULL;
280 	cl->rtp_session = NULL;
281 	cl->remote_ufrag = cl->remote_pwd = NULL;
282 	cl->stun_server_requests = NULL;
283 	cl->local_candidates = cl->remote_candidates = cl->pairs = cl->losing_pairs = cl->triggered_checks_queue = cl->check_list = cl->valid_list = cl->transaction_list = NULL;
284 	cl->local_componentIDs = cl->remote_componentIDs = cl->foundations = NULL;
285 	cl->state = ICL_Running;
286 	cl->foundation_generator = 1;
287 	cl->mismatch = FALSE;
288 	cl->gathering_candidates = FALSE;
289 	cl->gathering_finished = FALSE;
290 	cl->nomination_delay_running = FALSE;
291 	cl->ta_time = ice_current_time();
292 	memset(&cl->keepalive_time, 0, sizeof(cl->keepalive_time));
293 	memset(&cl->gathering_start_time, 0, sizeof(cl->gathering_start_time));
294 	memset(&cl->nomination_delay_start_time, 0, sizeof(cl->nomination_delay_start_time));
295 }
296 
ice_check_list_new(void)297 IceCheckList * ice_check_list_new(void)
298 {
299 	IceCheckList *cl = ms_new0(IceCheckList, 1);
300 	if (cl == NULL) {
301 		ms_error("ice_check_list_new: Memory allocation failed");
302 		return NULL;
303 	}
304 	ice_check_list_init(cl);
305 	return cl;
306 }
307 
ice_compute_pair_priority(IceCandidatePair * pair,const IceRole * role)308 static void ice_compute_pair_priority(IceCandidatePair *pair, const IceRole *role)
309 {
310 	/* Use formula defined in 5.7.2 to compute pair priority. */
311 	uint64_t G = 0;
312 	uint64_t D = 0;
313 
314 	switch (*role) {
315 		case IR_Controlling:
316 			G = pair->local->priority;
317 			D = pair->remote->priority;
318 			break;
319 		case IR_Controlled:
320 			G = pair->remote->priority;
321 			D = pair->local->priority;
322 			break;
323 	}
324 	pair->priority = (MIN(G, D) << 32) | (MAX(G, D) << 1) | (G > D ? 1 : 0);
325 }
326 
ice_pair_new(IceCheckList * cl,IceCandidate * local_candidate,IceCandidate * remote_candidate)327 static IceCandidatePair *ice_pair_new(IceCheckList *cl, IceCandidate* local_candidate, IceCandidate *remote_candidate)
328 {
329 	IceCandidatePair *pair = ms_new0(IceCandidatePair, 1);
330 	pair->local = local_candidate;
331 	pair->remote = remote_candidate;
332 	pair->state = ICP_Frozen;
333 	pair->is_default = FALSE;
334 	pair->is_nominated = FALSE;
335 	pair->use_candidate = FALSE;
336 	pair->wait_transaction_timeout = FALSE;
337 	if ((pair->local->is_default == TRUE) && (pair->remote->is_default == TRUE)) pair->is_default = TRUE;
338 	else pair->is_default = FALSE;
339 	pair->rto = ICE_DEFAULT_RTO_DURATION;
340 	pair->retransmissions = 0;
341 	pair->role = cl->session->role;
342 	ice_compute_pair_priority(pair, &cl->session->role);
343 	pair->retry_with_dummy_message_integrity=!cl->session->check_message_integrity;
344 	return pair;
345 }
346 
ice_free_transaction(IceTransaction * transaction)347 static void ice_free_transaction(IceTransaction *transaction)
348 {
349 	ms_free(transaction);
350 }
351 
ice_free_pair_foundation(IcePairFoundation * foundation)352 static void ice_free_pair_foundation(IcePairFoundation *foundation)
353 {
354 	ms_free(foundation);
355 }
356 
ice_free_valid_pair(IceValidCandidatePair * valid_pair)357 static void ice_free_valid_pair(IceValidCandidatePair *valid_pair)
358 {
359 	ms_free(valid_pair);
360 }
361 
ice_free_candidate_pair(IceCandidatePair * pair,IceCheckList * cl)362 static void ice_free_candidate_pair(IceCandidatePair *pair, IceCheckList *cl)
363 {
364 	bctbx_list_t *elem;
365 	while ((elem = bctbx_list_find(cl->check_list, pair)) != NULL) {
366 		cl->check_list = bctbx_list_remove(cl->check_list, pair);
367 	}
368 	while ((elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_pair_in_valid_list, pair)) != NULL) {
369 		ice_free_valid_pair(elem->data);
370 		cl->valid_list = bctbx_list_erase_link(cl->valid_list, elem);
371 	}
372 	ms_free(pair);
373 }
374 
ice_free_candidate(IceCandidate * candidate)375 static void ice_free_candidate(IceCandidate *candidate)
376 {
377 	ms_free(candidate);
378 }
379 
ice_check_list_destroy_turn_contexts(IceCheckList * cl)380 static void ice_check_list_destroy_turn_contexts(IceCheckList *cl) {
381 	ice_check_list_deallocate_turn_candidates(cl);
382 	if (cl->rtp_turn_context != NULL) {
383 		ms_turn_context_destroy(cl->rtp_turn_context);
384 		cl->rtp_turn_context = NULL;
385 	}
386 	if (cl->rtcp_turn_context != NULL) {
387 		ms_turn_context_destroy(cl->rtcp_turn_context);
388 		cl->rtcp_turn_context = NULL;
389 	}
390 }
391 
ice_check_list_destroy(IceCheckList * cl)392 void ice_check_list_destroy(IceCheckList *cl)
393 {
394 	ice_check_list_destroy_turn_contexts(cl);
395 	if (cl->remote_ufrag) ms_free(cl->remote_ufrag);
396 	if (cl->remote_pwd) ms_free(cl->remote_pwd);
397 	bctbx_list_for_each(cl->stun_server_requests, (void (*)(void*))ice_stun_server_request_free);
398 	bctbx_list_for_each(cl->transaction_list, (void (*)(void*))ice_free_transaction);
399 	bctbx_list_for_each(cl->foundations, (void (*)(void*))ice_free_pair_foundation);
400 	bctbx_list_for_each2(cl->pairs, (void (*)(void*,void*))ice_free_candidate_pair, cl);
401 	bctbx_list_for_each(cl->valid_list, (void (*)(void*))ice_free_valid_pair);
402 	bctbx_list_for_each(cl->remote_candidates, (void (*)(void*))ice_free_candidate);
403 	bctbx_list_for_each(cl->local_candidates, (void (*)(void*))ice_free_candidate);
404 	bctbx_list_free(cl->stun_server_requests);
405 	bctbx_list_free(cl->transaction_list);
406 	bctbx_list_free(cl->foundations);
407 	bctbx_list_free(cl->local_componentIDs);
408 	bctbx_list_free(cl->remote_componentIDs);
409 	bctbx_list_free(cl->valid_list);
410 	bctbx_list_free(cl->check_list);
411 	bctbx_list_free(cl->triggered_checks_queue);
412 	bctbx_list_free(cl->losing_pairs);
413 	bctbx_list_free(cl->pairs);
414 	bctbx_list_free(cl->remote_candidates);
415 	bctbx_list_free(cl->local_candidates);
416 	memset(cl, 0, sizeof(IceCheckList));
417 	ms_free(cl);
418 }
419 
420 
421 
422 /******************************************************************************
423  * CANDIDATE ACCESSORS                                                        *
424  *****************************************************************************/
425 
ice_candidate_type(const IceCandidate * candidate)426 const char *ice_candidate_type(const IceCandidate *candidate)
427 {
428 	return candidate_type_values[candidate->type];
429 }
430 
431 /******************************************************************************
432  * CANDIDATE PAIR ACCESSORS                                                   *
433  *****************************************************************************/
434 
ice_pair_set_state(IceCandidatePair * pair,IceCandidatePairState state)435 static void ice_pair_set_state(IceCandidatePair *pair, IceCandidatePairState state)
436 {
437 	if (pair->state != state) {
438 		pair->state = state;
439 	}
440 }
441 
442 
443 /******************************************************************************
444  * CHECK LIST ACCESSORS                                                       *
445  *****************************************************************************/
446 
ice_check_list_state(const IceCheckList * cl)447 IceCheckListState ice_check_list_state(const IceCheckList* cl)
448 {
449 	return cl->state;
450 }
451 
ice_find_check_list_from_state(const IceSession * session,IceCheckListState state)452 static IceCheckList * ice_find_check_list_from_state(const IceSession *session, IceCheckListState state)
453 {
454 	int i;
455 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
456 		if (session->streams[i] && ice_check_list_state(session->streams[i]) == state) return session->streams[i];
457 	}
458 	return NULL;
459 }
460 
ice_check_list_set_state(IceCheckList * cl,IceCheckListState state)461 void ice_check_list_set_state(IceCheckList *cl, IceCheckListState state)
462 {
463 	if (cl->state != state) {
464 		cl->state = state;
465 		if (ice_find_check_list_from_state(cl->session, ICL_Running) == NULL) {
466 			if (ice_find_check_list_from_state(cl->session, ICL_Failed) != NULL) {
467 				/* Set the state of the session to Failed if at least one check list is in the Failed state. */
468 				cl->session->state = IS_Failed;
469 			} else {
470 				/* All the check lists are in the Completed state, set the state of the session to Completed. */
471 				cl->session->state = IS_Completed;
472 			}
473 		}
474 	}
475 }
476 
ice_check_list_set_rtp_session(IceCheckList * cl,RtpSession * rtp_session)477 void ice_check_list_set_rtp_session(IceCheckList *cl, RtpSession *rtp_session)
478 {
479 	cl->rtp_session = rtp_session;
480 }
481 
ice_check_list_local_ufrag(const IceCheckList * cl)482 const char * ice_check_list_local_ufrag(const IceCheckList* cl)
483 {
484 	/* Do not handle media specific ufrag for the moment, so use the session local ufrag. */
485 	return cl->session->local_ufrag;
486 }
487 
ice_check_list_local_pwd(const IceCheckList * cl)488 const char * ice_check_list_local_pwd(const IceCheckList* cl)
489 {
490 	/* Do not handle media specific pwd for the moment, so use the session local pwd. */
491 	return cl->session->local_pwd;
492 }
493 
ice_check_list_remote_ufrag(const IceCheckList * cl)494 const char * ice_check_list_remote_ufrag(const IceCheckList* cl)
495 {
496 	if (cl->remote_ufrag) return cl->remote_ufrag;
497 	else return cl->session->remote_ufrag;
498 }
499 
ice_check_list_remote_pwd(const IceCheckList * cl)500 const char * ice_check_list_remote_pwd(const IceCheckList* cl)
501 {
502 	if (cl->remote_pwd) return cl->remote_pwd;
503 	else return cl->session->remote_pwd;
504 }
505 
ice_find_default_local_candidate(const IceCandidate * candidate,const uint16_t * componentID)506 static int ice_find_default_local_candidate(const IceCandidate *candidate, const uint16_t *componentID)
507 {
508 	return !((candidate->componentID == *componentID) && (candidate->is_default == TRUE));
509 }
510 
ice_check_list_remote_credentials_changed(IceCheckList * cl,const char * ufrag,const char * pwd)511 bool_t ice_check_list_remote_credentials_changed(IceCheckList *cl, const char *ufrag, const char *pwd)
512 {
513 	const char *old_ufrag;
514 	const char *old_pwd;
515 	if ((cl->remote_ufrag == NULL) || (cl->remote_pwd == NULL)) {
516 		if (cl->remote_ufrag == NULL) old_ufrag = cl->session->remote_ufrag;
517 		else old_ufrag = cl->remote_ufrag;
518 		if ((strlen(ufrag) != strlen(old_ufrag)) || (strcmp(ufrag, old_ufrag) != 0)) return TRUE;
519 		if (cl->remote_pwd == NULL) old_pwd = cl->session->remote_pwd;
520 		else old_pwd = cl->remote_pwd;
521 		if ((strlen(pwd) != strlen(old_pwd)) || (strcmp(pwd, old_pwd) != 0)) return TRUE;
522 		return FALSE;
523 	}
524 	if (strlen(ufrag) != strlen(cl->remote_ufrag) || (strcmp(ufrag, cl->remote_ufrag) != 0)) return TRUE;
525 	if (strlen(pwd) != strlen(cl->remote_pwd) || (strcmp(pwd, cl->remote_pwd) != 0)) return TRUE;
526 	return FALSE;
527 }
528 
ice_check_list_set_remote_credentials(IceCheckList * cl,const char * ufrag,const char * pwd)529 void ice_check_list_set_remote_credentials(IceCheckList *cl, const char *ufrag, const char *pwd)
530 {
531 	ice_set_credentials(&cl->remote_ufrag, &cl->remote_pwd, ufrag, pwd);
532 }
533 
ice_check_list_get_remote_ufrag(const IceCheckList * cl)534 const char* ice_check_list_get_remote_ufrag(const IceCheckList *cl)
535 {
536 	return cl->remote_ufrag;
537 }
538 
ice_check_list_get_remote_pwd(const IceCheckList * cl)539 const char* ice_check_list_get_remote_pwd(const IceCheckList *cl)
540 {
541 	return cl->remote_pwd;
542 }
543 
ice_check_list_default_local_candidate(const IceCheckList * cl,IceCandidate ** rtp_candidate,IceCandidate ** rtcp_candidate)544 bool_t ice_check_list_default_local_candidate(const IceCheckList *cl, IceCandidate **rtp_candidate, IceCandidate **rtcp_candidate) {
545 	uint16_t componentID;
546 	bctbx_list_t *elem;
547 
548 	if (rtp_candidate != NULL) {
549 		componentID = 1;
550 		elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_default_local_candidate, &componentID);
551 		if (elem == NULL) return FALSE;
552 		*rtp_candidate = (IceCandidate *)elem->data;
553 	}
554 	if (rtcp_candidate != NULL) {
555 		componentID = 2;
556 		elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_default_local_candidate, &componentID);
557 		if (elem == NULL) return FALSE;
558 		*rtcp_candidate = (IceCandidate *)elem->data;
559 	}
560 
561 	return TRUE;
562 }
563 
ice_check_list_selected_valid_local_candidate(const IceCheckList * cl,IceCandidate ** rtp_candidate,IceCandidate ** rtcp_candidate)564 bool_t ice_check_list_selected_valid_local_candidate(const IceCheckList *cl, IceCandidate **rtp_candidate, IceCandidate **rtcp_candidate) {
565 	IceValidCandidatePair *valid_pair = NULL;
566 	uint16_t componentID;
567 	bctbx_list_t *elem;
568 
569 	if (rtp_candidate != NULL) {
570 		componentID = 1;
571 		elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_selected_valid_pair_from_componentID, &componentID);
572 		if (elem == NULL) return FALSE;
573 		valid_pair = (IceValidCandidatePair *)elem->data;
574 		*rtp_candidate = valid_pair->valid->local;
575 	}
576 	if (rtcp_candidate != NULL) {
577 		if (rtp_session_rtcp_mux_enabled(cl->rtp_session)) {
578 			componentID = 1;
579 		} else {
580 			componentID = 2;
581 		}
582 		elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_selected_valid_pair_from_componentID, &componentID);
583 		if (elem == NULL) return FALSE;
584 		valid_pair = (IceValidCandidatePair *)elem->data;
585 		*rtcp_candidate = valid_pair->valid->local;
586 	}
587 
588 	return TRUE;
589 }
590 
ice_check_list_selected_valid_remote_candidate(const IceCheckList * cl,IceCandidate ** rtp_candidate,IceCandidate ** rtcp_candidate)591 bool_t ice_check_list_selected_valid_remote_candidate(const IceCheckList *cl, IceCandidate **rtp_candidate, IceCandidate **rtcp_candidate) {
592 	IceValidCandidatePair *valid_pair = NULL;
593 	uint16_t componentID;
594 	bctbx_list_t *elem;
595 
596 	if (rtp_candidate != NULL) {
597 		componentID = 1;
598 		elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_selected_valid_pair_from_componentID, &componentID);
599 		if (elem == NULL) return FALSE;
600 		valid_pair = (IceValidCandidatePair *)elem->data;
601 		*rtp_candidate = valid_pair->valid->remote;
602 	}
603 	if (rtcp_candidate != NULL) {
604 		if (rtp_session_rtcp_mux_enabled(cl->rtp_session)) {
605 			componentID = 1;
606 		} else {
607 			componentID = 2;
608 		}
609 		elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_selected_valid_pair_from_componentID, &componentID);
610 		if (elem == NULL) return FALSE;
611 		valid_pair = (IceValidCandidatePair *)elem->data;
612 		*rtcp_candidate = valid_pair->valid->remote;
613 	}
614 
615 	return TRUE;
616 }
617 
ice_find_host_pair_identical_to_reflexive_pair(const IceCandidatePair * p1,const IceCandidatePair * p2)618 static int ice_find_host_pair_identical_to_reflexive_pair(const IceCandidatePair *p1, const IceCandidatePair *p2)
619 {
620 	return !((ice_compare_transport_addresses(&p1->local->taddr, &p2->local->taddr) == 0)
621 		&& (p1->local->componentID == p2->local->componentID)
622 		&& (ice_compare_transport_addresses(&p1->remote->taddr, &p2->remote->taddr) == 0)
623 		&& (p1->remote->componentID == p2->remote->componentID)
624 		&& (p1->remote->type == ICT_HostCandidate));
625 }
626 
ice_check_list_selected_valid_candidate_type(const IceCheckList * cl)627 IceCandidateType ice_check_list_selected_valid_candidate_type(const IceCheckList *cl)
628 {
629 	IceCandidatePair *pair = NULL;
630 	IceCandidateType type = ICT_RelayedCandidate;
631 	bctbx_list_t *elem;
632 	uint16_t componentID = 1;
633 
634 	elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_selected_valid_pair_from_componentID, &componentID);
635 	if (elem == NULL) return type;
636 	pair = ((IceValidCandidatePair *)elem->data)->valid;
637 	if (pair->local->type == ICT_RelayedCandidate) return ICT_RelayedCandidate;
638 	type = pair->remote->type;
639 	/**
640 	 * If the pair is reflexive, check if there is a pair with the same addresses and componentID that is of host type to
641 	 * report host connection instead of reflexive connection. This might happen if the ICE checks discover reflexives
642 	 * candidates before the signaling layer has communicated the host candidates to the other peer.
643 	 */
644 	if ((type == ICT_ServerReflexiveCandidate) || (type == ICT_PeerReflexiveCandidate)) {
645 		elem = bctbx_list_find_custom(cl->pairs, (bctbx_compare_func)ice_find_host_pair_identical_to_reflexive_pair, pair);
646 		if (elem != NULL) {
647 			type = ((IceCandidatePair *)elem->data)->remote->type;
648 		}
649 	}
650 	return type;
651 }
652 
ice_check_list_check_completed(IceCheckList * cl)653 void ice_check_list_check_completed(IceCheckList *cl)
654 {
655 	CheckList_Bool cb;
656 
657 	if (cl->state != ICL_Completed) {
658 		cb.cl = cl;
659 		cb.result = TRUE;
660 		bctbx_list_for_each2(cl->local_componentIDs, (void (*)(void*,void*))ice_find_selected_valid_pair_for_componentID, &cb);
661 		if (cb.result == TRUE) {
662 			ice_check_list_set_state(cl, ICL_Completed);
663 		}
664 	}
665 }
666 
ice_check_list_queue_triggered_check(IceCheckList * cl,IceCandidatePair * pair)667 static void ice_check_list_queue_triggered_check(IceCheckList *cl, IceCandidatePair *pair)
668 {
669 	bctbx_list_t *elem = bctbx_list_find(cl->triggered_checks_queue, pair);
670 	if (elem != NULL) {
671 		/* The pair is already in the triggered checks queue, do not add it again. */
672 	} else {
673 		cl->triggered_checks_queue = bctbx_list_append(cl->triggered_checks_queue, pair);
674 	}
675 }
676 
ice_check_list_pop_triggered_check(IceCheckList * cl)677 static IceCandidatePair * ice_check_list_pop_triggered_check(IceCheckList *cl)
678 {
679 	IceCandidatePair *pair;
680 
681 	if (bctbx_list_size(cl->triggered_checks_queue) == 0) return NULL;
682 	pair = bctbx_list_nth_data(cl->triggered_checks_queue, 0);
683 	if (pair != NULL) {
684 		/* Remove the first element in the triggered checks queue. */
685 		cl->triggered_checks_queue = bctbx_list_erase_link(cl->triggered_checks_queue, cl->triggered_checks_queue);
686 	}
687 	return pair;
688 }
689 
ice_find_non_frozen_pair(const IceCandidatePair * pair,const void * dummy)690 static int ice_find_non_frozen_pair(const IceCandidatePair *pair, const void *dummy)
691 {
692 	return (pair->state == ICP_Frozen);
693 }
694 
ice_check_list_is_frozen(const IceCheckList * cl)695 static bool_t ice_check_list_is_frozen(const IceCheckList *cl)
696 {
697 	bctbx_list_t *elem = bctbx_list_find_custom(cl->check_list, (bctbx_compare_func)ice_find_non_frozen_pair, NULL);
698 	return (elem == NULL);
699 }
700 
ice_check_list_is_mismatch(const IceCheckList * cl)701 bool_t ice_check_list_is_mismatch(const IceCheckList *cl)
702 {
703 	return cl->mismatch;
704 }
705 
706 
707 /******************************************************************************
708  * SESSION ACCESSORS                                                          *
709  *****************************************************************************/
710 
ice_session_check_list(const IceSession * session,int n)711 IceCheckList * ice_session_check_list(const IceSession *session, int n)
712 {
713 	if (n >= ICE_SESSION_MAX_CHECK_LISTS) return NULL;
714 	return session->streams[n];
715 }
716 
ice_session_local_ufrag(const IceSession * session)717 const char * ice_session_local_ufrag(const IceSession *session)
718 {
719 	return session->local_ufrag;
720 }
721 
ice_session_local_pwd(const IceSession * session)722 const char * ice_session_local_pwd(const IceSession *session)
723 {
724 	return session->local_pwd;
725 }
726 
ice_session_remote_ufrag(const IceSession * session)727 const char * ice_session_remote_ufrag(const IceSession *session)
728 {
729 	return session->remote_ufrag;
730 }
731 
ice_session_remote_pwd(const IceSession * session)732 const char * ice_session_remote_pwd(const IceSession *session)
733 {
734 	return session->remote_pwd;
735 }
736 
ice_check_list_compute_pair_priorities(IceCheckList * cl)737 static void ice_check_list_compute_pair_priorities(IceCheckList *cl)
738 {
739 	bctbx_list_for_each2(cl->pairs, (void (*)(void*,void*))ice_compute_pair_priority, &cl->session->role);
740 }
741 
ice_session_compute_pair_priorities(IceSession * session)742 static void ice_session_compute_pair_priorities(IceSession *session)
743 {
744 	int i;
745 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
746 		if (session->streams[i] != NULL)
747 			ice_check_list_compute_pair_priorities(session->streams[i]);
748 	}
749 }
750 
ice_session_state(const IceSession * session)751 IceSessionState ice_session_state(const IceSession *session)
752 {
753 	return session->state;
754 }
755 
ice_session_role(const IceSession * session)756 IceRole ice_session_role(const IceSession *session)
757 {
758 	return session->role;
759 }
760 
ice_session_set_role(IceSession * session,IceRole role)761 void ice_session_set_role(IceSession *session, IceRole role)
762 {
763 	if (session->role != role) {
764 		/* Compute new candidate pair priorities if the role changes. */
765 		session->role = role;
766 		ice_session_compute_pair_priorities(session);
767 	}
768 }
769 
ice_session_set_local_credentials(IceSession * session,const char * ufrag,const char * pwd)770 void ice_session_set_local_credentials(IceSession *session, const char *ufrag, const char *pwd)
771 {
772 	ice_set_credentials(&session->local_ufrag, &session->local_pwd, ufrag, pwd);
773 }
774 
ice_session_remote_credentials_changed(IceSession * session,const char * ufrag,const char * pwd)775 bool_t ice_session_remote_credentials_changed(IceSession *session, const char *ufrag, const char *pwd)
776 {
777 	if ((session->remote_ufrag == NULL) || (session->remote_pwd == NULL)) return TRUE;
778 	if (strlen(ufrag) != strlen(session->remote_ufrag) || (strcmp(ufrag, session->remote_ufrag) != 0)) return TRUE;
779 	if (strlen(pwd) != strlen(session->remote_pwd) || (strcmp(pwd, session->remote_pwd) != 0)) return TRUE;
780 	return FALSE;
781 }
782 
ice_session_set_remote_credentials(IceSession * session,const char * ufrag,const char * pwd)783 void ice_session_set_remote_credentials(IceSession *session, const char *ufrag, const char *pwd)
784 {
785 	ice_set_credentials(&session->remote_ufrag, &session->remote_pwd, ufrag, pwd);
786 }
787 
ice_session_set_max_connectivity_checks(IceSession * session,uint8_t max_connectivity_checks)788 void ice_session_set_max_connectivity_checks(IceSession *session, uint8_t max_connectivity_checks)
789 {
790 	session->max_connectivity_checks = max_connectivity_checks;
791 }
792 
ice_session_set_keepalive_timeout(IceSession * session,uint8_t timeout)793 void ice_session_set_keepalive_timeout(IceSession *session, uint8_t timeout)
794 {
795 	if (timeout < ICE_DEFAULT_KEEPALIVE_TIMEOUT) timeout = ICE_DEFAULT_KEEPALIVE_TIMEOUT;
796 	session->keepalive_timeout = timeout;
797 }
798 
799 
800 /******************************************************************************
801  * SESSION HANDLING                                                           *
802  *****************************************************************************/
803 
ice_session_nb_check_lists(IceSession * session)804 int ice_session_nb_check_lists(IceSession *session)
805 {
806 	int i;
807 	int nb = 0;
808 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
809 		if (session->streams[i] != NULL) nb++;
810 	}
811 	return nb;
812 }
813 
ice_session_has_completed_check_list(const IceSession * session)814 bool_t ice_session_has_completed_check_list(const IceSession *session)
815 {
816 	int i;
817 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
818 		if ((session->streams[i] != NULL) && (ice_check_list_state(session->streams[i]) == ICL_Completed))
819 			return TRUE;
820 	}
821 	return FALSE;
822 }
823 
ice_session_add_check_list(IceSession * session,IceCheckList * cl,unsigned int idx)824 void ice_session_add_check_list(IceSession *session, IceCheckList *cl, unsigned int idx)
825 {
826 	if (idx >= ICE_SESSION_MAX_CHECK_LISTS) {
827 		ms_error("ice_session_add_check_list: Wrong idx parameter");
828 		return;
829 	}
830 	if (session->streams[idx] != NULL) {
831 		ms_error("ice_session_add_check_list: Existing check list at index %u, remove it first", idx);
832 		return;
833 	}
834 	session->streams[idx] = cl;
835 	cl->session = session;
836 	if (cl->state == ICL_Running) {
837 		session->state = IS_Running;
838 	}
839 }
840 
ice_session_remove_check_list(IceSession * session,IceCheckList * cl)841 void ice_session_remove_check_list(IceSession *session, IceCheckList *cl)
842 {
843 	int i;
844 	bool_t keep_session_state = FALSE;
845 
846 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
847 		if ((session->streams[i] != NULL) && (session->streams[i] == cl)) {
848 			ice_check_list_destroy(cl);
849 			session->streams[i] = NULL;
850 			break;
851 		}
852 	}
853 
854 	// If all remaining check lists have completed set the session state to completed
855 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
856 		if ((session->streams[i] != NULL) && (ice_check_list_state(session->streams[i]) != ICL_Completed)) {
857 			keep_session_state = TRUE;
858 		}
859 	}
860 	if (!keep_session_state) {
861 		session->state = IS_Completed;
862 	}
863 }
864 
ice_session_remove_check_list_from_idx(IceSession * session,unsigned int idx)865 void ice_session_remove_check_list_from_idx(IceSession *session, unsigned int idx) {
866 	if (idx >= ICE_SESSION_MAX_CHECK_LISTS) {
867 		ms_error("ice_session_remove_check_list_from_idx: Wrong idx parameter");
868 		return;
869 	}
870 	if (session->streams[idx] != NULL) {
871 		ice_check_list_destroy(session->streams[idx]);
872 		session->streams[idx] = NULL;
873 	}
874 }
875 
ice_find_default_candidate_from_componentID(const IceCandidate * candidate,const uint16_t * componentID)876 static int ice_find_default_candidate_from_componentID(const IceCandidate *candidate, const uint16_t *componentID)
877 {
878 	return !((candidate->is_default == TRUE) && (candidate->componentID == *componentID));
879 }
880 
ice_find_default_remote_candidate_for_componentID(const uint16_t * componentID,IceCheckList * cl)881 static void ice_find_default_remote_candidate_for_componentID(const uint16_t *componentID, IceCheckList *cl)
882 {
883 	bctbx_list_t *elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_find_default_candidate_from_componentID, componentID);
884 	if (elem == NULL) {
885 		cl->mismatch = TRUE;
886 		cl->state = ICL_Failed;
887 	}
888 }
889 
ice_check_list_check_mismatch(IceCheckList * cl)890 static void ice_check_list_check_mismatch(IceCheckList *cl)
891 {
892 	bctbx_list_for_each2(cl->remote_componentIDs, (void (*)(void*,void*))ice_find_default_remote_candidate_for_componentID, cl);
893 }
894 
ice_session_check_mismatch(IceSession * session)895 void ice_session_check_mismatch(IceSession *session)
896 {
897 	int i;
898 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
899 		if (session->streams[i] != NULL)
900 			ice_check_list_check_mismatch(session->streams[i]);
901 	}
902 }
903 
904 
905 /******************************************************************************
906  * CANDIDATES GATHERING                                                       *
907  *****************************************************************************/
908 
ice_check_list_candidates_gathered(const IceCheckList * cl)909 bool_t ice_check_list_candidates_gathered(const IceCheckList *cl)
910 {
911 	return cl->gathering_finished;
912 }
913 
ice_session_candidates_gathered(const IceSession * session)914 bool_t ice_session_candidates_gathered(const IceSession *session)
915 {
916 	int i;
917 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
918 		if ((session->streams[i] != NULL) && (ice_check_list_candidates_gathered(session->streams[i]) != TRUE))
919 			return FALSE;
920 	}
921 	return TRUE;
922 }
923 
ice_check_list_gathering_needed(const IceCheckList * cl)924 static bool_t ice_check_list_gathering_needed(const IceCheckList *cl)
925 {
926 	if (cl->gathering_finished == FALSE)
927 		return TRUE;
928 	return FALSE;
929 }
930 
ice_check_list_add_stun_server_request(IceCheckList * cl,IceStunServerRequest * request)931 static void ice_check_list_add_stun_server_request(IceCheckList *cl, IceStunServerRequest *request) {
932 	cl->stun_server_requests = bctbx_list_append(cl->stun_server_requests, request);
933 }
934 
ice_check_list_gather_candidates(IceCheckList * cl,Session_Index * si)935 static bool_t ice_check_list_gather_candidates(IceCheckList *cl, Session_Index *si)
936 {
937 	IceStunServerRequest *request;
938 	RtpTransport *rtptp=NULL;
939 	MSTimeSpec curtime = ice_current_time();
940 	char source_addr_str[64];
941 	int source_port = 0;
942 
943 	if ((cl->rtp_session != NULL) && (cl->gathering_candidates == FALSE) && (cl->state != ICL_Completed) && (ice_check_list_candidates_gathered(cl) == FALSE)) {
944 		cl->gathering_candidates = TRUE;
945 		cl->gathering_start_time = curtime;
946 		rtp_session_get_transports(cl->rtp_session,&rtptp,NULL);
947 		if (rtptp) {
948 			struct sockaddr *sa = (struct sockaddr *)&cl->rtp_session->rtp.gs.loc_addr;
949 			if (cl->session->turn_enabled) {
950 				/* Define the RTP endpoint that will perform STUN encapsulation/decapsulation for TURN data */
951 				meta_rtp_transport_set_endpoint(rtptp, ms_turn_context_create_endpoint(cl->rtp_turn_context));
952 				ms_turn_context_set_server_addr(cl->rtp_turn_context, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
953 			}
954 			memset(source_addr_str, 0, sizeof(source_addr_str));
955 			bctbx_sockaddr_to_ip_address(sa, cl->rtp_session->rtp.gs.loc_addrlen, source_addr_str, sizeof(source_addr_str), &source_port);
956 			request = ice_stun_server_request_new(cl, cl->rtp_turn_context, rtptp, sa->sa_family, source_addr_str, source_port,
957 				cl->session->turn_enabled ? MS_TURN_METHOD_ALLOCATE : MS_STUN_METHOD_BINDING);
958 			request->gathering = TRUE;
959 			if (si->index == 0) {
960 				IceStunServerRequestTransaction *transaction = NULL;
961 				request->next_transmission_time = ice_add_ms(curtime, ICE_DEFAULT_RTO_DURATION);
962 				if (cl->session->turn_enabled) ms_turn_context_set_state(cl->rtp_turn_context, MS_TURN_CONTEXT_STATE_CREATING_ALLOCATION);
963 				transaction = ice_send_stun_server_request(request, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
964 				ice_stun_server_request_add_transaction(request, transaction);
965 			} else {
966 				request->next_transmission_time = ice_add_ms(curtime, 2 * si->index * ICE_DEFAULT_TA_DURATION);
967 			}
968 			ice_check_list_add_stun_server_request(cl, request);
969 		} else {
970 			ms_error("ice: no rtp socket found for session [%p]",cl->rtp_session);
971 		}
972 		rtptp=NULL;
973 		rtp_session_get_transports(cl->rtp_session,NULL,&rtptp);
974 		if (rtptp) {
975 			struct sockaddr *sa = (struct sockaddr *)&cl->rtp_session->rtcp.gs.loc_addr;
976 			if (cl->session->turn_enabled) {
977 				/* Define the RTP endpoint that will perform STUN encapsulation/decapsulation for TURN data */
978 				meta_rtp_transport_set_endpoint(rtptp, ms_turn_context_create_endpoint(cl->rtcp_turn_context));
979 				ms_turn_context_set_server_addr(cl->rtcp_turn_context, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
980 			}
981 			memset(source_addr_str, 0, sizeof(source_addr_str));
982 			bctbx_sockaddr_to_ip_address(sa, cl->rtp_session->rtcp.gs.loc_addrlen, source_addr_str, sizeof(source_addr_str), &source_port);
983 			request = ice_stun_server_request_new(cl, cl->rtcp_turn_context, rtptp, sa->sa_family, source_addr_str, source_port,
984 				cl->session->turn_enabled ? MS_TURN_METHOD_ALLOCATE : MS_STUN_METHOD_BINDING);
985 			request->gathering = TRUE;
986 			request->next_transmission_time = ice_add_ms(curtime, 2 * si->index * ICE_DEFAULT_TA_DURATION + ICE_DEFAULT_TA_DURATION);
987 			ice_check_list_add_stun_server_request(cl, request);
988 			if (cl->session->turn_enabled) ms_turn_context_set_state(cl->rtcp_turn_context, MS_TURN_CONTEXT_STATE_CREATING_ALLOCATION);
989 		}else {
990 			ms_message("ice: no rtcp socket found for session [%p]",cl->rtp_session);
991 		}
992 		si->index++;
993 	} else {
994 		if (cl->gathering_candidates == FALSE) {
995 			ms_message("ice: candidate gathering skipped for rtp session [%p] with check list [%p] in state [%s]",cl->rtp_session,cl,ice_check_list_state_to_string(cl->state));
996 		}
997 	}
998 
999 	return cl->gathering_candidates;
1000 }
1001 
ice_check_list_deallocate_turn_candidate(IceCheckList * cl,MSTurnContext * turn_context,RtpTransport * rtptp,OrtpStream * stream)1002 static void ice_check_list_deallocate_turn_candidate(IceCheckList *cl, MSTurnContext *turn_context, RtpTransport *rtptp, OrtpStream *stream) {
1003 	IceStunServerRequest *request = NULL;
1004 	IceStunServerRequestTransaction *transaction = NULL;
1005 	char source_addr_str[64];
1006 	int source_port = 0;
1007 
1008 	if ((turn_context != NULL) && (ms_turn_context_get_state(turn_context) >= MS_TURN_CONTEXT_STATE_ALLOCATION_CREATED)) {
1009 		ms_turn_context_set_lifetime(turn_context, 0);
1010 		if (rtptp) {
1011 			struct sockaddr *sa = (struct sockaddr *)&stream->loc_addr;
1012 			memset(source_addr_str, 0, sizeof(source_addr_str));
1013 			bctbx_sockaddr_to_ip_address(sa, stream->loc_addrlen, source_addr_str, sizeof(source_addr_str), &source_port);
1014 			request = ice_stun_server_request_new(cl, turn_context, rtptp, sa->sa_family, source_addr_str, source_port, MS_TURN_METHOD_REFRESH);
1015 			transaction = ice_send_stun_server_request(request, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
1016 			if (transaction != NULL) ice_stun_server_request_transaction_free(transaction);
1017 			ice_stun_server_request_free(request);
1018 			meta_rtp_transport_set_endpoint(rtptp,NULL); /*endpoint is later freed*/
1019 		} else {
1020 			ms_error("ice: no rtp socket found for session [%p]", cl->rtp_session);
1021 		}
1022 	}
1023 }
1024 
ice_check_list_deallocate_rtp_turn_candidate(IceCheckList * cl)1025 static void ice_check_list_deallocate_rtp_turn_candidate(IceCheckList *cl) {
1026 	RtpTransport *rtptp = NULL;
1027 	rtp_session_get_transports(cl->rtp_session, &rtptp, NULL);
1028 	ice_check_list_deallocate_turn_candidate(cl, cl->rtp_turn_context, rtptp, &cl->rtp_session->rtp.gs);
1029 }
1030 
ice_check_list_deallocate_rtcp_turn_candidate(IceCheckList * cl)1031 static void ice_check_list_deallocate_rtcp_turn_candidate(IceCheckList *cl) {
1032 	RtpTransport *rtptp = NULL;
1033 	rtp_session_get_transports(cl->rtp_session, NULL, &rtptp);
1034 	ice_check_list_deallocate_turn_candidate(cl, cl->rtcp_turn_context, rtptp, &cl->rtp_session->rtcp.gs);
1035 }
1036 
ice_check_list_deallocate_turn_candidates(IceCheckList * cl)1037 static void ice_check_list_deallocate_turn_candidates(IceCheckList *cl) {
1038 	ice_check_list_deallocate_rtp_turn_candidate(cl);
1039 	ice_check_list_deallocate_rtcp_turn_candidate(cl);
1040 }
1041 
ice_session_gathering_needed(const IceSession * session)1042 static bool_t ice_session_gathering_needed(const IceSession *session) {
1043 	int i;
1044 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
1045 		if ((session->streams[i] != NULL) && (ice_check_list_gathering_needed(session->streams[i]) == TRUE))
1046 			return TRUE;
1047 	}
1048 	return FALSE;
1049 }
1050 
ice_session_first_check_list(const IceSession * session)1051 static IceCheckList * ice_session_first_check_list(const IceSession *session) {
1052 	int i;
1053 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
1054 		if (session->streams[i] != NULL)
1055 			return session->streams[i];
1056 	}
1057 	return NULL;
1058 }
1059 
ice_session_gather_candidates(IceSession * session,const struct sockaddr * ss,socklen_t ss_len)1060 bool_t ice_session_gather_candidates(IceSession *session, const struct sockaddr* ss, socklen_t ss_len)
1061 {
1062 	Session_Index si;
1063 	OrtpEvent *ev;
1064 	int i;
1065 	bool_t gathering_in_progress = FALSE;
1066 
1067 	memcpy(&session->ss,ss,ss_len);
1068 	session->ss_len = ss_len;
1069 	si.session = session;
1070 	si.index = 0;
1071 	ms_get_cur_time(&session->gathering_start_ts);
1072 	if (ice_session_gathering_needed(session) == TRUE) {
1073 		for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
1074 			if (session->streams[i] != NULL) {
1075 				bool_t cl_gathering_in_progress = ice_check_list_gather_candidates(session->streams[i], &si);
1076 				if (cl_gathering_in_progress == TRUE) gathering_in_progress = TRUE;
1077 			}
1078 		}
1079 	} else {
1080 		/* Notify end of gathering since it has already been done. */
1081 		ev = ortp_event_new(ORTP_EVENT_ICE_GATHERING_FINISHED);
1082 		ortp_event_get_data(ev)->info.ice_processing_successful = TRUE;
1083 		session->gathering_end_ts = session->gathering_start_ts;
1084 		rtp_session_dispatch_event(ice_session_first_check_list(session)->rtp_session, ev);
1085 	}
1086 
1087 	return gathering_in_progress;
1088 }
1089 
ice_session_gathering_duration(IceSession * session)1090 int ice_session_gathering_duration(IceSession *session)
1091 {
1092 	if ((session->gathering_start_ts.tv_sec == -1) || (session->gathering_end_ts.tv_sec == -1)) return -1;
1093 	return (int)(((session->gathering_end_ts.tv_sec - session->gathering_start_ts.tv_sec) * 1000.0)
1094 		+ ((session->gathering_end_ts.tv_nsec - session->gathering_start_ts.tv_nsec) / 1000000.0));
1095 }
1096 
ice_session_enable_forced_relay(IceSession * session,bool_t enable)1097 void ice_session_enable_forced_relay(IceSession *session, bool_t enable) {
1098 	session->forced_relay = enable;
1099 }
1100 
ice_session_enable_short_turn_refresh(IceSession * session,bool_t enable)1101 void ice_session_enable_short_turn_refresh(IceSession *session, bool_t enable) {
1102 	session->short_turn_refresh = enable;
1103 }
1104 
ice_check_list_create_turn_contexts(IceCheckList * cl)1105 static void ice_check_list_create_turn_contexts(IceCheckList *cl) {
1106 	if (!cl->rtp_turn_context){
1107 		cl->rtp_turn_context = ms_turn_context_new(MS_TURN_CONTEXT_TYPE_RTP, cl->rtp_session);
1108 	}
1109 	if (!cl->rtcp_turn_context){
1110 		cl->rtcp_turn_context = ms_turn_context_new(MS_TURN_CONTEXT_TYPE_RTCP, cl->rtp_session);
1111 	}
1112 }
1113 
ice_session_enable_turn(IceSession * session,bool_t enable)1114 void ice_session_enable_turn(IceSession *session, bool_t enable) {
1115 	int i;
1116 	session->turn_enabled = enable;
1117 	if (!enable) return;
1118 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
1119 		if (session->streams[i] != NULL)
1120 			ice_check_list_create_turn_contexts(session->streams[i]);
1121 	}
1122 }
1123 
ice_session_set_stun_auth_requested_cb(IceSession * session,MSStunAuthRequestedCb cb,void * userdata)1124 void ice_session_set_stun_auth_requested_cb(IceSession *session, MSStunAuthRequestedCb cb, void *userdata)
1125 {
1126 	session->stun_auth_requested_cb = cb;
1127 	session->stun_auth_requested_userdata = userdata;
1128 }
1129 
ice_transaction_sum_gathering_round_trip_time(const IceStunServerRequestTransaction * transaction,IceStunRequestRoundTripTime * rtt)1130 static void ice_transaction_sum_gathering_round_trip_time(const IceStunServerRequestTransaction *transaction, IceStunRequestRoundTripTime *rtt)
1131 {
1132 	if ((transaction->response_time.tv_sec != 0) && (transaction->response_time.tv_nsec != 0)) {
1133 		rtt->nb_responses++;
1134 		rtt->sum += ice_compare_time(transaction->response_time, transaction->request_time);
1135 	}
1136 }
1137 
ice_stun_server_check_sum_gathering_round_trip_time(const IceStunServerRequest * request,IceStunRequestRoundTripTime * rtt)1138 static void ice_stun_server_check_sum_gathering_round_trip_time(const IceStunServerRequest *request, IceStunRequestRoundTripTime *rtt)
1139 {
1140 	if (request->gathering == TRUE) {
1141 		bctbx_list_for_each2(request->transactions, (void (*)(void*,void*))ice_transaction_sum_gathering_round_trip_time, rtt);
1142 	}
1143 }
1144 
ice_check_list_sum_gathering_round_trip_times(IceCheckList * cl)1145 static void ice_check_list_sum_gathering_round_trip_times(IceCheckList *cl)
1146 {
1147 	bctbx_list_for_each2(cl->stun_server_requests, (void (*)(void*,void*))ice_stun_server_check_sum_gathering_round_trip_time, &cl->rtt);
1148 }
1149 
ice_session_average_gathering_round_trip_time(IceSession * session)1150 int ice_session_average_gathering_round_trip_time(IceSession *session)
1151 {
1152 	IceStunRequestRoundTripTime rtt;
1153 	int i;
1154 
1155 	if ((session->gathering_start_ts.tv_sec == -1) || (session->gathering_end_ts.tv_sec == -1)) return -1;
1156 	memset(&rtt, 0, sizeof(rtt));
1157 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
1158 		if (session->streams[i] != NULL) {
1159 			rtt.nb_responses += session->streams[i]->rtt.nb_responses;
1160 			rtt.sum += session->streams[i]->rtt.sum;
1161 		}
1162 	}
1163 	if (rtt.nb_responses == 0) return -1;
1164 	return (rtt.sum / rtt.nb_responses);
1165 }
1166 
1167 
1168 /******************************************************************************
1169  * CANDIDATES SELECTION                                                       *
1170  *****************************************************************************/
1171 
ice_unselect_valid_pair(IceValidCandidatePair * valid_pair)1172 static void ice_unselect_valid_pair(IceValidCandidatePair *valid_pair)
1173 {
1174 	valid_pair->selected = FALSE;
1175 }
1176 
ice_check_list_select_candidates(IceCheckList * cl)1177 static void ice_check_list_select_candidates(IceCheckList *cl)
1178 {
1179 	IceValidCandidatePair *valid_pair = NULL;
1180 	uint16_t componentID;
1181 	bctbx_list_t *elem;
1182 
1183 	if (cl->state != ICL_Completed) return;
1184 
1185 	bctbx_list_for_each(cl->valid_list, (void (*)(void*))ice_unselect_valid_pair);
1186 	for (componentID = 1; componentID <= 2; componentID++) {
1187 		elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_nominated_valid_pair_from_componentID, &componentID);
1188 		if (elem == NULL) continue;
1189 		valid_pair = (IceValidCandidatePair *)elem->data;
1190 		valid_pair->selected = TRUE;
1191 	}
1192 }
1193 
ice_session_select_candidates(IceSession * session)1194 void ice_session_select_candidates(IceSession *session)
1195 {
1196 	int i;
1197 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
1198 		if (session->streams[i] != NULL)
1199 			ice_check_list_select_candidates(session->streams[i]);
1200 	}
1201 }
1202 
1203 
1204 /******************************************************************************
1205  * TRANSACTION HANDLING                                                       *
1206  *****************************************************************************/
1207 
ice_create_transaction(IceCheckList * cl,IceCandidatePair * pair,const UInt96 tr_id)1208 static IceTransaction * ice_create_transaction(IceCheckList *cl, IceCandidatePair *pair, const UInt96 tr_id)
1209 {
1210 	IceTransaction *transaction = ms_new0(IceTransaction, 1);
1211 	transaction->pair = pair;
1212 	transaction->transactionID = tr_id;
1213 	cl->transaction_list = bctbx_list_prepend(cl->transaction_list, transaction);
1214 	return transaction;
1215 }
1216 
ice_find_transaction_from_pair(const IceTransaction * transaction,const IceCandidatePair * pair)1217 static int ice_find_transaction_from_pair(const IceTransaction *transaction, const IceCandidatePair *pair)
1218 {
1219 	return (transaction->pair != pair);
1220 }
1221 
ice_find_transaction(const IceCheckList * cl,const IceCandidatePair * pair)1222 static IceTransaction * ice_find_transaction(const IceCheckList *cl, const IceCandidatePair *pair)
1223 {
1224 	bctbx_list_t *elem = bctbx_list_find_custom(cl->transaction_list, (bctbx_compare_func)ice_find_transaction_from_pair, pair);
1225 	if (elem == NULL) return NULL;
1226 	return (IceTransaction *)elem->data;
1227 }
1228 
1229 
1230 /******************************************************************************
1231  * STUN PACKETS HANDLING                                                      *
1232  *****************************************************************************/
1233 
ice_stun_server_request_transaction_new(UInt96 transactionID)1234 static IceStunServerRequestTransaction * ice_stun_server_request_transaction_new(UInt96 transactionID) {
1235 	IceStunServerRequestTransaction *transaction = ms_new0(IceStunServerRequestTransaction, 1);
1236 	transaction->request_time = ice_current_time();
1237 	transaction->transactionID = transactionID;
1238 	return transaction;
1239 }
1240 
ice_stun_server_request_new(IceCheckList * cl,MSTurnContext * turn_context,RtpTransport * rtptp,int family,const char * srcaddr,int srcport,uint16_t stun_method)1241 static IceStunServerRequest * ice_stun_server_request_new(IceCheckList *cl, MSTurnContext *turn_context, RtpTransport *rtptp, int family, const char *srcaddr, int srcport, uint16_t stun_method) {
1242 	IceStunServerRequest *request = (IceStunServerRequest *)ms_new0(IceStunServerRequest, 1);
1243 	request->cl = cl;
1244 	request->turn_context = turn_context;
1245 	request->rtptp = rtptp;
1246 	request->source_ai = bctbx_ip_address_to_addrinfo(family, SOCK_DGRAM, srcaddr, srcport);
1247 	request->stun_method = stun_method;
1248 	return request;
1249 }
1250 
ice_stun_server_request_add_transaction(IceStunServerRequest * request,IceStunServerRequestTransaction * transaction)1251 static void ice_stun_server_request_add_transaction(IceStunServerRequest *request, IceStunServerRequestTransaction *transaction) {
1252 	if (transaction != NULL) {
1253 		request->transactions = bctbx_list_append(request->transactions, transaction);
1254 	}
1255 }
1256 
ice_stun_server_request_transaction_free(IceStunServerRequestTransaction * transaction)1257 static void ice_stun_server_request_transaction_free(IceStunServerRequestTransaction *transaction) {
1258 	ms_free(transaction);
1259 }
1260 
ice_stun_server_request_free(IceStunServerRequest * request)1261 static void ice_stun_server_request_free(IceStunServerRequest *request) {
1262 	bctbx_list_for_each(request->transactions, (void (*)(void*))ice_stun_server_request_transaction_free);
1263 	bctbx_list_free(request->transactions);
1264 	if (request->source_ai != NULL) bctbx_freeaddrinfo(request->source_ai);
1265 	ms_free(request);
1266 }
1267 
ice_send_message_to_socket(RtpTransport * rtptp,char * buf,size_t len,const struct sockaddr * from,socklen_t fromlen,const struct sockaddr * to,socklen_t tolen)1268 static int ice_send_message_to_socket(RtpTransport * rtptp, char* buf, size_t len, const struct sockaddr *from, socklen_t fromlen, const struct sockaddr *to, socklen_t tolen) {
1269 	mblk_t *m = rtp_session_create_packet_raw((const uint8_t *)buf, len);
1270 	int err;
1271 	struct addrinfo *v6ai = NULL;
1272 
1273 	memcpy(&m->net_addr, from, fromlen);
1274 	m->net_addrlen = fromlen;
1275 	if ((rtptp->session->rtp.gs.sockfamily == AF_INET6) && (to->sa_family == AF_INET)) {
1276 
1277 		char to_addr_str[64];
1278 		int to_port = 0;
1279 		memset(to_addr_str, 0, sizeof(to_addr_str));
1280 		bctbx_sockaddr_to_ip_address(to, tolen, to_addr_str, sizeof(to_addr_str), &to_port);
1281 		v6ai = bctbx_ip_address_to_addrinfo(AF_INET6, SOCK_DGRAM, to_addr_str, to_port);
1282 		to = v6ai->ai_addr;
1283 		tolen = (socklen_t)v6ai->ai_addrlen;
1284 	}
1285 	err = meta_rtp_transport_modifier_inject_packet_to_send_to(rtptp, NULL, m, 0, to, tolen);
1286 	freemsg(m);
1287 	if (v6ai) bctbx_freeaddrinfo(v6ai);
1288 	return err;
1289 }
1290 
ice_send_message_to_stun_addr(RtpTransport * rtpt,char * buff,size_t len,MSStunAddress * source,MSStunAddress * dest)1291 static int ice_send_message_to_stun_addr(RtpTransport * rtpt, char* buff, size_t len, MSStunAddress *source, MSStunAddress *dest) {
1292 	struct sockaddr_storage source_addr;
1293 	struct sockaddr_storage dest_addr;
1294 	socklen_t source_addrlen = sizeof(source_addr);
1295 	socklen_t dest_addrlen = sizeof(dest_addr);
1296 	memset(&source_addr, 0, source_addrlen);
1297 	memset(&dest_addr, 0, dest_addrlen);
1298 	ms_stun_address_to_sockaddr(source, (struct sockaddr *)&source_addr, &source_addrlen);
1299 	ms_stun_address_to_sockaddr(dest, (struct sockaddr *)&dest_addr, &dest_addrlen);
1300 	return ice_send_message_to_socket(rtpt, buff, len, (struct sockaddr*)&source_addr, source_addrlen, (struct sockaddr *)&dest_addr, dest_addrlen);
1301 }
1302 
ice_send_stun_request(RtpTransport * rtptp,const struct sockaddr * source,socklen_t sourcelen,const struct sockaddr * server,socklen_t addrlen,MSStunMessage * msg,const char * request_type)1303 static IceStunServerRequestTransaction * ice_send_stun_request(RtpTransport *rtptp, const struct sockaddr *source, socklen_t sourcelen, const struct sockaddr *server, socklen_t addrlen, MSStunMessage *msg, const char *request_type)
1304 {
1305 	IceStunServerRequestTransaction *transaction = NULL;
1306 	char *buf = NULL;
1307 	size_t len;
1308 	char source_addr_str[64];
1309 	char dest_addr_str[64];
1310 	char tr_id_str[25];
1311 	struct sockaddr_storage server_addr;
1312 	socklen_t server_addrlen = sizeof(server_addr);
1313 
1314 	len = ms_stun_message_encode(msg, &buf);
1315 	if (len > 0) {
1316 		transaction = ice_stun_server_request_transaction_new(ms_stun_message_get_tr_id(msg));
1317 		transactionID2string(&transaction->transactionID, tr_id_str);
1318 		memset(&server_addr, 0, server_addrlen);
1319 		bctbx_sockaddr_ipv6_to_ipv4(server, (struct sockaddr *)&server_addr, &server_addrlen);
1320 		memset(source_addr_str, 0, sizeof(source_addr_str));
1321 		memset(dest_addr_str, 0, sizeof(dest_addr_str));
1322 		bctbx_sockaddr_to_printable_ip_address((struct sockaddr *)source, sourcelen, source_addr_str, sizeof(source_addr_str));
1323 		bctbx_sockaddr_to_printable_ip_address((struct sockaddr *)&server_addr, server_addrlen, dest_addr_str, sizeof(dest_addr_str));
1324 		ms_message("ice: Send %s: %s --> %s [%s]", request_type, source_addr_str, dest_addr_str, tr_id_str);
1325 		ice_send_message_to_socket(rtptp, buf, len, source, sourcelen, (struct sockaddr *)&server_addr, server_addrlen);
1326 	} else {
1327 		ms_error("ice: encoding %s [%s] failed", request_type, tr_id_str);
1328 	}
1329 	if (buf != NULL) ms_free(buf);
1330 	return transaction;
1331 }
1332 
ice_send_stun_server_binding_request(IceStunServerRequest * request,const struct sockaddr * server,socklen_t addrlen)1333 static IceStunServerRequestTransaction * ice_send_stun_server_binding_request(IceStunServerRequest *request, const struct sockaddr *server, socklen_t addrlen)
1334 {
1335 	IceStunServerRequestTransaction *transaction = NULL;
1336 	MSStunMessage *msg = ms_stun_binding_request_create();
1337 	transaction = ice_send_stun_request(request->rtptp, request->source_ai->ai_addr, (socklen_t)request->source_ai->ai_addrlen, server, addrlen, msg, "STUN binding request");
1338 	ms_stun_message_destroy(msg);
1339 	return transaction;
1340 }
1341 
ice_parse_stun_server_response(const MSStunMessage * msg,MSStunAddress * srflx_address,MSStunAddress * relay_address)1342 static int ice_parse_stun_server_response(const MSStunMessage *msg, MSStunAddress *srflx_address, MSStunAddress *relay_address)
1343 {
1344 	const MSStunAddress *stunaddr = ms_stun_message_get_xor_mapped_address(msg);
1345 	if (stunaddr == NULL) stunaddr = ms_stun_message_get_mapped_address(msg);
1346 	if (stunaddr == NULL) return -1;
1347 	*srflx_address = *stunaddr;
1348 	stunaddr = ms_stun_message_get_xor_relayed_address(msg);
1349 	if (stunaddr != NULL) *relay_address = *stunaddr;
1350 	return 0;
1351 }
1352 
stun_message_fill_authentication_from_turn_context(MSStunMessage * msg,const MSTurnContext * turn_context)1353 static void stun_message_fill_authentication_from_turn_context(MSStunMessage *msg, const MSTurnContext *turn_context) {
1354 	ms_stun_message_set_realm(msg, ms_turn_context_get_realm(turn_context));
1355 	ms_stun_message_set_nonce(msg, ms_turn_context_get_nonce(turn_context));
1356 	ms_stun_message_set_username(msg, ms_turn_context_get_username(turn_context));
1357 	ms_stun_message_set_password(msg, ms_turn_context_get_password(turn_context));
1358 	ms_stun_message_set_ha1(msg, ms_turn_context_get_ha1(turn_context));
1359 	if (ms_turn_context_get_password(turn_context) || ms_turn_context_get_ha1(turn_context))
1360 		ms_stun_message_enable_message_integrity(msg, TRUE);
1361 }
1362 
ice_send_turn_server_allocate_request(IceStunServerRequest * request,const struct sockaddr * server,socklen_t addrlen)1363 static IceStunServerRequestTransaction * ice_send_turn_server_allocate_request(IceStunServerRequest *request, const struct sockaddr *server, socklen_t addrlen) {
1364 	IceStunServerRequestTransaction *transaction = NULL;
1365 	MSStunMessage *msg = ms_turn_allocate_request_create();
1366 	stun_message_fill_authentication_from_turn_context(msg, request->turn_context);
1367 	request->stun_method = ms_stun_message_get_method(msg);
1368 	if (request->requested_address_family != 0) ms_stun_message_set_requested_address_family(msg, request->requested_address_family);
1369 	transaction = ice_send_stun_request(request->rtptp, request->source_ai->ai_addr, (socklen_t)request->source_ai->ai_addrlen, server, addrlen, msg, "TURN allocate request");
1370 	ms_stun_message_destroy(msg);
1371 	return transaction;
1372 }
1373 
ice_send_turn_server_refresh_request(IceStunServerRequest * request,const struct sockaddr * server,socklen_t addrlen)1374 static IceStunServerRequestTransaction * ice_send_turn_server_refresh_request(IceStunServerRequest *request, const struct sockaddr *server, socklen_t addrlen) {
1375 	IceStunServerRequestTransaction *transaction = NULL;
1376 	if (ms_turn_context_get_state(request->turn_context) != MS_TURN_CONTEXT_STATE_IDLE) {
1377 		MSStunMessage *msg = ms_turn_refresh_request_create(ms_turn_context_get_lifetime(request->turn_context));
1378 		stun_message_fill_authentication_from_turn_context(msg, request->turn_context);
1379 		request->stun_method = ms_stun_message_get_method(msg);
1380 		transaction = ice_send_stun_request(request->rtptp, request->source_ai->ai_addr, (socklen_t)request->source_ai->ai_addrlen, server, addrlen, msg, "TURN refresh request");
1381 		ms_stun_message_destroy(msg);
1382 	}
1383 	return transaction;
1384 }
1385 
ice_send_turn_server_create_permission_request(IceStunServerRequest * request,const struct sockaddr * server,socklen_t addrlen)1386 static IceStunServerRequestTransaction * ice_send_turn_server_create_permission_request(IceStunServerRequest *request, const struct sockaddr *server, socklen_t addrlen) {
1387 	IceStunServerRequestTransaction *transaction = NULL;
1388 	MSStunMessage *msg = ms_turn_create_permission_request_create(request->peer_address);
1389 	stun_message_fill_authentication_from_turn_context(msg, request->turn_context);
1390 	request->stun_method = ms_stun_message_get_method(msg);
1391 	transaction = ice_send_stun_request(request->rtptp, request->source_ai->ai_addr, (socklen_t)request->source_ai->ai_addrlen, server, addrlen, msg, "TURN create permission request");
1392 	ms_stun_message_destroy(msg);
1393 	return transaction;
1394 }
1395 
ice_send_turn_server_channel_bind_request(IceStunServerRequest * request,const struct sockaddr * server,socklen_t addrlen)1396 static IceStunServerRequestTransaction * ice_send_turn_server_channel_bind_request(IceStunServerRequest *request, const struct sockaddr *server, socklen_t addrlen) {
1397 	IceStunServerRequestTransaction *transaction = NULL;
1398 	MSStunMessage *msg = ms_turn_channel_bind_request_create(request->peer_address, request->channel_number);
1399 	stun_message_fill_authentication_from_turn_context(msg, request->turn_context);
1400 	request->stun_method = ms_stun_message_get_method(msg);
1401 	transaction = ice_send_stun_request(request->rtptp, request->source_ai->ai_addr, (socklen_t)request->source_ai->ai_addrlen, server, addrlen, msg, "TURN channel bind request");
1402 	ms_stun_message_destroy(msg);
1403 	return transaction;
1404 }
1405 
ice_send_stun_server_request(IceStunServerRequest * request,const struct sockaddr * server,socklen_t addrlen)1406 static IceStunServerRequestTransaction * ice_send_stun_server_request(IceStunServerRequest *request, const struct sockaddr *server, socklen_t addrlen) {
1407 	IceStunServerRequestTransaction *transaction = NULL;
1408 	switch (request->stun_method) {
1409 		case MS_STUN_METHOD_BINDING:
1410 			transaction = ice_send_stun_server_binding_request(request, server, addrlen);
1411 			break;
1412 		case MS_TURN_METHOD_ALLOCATE:
1413 			transaction = ice_send_turn_server_allocate_request(request, server, addrlen);
1414 			break;
1415 		case MS_TURN_METHOD_CREATE_PERMISSION:
1416 			transaction = ice_send_turn_server_create_permission_request(request, server, addrlen);
1417 			break;
1418 		case MS_TURN_METHOD_REFRESH:
1419 			transaction = ice_send_turn_server_refresh_request(request, server, addrlen);
1420 			break;
1421 		case MS_TURN_METHOD_CHANNEL_BIND:
1422 			transaction = ice_send_turn_server_channel_bind_request(request, server, addrlen);
1423 			break;
1424 		default:
1425 			break;
1426 	}
1427 	return transaction;
1428 }
1429 
1430 /* Send a STUN binding request for ICE connectivity checks according to 7.1.2. */
ice_send_binding_request(IceCheckList * cl,IceCandidatePair * pair,const RtpSession * rtp_session)1431 static void ice_send_binding_request(IceCheckList *cl, IceCandidatePair *pair, const RtpSession *rtp_session)
1432 {
1433 	MSStunMessage *msg;
1434 	MSStunAddress source;
1435 	MSStunAddress dest;
1436 	char *username;
1437 	IceTransaction *transaction;
1438 	char *buf = NULL;
1439 	size_t len;
1440 	RtpTransport *rtptp;
1441 	char local_addr_str[64];
1442 	char remote_addr_str[64];
1443 	char tr_id_str[25];
1444 
1445 	transaction = ice_find_transaction(cl, pair);
1446 
1447 	if (pair->state == ICP_InProgress) {
1448 		if (transaction == NULL) {
1449 			ms_error("ice: No transaction found for InProgress pair");
1450 			return;
1451 		}
1452 		if (pair->wait_transaction_timeout == TRUE) {
1453 			/* Special case where a binding response triggers a binding request for an InProgress pair. */
1454 			/* In this case we wait for the transmission timeout before creating a new binding request for the pair. */
1455 			pair->wait_transaction_timeout = FALSE;
1456 			if (pair->use_candidate == FALSE) {
1457 				ice_pair_set_state(pair, ICP_Waiting);
1458 				ice_check_list_queue_triggered_check(cl, pair);
1459 			}
1460 			return;
1461 		}
1462 		/* This is a retransmission: update the number of retransmissions, the retransmission timer value, and the transmission time. */
1463 		pair->retransmissions++;
1464 		if (pair->retransmissions > ICE_MAX_RETRANSMISSIONS) {
1465 			/* Too much retransmissions, stop sending connectivity checks for this pair. */
1466 			ice_pair_set_state(pair, ICP_Failed);
1467 			return;
1468 		}
1469 		pair->rto = pair->rto << 1;
1470 	}
1471 	pair->transmission_time = ice_current_time();
1472 
1473 	if (pair->local->componentID == 1) {
1474 		rtp_session_get_transports(rtp_session,&rtptp,NULL);
1475 	} else if (pair->local->componentID == 2) {
1476 		rtp_session_get_transports(rtp_session,NULL,&rtptp);
1477 	} else return;
1478 
1479 	source = ms_ip_address_to_stun_address(pair->local->taddr.family, SOCK_DGRAM, pair->local->taddr.ip, pair->local->taddr.port);
1480 	dest = ms_ip_address_to_stun_address(pair->remote->taddr.family, SOCK_DGRAM, pair->remote->taddr.ip, pair->remote->taddr.port);
1481 	msg = ms_stun_binding_request_create();
1482 	username = ms_strdup_printf("%s:%s", ice_check_list_remote_ufrag(cl), ice_check_list_local_ufrag(cl));
1483 	ms_stun_message_set_username(msg, username);
1484 	ms_free(username);
1485 	ms_stun_message_set_password(msg, ice_check_list_remote_pwd(cl));
1486 	ms_stun_message_enable_message_integrity(msg, TRUE);
1487 	ms_stun_message_enable_fingerprint(msg, TRUE);
1488 
1489 	/* Set the PRIORITY attribute as defined in 7.1.2.1. */
1490 	ms_stun_message_set_priority(msg, (pair->local->priority & 0x00ffffff) | (type_preference_values[ICT_PeerReflexiveCandidate] << 24));
1491 
1492 	/* Include the USE-CANDIDATE attribute if the pair is nominated and the agent has the controlling role, as defined in 7.1.2.1. */
1493 	if ((cl->session->role == IR_Controlling) && (pair->use_candidate == TRUE)) {
1494 		ms_stun_message_enable_use_candidate(msg, TRUE);
1495 	}
1496 
1497 	/* Include the ICE-CONTROLLING or ICE-CONTROLLED attribute depending on the role of the agent, as defined in 7.1.2.2. */
1498 	switch (cl->session->role) {
1499 		case IR_Controlling:
1500 			ms_stun_message_set_ice_controlling(msg, cl->session->tie_breaker);
1501 			break;
1502 		case IR_Controlled:
1503 			ms_stun_message_set_ice_controlled(msg, cl->session->tie_breaker);
1504 			break;
1505 	}
1506 
1507 	/* Keep the same transaction ID for retransmission. */
1508 	if (pair->state == ICP_InProgress) {
1509 		ms_stun_message_set_tr_id(msg, transaction->transactionID);
1510 	} else {
1511 		transaction = ice_create_transaction(cl, pair, ms_stun_message_get_tr_id(msg));
1512 	}
1513 
1514 	/* For backward compatibility */
1515 	ms_stun_message_enable_dummy_message_integrity(msg, pair->use_dummy_hmac);
1516 
1517 	len = ms_stun_message_encode(msg, &buf);
1518 	if (len > 0) {
1519 		memset(local_addr_str, 0, sizeof(local_addr_str));
1520 		memset(remote_addr_str, 0, sizeof(remote_addr_str));
1521 		transactionID2string(&transaction->transactionID, tr_id_str);
1522 		ice_transport_address_to_printable_ip_address(&pair->local->taddr, local_addr_str, sizeof(local_addr_str));
1523 		ice_transport_address_to_printable_ip_address(&pair->remote->taddr, remote_addr_str, sizeof(remote_addr_str));
1524 		if (pair->state == ICP_InProgress) {
1525 			ms_message("ice: Retransmit (%d) binding request for pair %p: %s:%s --> %s:%s [%s]", pair->retransmissions, pair,
1526 				local_addr_str, candidate_type_values[pair->local->type], remote_addr_str, candidate_type_values[pair->remote->type], tr_id_str);
1527 		} else {
1528 			ms_message("ice: Send binding request for %s pair %p: %s:%s --> %s:%s [%s]", candidate_pair_state_values[pair->state], pair,
1529 				local_addr_str, candidate_type_values[pair->local->type], remote_addr_str, candidate_type_values[pair->remote->type], tr_id_str);
1530 		}
1531 
1532 		if ((cl->session->forced_relay == TRUE) && (pair->remote->type != ICT_RelayedCandidate) && (pair->local->type != ICT_RelayedCandidate)) {
1533 			ms_message("ice: Forced relay, did not send binding request for %s pair %p: %s:%s --> %s:%s [%s]", candidate_pair_state_values[pair->state], pair,
1534 				local_addr_str, candidate_type_values[pair->local->type], remote_addr_str, candidate_type_values[pair->remote->type], tr_id_str);
1535 		} else {
1536 			ice_send_message_to_stun_addr(rtptp, buf, len, &source, &dest);
1537 		}
1538 
1539 		if (pair->state != ICP_InProgress) {
1540 			/* First transmission of the request, initialize the retransmission timer. */
1541 			pair->rto = ICE_DEFAULT_RTO_DURATION;
1542 			pair->retransmissions = 0;
1543 			/* Save the role of the agent. */
1544 			pair->role = cl->session->role;
1545 			/* Change the state of the pair. */
1546 			ice_pair_set_state(pair, ICP_InProgress);
1547 		}
1548 	}
1549 	if (buf != NULL) ms_free(buf);
1550 	ms_stun_message_destroy(msg);
1551 }
1552 
ice_get_componentID_from_rtp_session(const OrtpEventData * evt_data)1553 static int ice_get_componentID_from_rtp_session(const OrtpEventData *evt_data)
1554 {
1555 	if (evt_data->info.socket_type == OrtpRTPSocket) {
1556 		return 1;
1557 	} else if (evt_data->info.socket_type == OrtpRTCPSocket) {
1558 		return 2;
1559 	}
1560 	return -1;
1561 }
1562 
1563 
ice_get_transport_from_rtp_session(const RtpSession * rtp_session,const OrtpEventData * evt_data,RtpTransport ** rtptp)1564 static int ice_get_transport_from_rtp_session(const RtpSession *rtp_session, const OrtpEventData *evt_data, RtpTransport **rtptp) {
1565 	if (evt_data->info.socket_type == OrtpRTPSocket) {
1566 		rtp_session_get_transports(rtp_session, rtptp, NULL);
1567 		return 0;
1568 	} else if (evt_data->info.socket_type == OrtpRTCPSocket) {
1569 		rtp_session_get_transports(rtp_session, NULL,rtptp);
1570 		return 0;
1571 	}
1572 	return -1;
1573 }
1574 
ice_get_transport_from_rtp_session_and_componentID(const RtpSession * rtp_session,int componentID,RtpTransport ** rtptp)1575 static int ice_get_transport_from_rtp_session_and_componentID(const RtpSession *rtp_session, int componentID, RtpTransport **rtptp) {
1576 	if (componentID == 1) {
1577 		rtp_session_get_transports(rtp_session, rtptp, NULL);
1578 		return 0;
1579 	} else if (componentID == 2) {
1580 		rtp_session_get_transports(rtp_session, NULL,rtptp);
1581 		return 0;
1582 	} else return -1;
1583 }
1584 
ice_get_ortp_stream_from_rtp_session_and_componentID(const RtpSession * rtp_session,int componentID,const OrtpStream ** stream)1585 static int ice_get_ortp_stream_from_rtp_session_and_componentID(const RtpSession *rtp_session, int componentID, const OrtpStream **stream) {
1586 	if (componentID == 1) {
1587 		*stream = &rtp_session->rtp.gs;
1588 		return 0;
1589 	} else if (componentID == 2) {
1590 		*stream = &rtp_session->rtcp.gs;
1591 		return 0;
1592 	} else return -1;
1593 }
1594 
ice_get_turn_context_from_check_list(const IceCheckList * cl,const OrtpEventData * evt_data)1595 static MSTurnContext * ice_get_turn_context_from_check_list(const IceCheckList *cl, const OrtpEventData *evt_data) {
1596 	if (evt_data->info.socket_type == OrtpRTPSocket) {
1597 		return cl->rtp_turn_context;
1598 	} else if (evt_data->info.socket_type == OrtpRTCPSocket) {
1599 		return cl->rtcp_turn_context;
1600 	} else return NULL;
1601 }
1602 
ice_get_turn_context_from_check_list_componentID(const IceCheckList * cl,uint16_t componentID)1603 static MSTurnContext * ice_get_turn_context_from_check_list_componentID(const IceCheckList *cl, uint16_t componentID) {
1604 	if (componentID == 1) {
1605 		return cl->rtp_turn_context;
1606 	} else if (componentID == 2) {
1607 		return cl->rtcp_turn_context;
1608 	} else return NULL;
1609 }
1610 
ice_send_binding_response(IceCheckList * cl,const RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * dest)1611 static void ice_send_binding_response(IceCheckList *cl, const RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *dest)
1612 {
1613 	MSStunMessage *response;
1614 	char *buf = NULL;
1615 	char *username;
1616 	size_t len;
1617 	RtpTransport *rtptp = NULL;
1618 	struct sockaddr_storage dest_addr;
1619 	socklen_t dest_addrlen = sizeof(dest_addr);
1620 	struct sockaddr_storage source_addr;
1621 	socklen_t source_addrlen = sizeof(source_addr);
1622 	char dest_addr_str[256];
1623 	char source_addr_str[256];
1624 	char tr_id_str[25];
1625 	UInt96 tr_id;
1626 
1627 	ice_get_transport_from_rtp_session(rtp_session, evt_data, &rtptp);
1628 	if (!rtptp) return;
1629 
1630 	memset(&dest_addr, 0, dest_addrlen);
1631 	memset(&source_addr, 0, source_addrlen);
1632 
1633 	/* Create the binding response, copying the transaction ID from the request. */
1634 	tr_id = ms_stun_message_get_tr_id(msg);
1635 	response = ms_stun_binding_success_response_create();
1636 	ms_stun_message_set_tr_id(response, tr_id);
1637 	ms_stun_message_enable_message_integrity(response, TRUE);
1638 	ms_stun_message_enable_fingerprint(response, TRUE);
1639 	/* For backward compatibility */
1640 	ms_stun_message_enable_dummy_message_integrity(response, ms_stun_message_dummy_message_integrity_enabled(msg));
1641 
1642 	/* Add username for message integrity */
1643 	username = ms_strdup_printf("%s:%s", ice_check_list_local_ufrag(cl), ice_check_list_remote_ufrag(cl));
1644 	ms_stun_message_set_username(response, username);
1645 	ms_free(username);
1646 	if (ms_stun_message_dummy_message_integrity_enabled(msg) && !cl->session->check_message_integrity) {
1647 		/* Legacy case, include username for backward compatibility */
1648 	} else {
1649 		ms_stun_message_include_username_attribute(response, FALSE);
1650 	}
1651 
1652 	/* Add password for message integrity */
1653 	ms_stun_message_set_password(response, ice_check_list_local_pwd(cl));
1654 
1655 	/* Add the mapped address to the response. */
1656 	ms_stun_message_set_xor_mapped_address(response, *dest);
1657 
1658 	len = ms_stun_message_encode(response, &buf);
1659 	if (len > 0) {
1660 		memset(dest_addr_str, 0, sizeof(dest_addr_str));
1661 		memset(source_addr_str, 0, sizeof(source_addr_str));
1662 		transactionID2string(&tr_id, tr_id_str);
1663 		ms_stun_address_to_sockaddr(dest, (struct sockaddr*)&dest_addr, &dest_addrlen);
1664 		bctbx_sockaddr_to_printable_ip_address((struct sockaddr *)&dest_addr, dest_addrlen, dest_addr_str, sizeof(dest_addr_str));
1665 		ortp_recvaddr_to_sockaddr(&evt_data->packet->recv_addr, (struct sockaddr *)&source_addr, &source_addrlen);
1666 		bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&source_addr, (struct sockaddr *)&source_addr, &source_addrlen);
1667 		bctbx_sockaddr_to_printable_ip_address((struct sockaddr *)&source_addr, source_addrlen, source_addr_str, sizeof(source_addr_str));
1668 		ms_message("ice: Send binding response: %s --> %s [%s]", source_addr_str, dest_addr_str, tr_id_str);
1669 		ice_send_message_to_socket(rtptp, buf, len, (struct sockaddr *)&source_addr, source_addrlen, (struct sockaddr *)&dest_addr, dest_addrlen);
1670 	}
1671 	if (buf != NULL) ms_free(buf);
1672 	ms_stun_message_destroy(response);
1673 }
1674 
ice_send_error_response(const RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * dest,uint16_t error_num,const char * error_msg)1675 static void ice_send_error_response(const RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *dest, uint16_t error_num, const char *error_msg)
1676 {
1677 	MSStunMessage *response;
1678 	char *buf = NULL;
1679 	size_t len;
1680 	RtpTransport* rtptp;
1681 	struct sockaddr_storage dest_addr;
1682 	socklen_t dest_addrlen = sizeof(dest_addr);
1683 	struct sockaddr_storage source_addr;
1684 	socklen_t source_addrlen = sizeof(source_addr);
1685 	char dest_addr_str[256];
1686 	char source_addr_str[256];
1687 	char tr_id_str[25];
1688 	UInt96 tr_id;
1689 
1690 	memset(&dest_addr, 0, dest_addrlen);
1691 	memset(&source_addr, 0, source_addrlen);
1692 	ice_get_transport_from_rtp_session(rtp_session, evt_data, &rtptp);
1693 	if (!rtptp) return;
1694 
1695 	/* Create the error response, copying the transaction ID from the request. */
1696 	tr_id = ms_stun_message_get_tr_id(msg);
1697 	response = ms_stun_binding_error_response_create();
1698 	ms_stun_message_enable_fingerprint(response, TRUE);
1699 	ms_stun_message_set_error_code(response, error_num, error_msg);
1700 
1701 	len = ms_stun_message_encode(response, &buf);
1702 	if (len > 0) {
1703 		memset(dest_addr_str, 0, sizeof(dest_addr_str));
1704 		memset(source_addr_str, 0, sizeof(source_addr_str));
1705 		transactionID2string(&tr_id, tr_id_str);
1706 		ms_stun_address_to_sockaddr(dest, (struct sockaddr *)&dest_addr, &dest_addrlen);
1707 		bctbx_sockaddr_to_printable_ip_address((struct sockaddr *)&dest_addr, dest_addrlen, dest_addr_str, sizeof(dest_addr_str));
1708 		ortp_recvaddr_to_sockaddr(&evt_data->packet->recv_addr, (struct sockaddr *)&source_addr, &source_addrlen);
1709 		bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&source_addr, (struct sockaddr *)&source_addr, &source_addrlen);
1710 		bctbx_sockaddr_to_printable_ip_address((struct sockaddr *)&source_addr, source_addrlen, source_addr_str, sizeof(source_addr_str));
1711 		ms_message("ice: Send error response: %s --> %s [%s]", source_addr_str, dest_addr_str, tr_id_str);
1712 		ice_send_message_to_socket(rtptp, buf, len, (struct sockaddr *)&source_addr, source_addrlen, (struct sockaddr *)&dest_addr, dest_addrlen);
1713 	}
1714 	if (buf != NULL) ms_free(buf);
1715 	ms_free(response);
1716 }
1717 
ice_send_indication(const IceCandidatePair * pair,const RtpSession * rtp_session)1718 static void ice_send_indication(const IceCandidatePair *pair, const RtpSession *rtp_session)
1719 {
1720 	MSStunMessage *indication;
1721 	MSStunAddress source;
1722 	MSStunAddress dest;
1723 	char *buf = NULL;
1724 	size_t len;
1725 	RtpTransport *rtptp;
1726 	char local_addr_str[64];
1727 	char remote_addr_str[64];
1728 
1729 	if (pair->local->componentID == 1) {
1730 		rtp_session_get_transports(rtp_session,&rtptp,NULL);
1731 	} else if (pair->local->componentID == 2) {
1732 		rtp_session_get_transports(rtp_session,NULL,&rtptp);
1733 	} else return;
1734 
1735 	source = ms_ip_address_to_stun_address(pair->local->taddr.family, SOCK_DGRAM, pair->local->taddr.ip, pair->local->taddr.port);
1736 	dest = ms_ip_address_to_stun_address(pair->remote->taddr.family, SOCK_DGRAM, pair->remote->taddr.ip, pair->remote->taddr.port);
1737 	indication = ms_stun_binding_indication_create();
1738 	ms_stun_message_enable_fingerprint(indication, TRUE);
1739 	/* For backward compatibility */
1740 	ms_stun_message_enable_dummy_message_integrity(indication, pair->use_dummy_hmac);
1741 
1742 	len = ms_stun_message_encode(indication, &buf);
1743 	if (len > 0) {
1744 		memset(local_addr_str, 0, sizeof(local_addr_str));
1745 		memset(remote_addr_str, 0, sizeof(remote_addr_str));
1746 		ice_transport_address_to_printable_ip_address(&pair->local->taddr, local_addr_str, sizeof(local_addr_str));
1747 		ice_transport_address_to_printable_ip_address(&pair->remote->taddr, remote_addr_str, sizeof(remote_addr_str));
1748 		ms_message("ice: Send indication for pair %p: %s:%s --> %s:%s", pair,
1749 			local_addr_str, candidate_type_values[pair->local->type], remote_addr_str, candidate_type_values[pair->remote->type]);
1750 		ice_send_message_to_stun_addr(rtptp, buf, len, &source, &dest);
1751 	}
1752 	if (buf != NULL) ms_free(buf);
1753 	ms_free(indication);
1754 }
1755 
ice_send_keepalive_packet_for_componentID(const uint16_t * componentID,const CheckList_RtpSession * cr)1756 static void ice_send_keepalive_packet_for_componentID(const uint16_t *componentID, const CheckList_RtpSession *cr)
1757 {
1758 	bctbx_list_t *elem = bctbx_list_find_custom(cr->cl->valid_list, (bctbx_compare_func)ice_find_selected_valid_pair_from_componentID, componentID);
1759 	if (elem != NULL) {
1760 		IceValidCandidatePair *valid_pair = (IceValidCandidatePair *)elem->data;
1761 		ice_send_indication(valid_pair->valid, cr->rtp_session);
1762 	}
1763 }
1764 
ice_send_keepalive_packets(IceCheckList * cl,const RtpSession * rtp_session)1765 static void ice_send_keepalive_packets(IceCheckList *cl, const RtpSession *rtp_session)
1766 {
1767 	CheckList_RtpSession cr;
1768 	cr.cl = cl;
1769 	cr.rtp_session = rtp_session;
1770 	bctbx_list_for_each2(cl->local_componentIDs, (void (*)(void*,void*))ice_send_keepalive_packet_for_componentID, &cr);
1771 }
1772 
ice_find_candidate_from_transport_address(const IceCandidate * candidate,const IceTransportAddress * taddr)1773 static int ice_find_candidate_from_transport_address(const IceCandidate *candidate, const IceTransportAddress *taddr)
1774 {
1775 	return ice_compare_transport_addresses(&candidate->taddr, taddr);
1776 }
1777 
ice_find_candidate_from_transport_address_and_componentID(const IceCandidate * candidate,const TransportAddress_ComponentID * taci)1778 static int ice_find_candidate_from_transport_address_and_componentID(const IceCandidate *candidate, const TransportAddress_ComponentID *taci) {
1779 	return !((candidate->componentID == taci->componentID) && (ice_compare_transport_addresses(&candidate->taddr, taci->ta) == 0));
1780 }
1781 
ice_find_candidate_from_ip_address(const IceCandidate * candidate,const char * ipaddr)1782 static int ice_find_candidate_from_ip_address(const IceCandidate *candidate, const char *ipaddr)
1783 {
1784 	return strcmp(candidate->taddr.ip, ipaddr);
1785 }
1786 
1787 /* Check that the mandatory attributes of a connectivity check binding request are present. */
ice_check_received_binding_request_attributes(const RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)1788 static int ice_check_received_binding_request_attributes(const RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr)
1789 {
1790 	if (!ms_stun_message_message_integrity_enabled(msg)) {
1791 		ms_warning("ice: Received binding request missing MESSAGE-INTEGRITY attribute");
1792 		ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_STUN_ERROR_CODE_BAD_REQUEST, "Missing MESSAGE-INTEGRITY attribute");
1793 		return -1;
1794 	}
1795 	if (ms_stun_message_get_username(msg) == NULL) {
1796 		ms_warning("ice: Received binding request missing USERNAME attribute");
1797 		ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_STUN_ERROR_CODE_BAD_REQUEST, "Missing USERNAME attribute");
1798 		return -1;
1799 	}
1800 	if (!ms_stun_message_fingerprint_enabled(msg)) {
1801 		ms_warning("ice: Received binding request missing FINGERPRINT attribute");
1802 		ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_STUN_ERROR_CODE_BAD_REQUEST, "Missing FINGERPRINT attribute");
1803 		return -1;
1804 	}
1805 	if (!ms_stun_message_has_priority(msg)) {
1806 		ms_warning("ice: Received binding request missing PRIORITY attribute");
1807 		ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_STUN_ERROR_CODE_BAD_REQUEST, "Missing PRIORITY attribute");
1808 		return -1;
1809 	}
1810 	if (!ms_stun_message_has_ice_controlling(msg) && !ms_stun_message_has_ice_controlled(msg)) {
1811 		ms_warning("ice: Received binding request missing ICE-CONTROLLING or ICE-CONTROLLED attribute");
1812 		ice_send_error_response(rtp_session, evt_data ,msg, remote_addr, MS_STUN_ERROR_CODE_BAD_REQUEST, "Missing ICE-CONTROLLING or ICE-CONTROLLED attribute");
1813 		return -1;
1814 	}
1815 	return 0;
1816 }
1817 
ice_check_received_binding_request_integrity(const IceCheckList * cl,const RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)1818 static int ice_check_received_binding_request_integrity(const IceCheckList *cl, const RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr)
1819 {
1820 	char *hmac;
1821 	mblk_t *mp = evt_data->packet;
1822 	int ret = 0;
1823 
1824 	/* Check the message integrity: first remove length of fingerprint... */
1825 	char *lenpos = (char *)mp->b_rptr + sizeof(uint16_t);
1826 	uint16_t newlen = htons(ms_stun_message_get_length(msg) - 8);
1827 
1828 	memcpy(lenpos, &newlen, sizeof(uint16_t));
1829 	hmac = ms_stun_calculate_integrity_short_term((char *)mp->b_rptr, (size_t)(mp->b_wptr - mp->b_rptr - 24 - 8), ice_check_list_local_pwd(cl));
1830 	/* ... and then restore the length with fingerprint. */
1831 	newlen = htons(ms_stun_message_get_length(msg));
1832 	memcpy(lenpos, &newlen, sizeof(uint16_t));
1833 	if (strcmp(ms_stun_message_get_message_integrity(msg), hmac) != 0) {
1834 		ms_error("ice: Wrong MESSAGE-INTEGRITY in received binding request");
1835 		if (!cl->session->check_message_integrity && ms_stun_message_dummy_message_integrity_enabled(msg)) {
1836 			ms_message("ice: skipping message integrity check for cl [%p]",cl);
1837 		} else {
1838 			ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_STUN_ERROR_CODE_UNAUTHORIZED, "Wrong MESSAGE-INTEGRITY attribute");
1839 			ret = -1;
1840 		}
1841 	}
1842 	ms_free(hmac);
1843 	return ret;
1844 }
1845 
ice_check_received_binding_request_username(const IceCheckList * cl,const RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)1846 static int ice_check_received_binding_request_username(const IceCheckList *cl, const RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr)
1847 {
1848 	const char *username = ms_stun_message_get_username(msg);
1849 	char *colon = strchr(username, ':');
1850 	if ((colon == NULL) || (strncmp(username, ice_check_list_local_ufrag(cl), colon - username) != 0)) {
1851 		ms_error("ice: Wrong USERNAME attribute (colon=%p)",colon);
1852 		ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_STUN_ERROR_CODE_UNAUTHORIZED, "Wrong USERNAME attribute");
1853 		return -1;
1854 	}
1855 	return 0;
1856 }
1857 
ice_check_received_binding_request_role_conflict(const IceCheckList * cl,const RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)1858 static int ice_check_received_binding_request_role_conflict(const IceCheckList *cl, const RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr)
1859 {
1860 	/* Detect and repair role conflicts according to 7.2.1.1. */
1861 	if ((cl->session->role == IR_Controlling) && (ms_stun_message_has_ice_controlling(msg))) {
1862 		ms_warning("ice: Role conflict, both agents are CONTROLLING");
1863 		if (cl->session->tie_breaker >= ms_stun_message_get_ice_controlling(msg)) {
1864 			ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_ICE_ERROR_CODE_ROLE_CONFLICT, "Role Conflict");
1865 			return -1;
1866 		} else {
1867 			ms_message("ice: Switch to the CONTROLLED role");
1868 			ice_session_set_role(cl->session, IR_Controlled);
1869 		}
1870 	} else if ((cl->session->role == IR_Controlled) && (ms_stun_message_has_ice_controlled(msg))) {
1871 		ms_warning("ice: Role conflict, both agents are CONTROLLED");
1872 		if (cl->session->tie_breaker >= ms_stun_message_get_ice_controlled(msg)) {
1873 			ms_message("ice: Switch to the CONTROLLING role");
1874 			ice_session_set_role(cl->session, IR_Controlling);
1875 		} else {
1876 			ice_send_error_response(rtp_session, evt_data, msg, remote_addr, MS_ICE_ERROR_CODE_ROLE_CONFLICT, "Role Conflict");
1877 			return -1;
1878 		}
1879 	}
1880 	return 0;
1881 }
1882 
ice_fill_transport_address_from_sockaddr(IceTransportAddress * taddr,struct sockaddr * addr,socklen_t addrlen)1883 static void ice_fill_transport_address_from_sockaddr(IceTransportAddress *taddr, struct sockaddr *addr, socklen_t addrlen) {
1884 	bctbx_sockaddr_to_ip_address(addr, addrlen, taddr->ip, sizeof(taddr->ip), &taddr->port);
1885 	taddr->family = addr->sa_family;
1886 }
1887 
ice_fill_transport_address_from_stun_address(IceTransportAddress * taddr,const MSStunAddress * stun_addr)1888 static void ice_fill_transport_address_from_stun_address(IceTransportAddress *taddr, const MSStunAddress *stun_addr) {
1889 	struct sockaddr_storage addr;
1890 	socklen_t addrlen = sizeof(addr);
1891 	memset(&addr, 0, addrlen);
1892 	ms_stun_address_to_sockaddr(stun_addr, (struct sockaddr *)&addr, &addrlen);
1893 	ice_fill_transport_address_from_sockaddr(taddr, (struct sockaddr *)&addr, addrlen);
1894 }
1895 
ice_transport_address_to_stun_address(IceTransportAddress * taddr)1896 static MSStunAddress ice_transport_address_to_stun_address(IceTransportAddress *taddr) {
1897 	return ms_ip_address_to_stun_address(taddr->family, SOCK_DGRAM, taddr->ip, taddr->port);
1898 }
1899 
ice_transport_address_to_printable_ip_address(const IceTransportAddress * taddr,char * printable_ip,size_t printable_ip_size)1900 static void ice_transport_address_to_printable_ip_address(const IceTransportAddress *taddr, char *printable_ip, size_t printable_ip_size) {
1901 	struct addrinfo *ai;
1902 	if (taddr == NULL) {
1903 		*printable_ip = '\0';
1904 	} else {
1905 		ai = bctbx_ip_address_to_addrinfo(taddr->family, SOCK_DGRAM, taddr->ip, taddr->port);
1906 		bctbx_addrinfo_to_printable_ip_address(ai, printable_ip, printable_ip_size);
1907 		bctbx_freeaddrinfo(ai);
1908 	}
1909 }
1910 
ice_find_candidate_from_foundation(const IceCandidate * candidate,const char * foundation)1911 static int ice_find_candidate_from_foundation(const IceCandidate *candidate, const char *foundation)
1912 {
1913 	return !((strlen(candidate->foundation) == strlen(foundation)) && (strcmp(candidate->foundation, foundation) == 0));
1914 }
1915 
ice_generate_arbitrary_foundation(char * foundation,int len,bctbx_list_t * list)1916 static void ice_generate_arbitrary_foundation(char *foundation, int len, bctbx_list_t *list)
1917 {
1918 	uint64_t r;
1919 	bctbx_list_t *elem;
1920 
1921 	do {
1922 		r = (((uint64_t)ortp_random()) << 32) | (((uint64_t)ortp_random()) & 0xffffffff);
1923 		snprintf(foundation, len, "%" PRIx64, r);
1924 		elem = bctbx_list_find_custom(list, (bctbx_compare_func)ice_find_candidate_from_foundation, foundation);
1925 	} while (elem != NULL);
1926 }
1927 
ice_learn_peer_reflexive_candidate(IceCheckList * cl,const OrtpEventData * evt_data,const MSStunMessage * msg,const IceTransportAddress * taddr)1928 static IceCandidate * ice_learn_peer_reflexive_candidate(IceCheckList *cl, const OrtpEventData *evt_data, const MSStunMessage *msg, const IceTransportAddress *taddr)
1929 {
1930 	char foundation[32];
1931 	IceCandidate *candidate = NULL;
1932 	bctbx_list_t *elem;
1933 	int componentID;
1934 	TransportAddress_ComponentID taci;
1935 
1936 	componentID = ice_get_componentID_from_rtp_session(evt_data);
1937 	if (componentID < 0) return NULL;
1938 
1939 	taci.ta = taddr;
1940 	taci.componentID = componentID;
1941 	elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_find_candidate_from_transport_address_and_componentID, &taci);
1942 	if (elem == NULL) {
1943 		ms_message("ice: Learned peer reflexive candidate %s:%d for componentID %d", taddr->ip, taddr->port, componentID);
1944 		/* Add peer reflexive candidate to the remote candidates list. */
1945 		memset(foundation, '\0', sizeof(foundation));
1946 		ice_generate_arbitrary_foundation(foundation, sizeof(foundation), cl->remote_candidates);
1947 		candidate = ice_add_remote_candidate(cl, "prflx", taddr->family, taddr->ip, taddr->port, componentID, ms_stun_message_get_priority(msg), foundation, FALSE);
1948 	}
1949 	return candidate;
1950 }
1951 
ice_find_pair_from_candidates(const IceCandidatePair * pair,const LocalCandidate_RemoteCandidate * candidates)1952 static int ice_find_pair_from_candidates(const IceCandidatePair *pair, const LocalCandidate_RemoteCandidate *candidates)
1953 {
1954 	return !((pair->local == candidates->local) && (pair->remote == candidates->remote));
1955 }
1956 
1957 /* Trigger checks as defined in 7.2.1.4. */
ice_trigger_connectivity_check_on_binding_request(IceCheckList * cl,const RtpSession * rtp_session,const OrtpEventData * evt_data,IceCandidate * prflx_candidate,const IceTransportAddress * remote_taddr)1958 static IceCandidatePair * ice_trigger_connectivity_check_on_binding_request(IceCheckList *cl, const RtpSession *rtp_session, const OrtpEventData *evt_data, IceCandidate *prflx_candidate, const IceTransportAddress *remote_taddr)
1959 {
1960 	IceTransportAddress local_taddr;
1961 	LocalCandidate_RemoteCandidate candidates;
1962 	bctbx_list_t *elem;
1963 	IceCandidatePair *pair = NULL;
1964 	struct sockaddr_storage recv_addr;
1965 	socklen_t recv_addrlen = sizeof(recv_addr);
1966 	char addr_str[64];
1967 
1968 	memset(&recv_addr, 0, recv_addrlen);
1969 	memset(addr_str, 0, sizeof(addr_str));
1970 	ortp_recvaddr_to_sockaddr(&evt_data->packet->recv_addr, (struct sockaddr *)&recv_addr, &recv_addrlen);
1971 	bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&recv_addr, (struct sockaddr *)&recv_addr, &recv_addrlen);
1972 	ice_fill_transport_address_from_sockaddr(&local_taddr, (struct sockaddr *)&recv_addr, recv_addrlen);
1973 	elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_candidate_from_transport_address, &local_taddr);
1974 	if (elem == NULL) {
1975 		ice_transport_address_to_printable_ip_address(&local_taddr, addr_str, sizeof(addr_str));
1976 		ms_error("ice: Local candidate %s not found!", addr_str);
1977 		return NULL;
1978 	}
1979 	candidates.local = (IceCandidate *)elem->data;
1980 	if (prflx_candidate != NULL) {
1981 		candidates.remote = prflx_candidate;
1982 	} else {
1983 		TransportAddress_ComponentID taci;
1984 		taci.componentID = candidates.local->componentID;
1985 		taci.ta = remote_taddr;
1986 		elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_find_candidate_from_transport_address_and_componentID, &taci);
1987 		if (elem == NULL) {
1988 			ice_transport_address_to_printable_ip_address(remote_taddr, addr_str, sizeof(addr_str));
1989 			ms_error("ice: Remote candidate %s not found!", addr_str);
1990 			return NULL;
1991 		}
1992 		candidates.remote = (IceCandidate *)elem->data;
1993 	}
1994 	elem = bctbx_list_find_custom(cl->check_list, (bctbx_compare_func)ice_find_pair_from_candidates, &candidates);
1995 	if (elem == NULL) {
1996 		/* The pair is not in the check list yet. */
1997 		ms_message("ice: Add new candidate pair in the check list");
1998 		/* Check if the pair is in the list of pairs even if it is not in the check list. */
1999 		elem = bctbx_list_find_custom(cl->pairs, (bctbx_compare_func)ice_find_pair_from_candidates, &candidates);
2000 		if (elem == NULL) {
2001 			pair = ice_pair_new(cl, candidates.local, candidates.remote);
2002 			cl->pairs = bctbx_list_append(cl->pairs, pair);
2003 		} else {
2004 			pair = (IceCandidatePair *)elem->data;
2005 		}
2006 		elem = bctbx_list_find(cl->check_list, pair);
2007 		if (elem == NULL) {
2008 			cl->check_list = bctbx_list_insert_sorted(cl->check_list, pair, (bctbx_compare_func)ice_compare_pair_priorities);
2009 		}
2010 		/* Set the state of the pair to Waiting and trigger a check. */
2011 		ice_pair_set_state(pair, ICP_Waiting);
2012 		ice_check_list_queue_triggered_check(cl, pair);
2013 	} else {
2014 		/* The pair has been found in the check list. */
2015 		pair = (IceCandidatePair *)elem->data;
2016 		switch (pair->state) {
2017 			case ICP_Waiting:
2018 			case ICP_Frozen:
2019 			case ICP_Failed:
2020 				ice_pair_set_state(pair, ICP_Waiting);
2021 				ice_check_list_queue_triggered_check(cl, pair);
2022 				break;
2023 			case ICP_InProgress:
2024 				/* Wait transaction timeout before creating a new binding request for this pair. */
2025 				pair->wait_transaction_timeout = TRUE;
2026 				break;
2027 			case ICP_Succeeded:
2028 				/* Nothing to be done. */
2029 				break;
2030 		}
2031 	}
2032 	return pair;
2033 }
2034 
2035 /* Update the nominated flag of a candidate pair according to 7.2.1.5. */
ice_update_nominated_flag_on_binding_request(const IceCheckList * cl,const MSStunMessage * msg,IceCandidatePair * pair)2036 static void ice_update_nominated_flag_on_binding_request(const IceCheckList *cl, const MSStunMessage *msg, IceCandidatePair *pair)
2037 {
2038 	if (ms_stun_message_use_candidate_enabled(msg) && (cl->session->role == IR_Controlled)) {
2039 		switch (pair->state) {
2040 			case ICP_Succeeded:
2041 				pair->is_nominated = TRUE;
2042 				break;
2043 			case ICP_Waiting:
2044 			case ICP_Frozen:
2045 			case ICP_InProgress:
2046 			case ICP_Failed:
2047 				/* Nothing to be done. */
2048 				break;
2049 		}
2050 	}
2051 }
2052 
ice_handle_received_binding_request(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)2053 static void ice_handle_received_binding_request(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr) {
2054 	IceTransportAddress taddr;
2055 	IceCandidate *prflx_candidate;
2056 	IceCandidatePair *pair;
2057 
2058 	if (ice_check_received_binding_request_attributes(rtp_session, evt_data, msg, remote_addr) < 0) return;
2059 	if (ice_check_received_binding_request_integrity(cl, rtp_session, evt_data, msg, remote_addr) < 0) return;
2060 	if (ice_check_received_binding_request_username(cl, rtp_session, evt_data, msg, remote_addr) < 0) return;
2061 	if (ice_check_received_binding_request_role_conflict(cl, rtp_session, evt_data, msg, remote_addr) < 0) return;
2062 
2063 	ice_fill_transport_address_from_stun_address(&taddr, remote_addr);
2064 	prflx_candidate = ice_learn_peer_reflexive_candidate(cl, evt_data, msg, &taddr);
2065 	pair = ice_trigger_connectivity_check_on_binding_request(cl, rtp_session, evt_data, prflx_candidate, &taddr);
2066 	if (pair != NULL) ice_update_nominated_flag_on_binding_request(cl, msg, pair);
2067 	ice_send_binding_response(cl,rtp_session, evt_data, msg, remote_addr);
2068 	ice_conclude_processing(cl, rtp_session);
2069 }
2070 
ice_find_stun_server_request(const IceStunServerRequest * request,const RtpTransport * rtptp)2071 static int ice_find_stun_server_request(const IceStunServerRequest *request, const RtpTransport *rtptp)
2072 {
2073 	return !(request->rtptp == rtptp);
2074 }
2075 
ice_find_check_list_gathering_candidates(const IceSession * session)2076 static IceCheckList * ice_find_check_list_gathering_candidates(const IceSession *session)
2077 {
2078 	int i;
2079 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
2080 		if ((session->streams[i] != NULL) && (session->streams[i]->gathering_candidates == TRUE))
2081 			return session->streams[i];
2082 	}
2083 	return NULL;
2084 }
2085 
ice_find_pair_from_transactionID(const IceTransaction * transaction,const UInt96 * transactionID)2086 static int ice_find_pair_from_transactionID(const IceTransaction *transaction, const UInt96 *transactionID)
2087 {
2088 	return memcmp(&transaction->transactionID, transactionID, sizeof(transaction->transactionID));
2089 }
2090 
ice_check_received_binding_response_addresses(const RtpSession * rtp_session,const OrtpEventData * evt_data,IceCandidatePair * pair,MSStunAddress * remote_addr)2091 static int ice_check_received_binding_response_addresses(const RtpSession *rtp_session, const OrtpEventData *evt_data, IceCandidatePair *pair, MSStunAddress *remote_addr) {
2092 	struct sockaddr_storage recv_addr;
2093 	socklen_t recv_addrlen = sizeof(recv_addr);
2094 	MSStunAddress recv_stun_addr;
2095 	MSStunAddress pair_remote_stun_addr;
2096 	MSStunAddress pair_local_stun_addr;
2097 
2098 	pair_remote_stun_addr = ms_ip_address_to_stun_address(pair->remote->taddr.family, SOCK_DGRAM, pair->remote->taddr.ip, pair->remote->taddr.port);
2099 	pair_local_stun_addr = ms_ip_address_to_stun_address(pair->local->taddr.family, SOCK_DGRAM, pair->local->taddr.ip, pair->local->taddr.port);
2100 	memset(&recv_addr, 0, recv_addrlen);
2101 	ortp_recvaddr_to_sockaddr(&evt_data->packet->recv_addr, (struct sockaddr *)&recv_addr, &recv_addrlen);
2102 	bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&recv_addr, (struct sockaddr *)&recv_addr, &recv_addrlen);
2103 	ms_sockaddr_to_stun_address((struct sockaddr *)&recv_addr, &recv_stun_addr);
2104 	if (ms_compare_stun_addresses(remote_addr, &pair_remote_stun_addr)
2105 		|| ms_compare_stun_addresses(&recv_stun_addr, &pair_local_stun_addr)) {
2106 		/* Non-symmetric addresses, set the state of the pair to Failed as defined in 7.1.3.1. */
2107 		ms_warning("ice: Non symmetric addresses, set state of pair %p to Failed", pair);
2108 		ice_pair_set_state(pair, ICP_Failed);
2109 		return -1;
2110 	}
2111 	return 0;
2112 }
2113 
ice_check_received_binding_response_attributes(const MSStunMessage * msg,const MSStunAddress * remote_addr,bool_t check_integrity)2114 static int ice_check_received_binding_response_attributes(const MSStunMessage *msg, const MSStunAddress *remote_addr,bool_t check_integrity)
2115 {
2116 	if (!ms_stun_message_message_integrity_enabled(msg)) {
2117 		ms_warning("ice: Received binding response missing MESSAGE-INTEGRITY attribute");
2118 		if (check_integrity)
2119 			return -1;
2120 	}
2121 	if (!ms_stun_message_fingerprint_enabled(msg)) {
2122 		ms_warning("ice: Received binding response missing FINGERPRINT attribute");
2123 		return -1;
2124 	}
2125 	if (ms_stun_message_get_xor_mapped_address(msg) == NULL) {
2126 		ms_warning("ice: Received binding response missing XOR-MAPPED-ADDRESS attribute");
2127 		return -1;
2128 	}
2129 	return 0;
2130 }
2131 
ice_discover_peer_reflexive_candidate(IceCheckList * cl,const IceCandidatePair * pair,const MSStunMessage * msg)2132 static IceCandidate * ice_discover_peer_reflexive_candidate(IceCheckList *cl, const IceCandidatePair *pair, const MSStunMessage *msg)
2133 {
2134 	IceTransportAddress taddr;
2135 	const MSStunAddress *xor_mapped_address;
2136 	IceCandidate *candidate = NULL;
2137 	bctbx_list_t *elem;
2138 	char taddr_str[64];
2139 	TransportAddress_ComponentID taci;
2140 
2141 	memset(&taddr, 0, sizeof(taddr));
2142 	xor_mapped_address = ms_stun_message_get_xor_mapped_address(msg);
2143 	ice_fill_transport_address_from_stun_address(&taddr, xor_mapped_address);
2144 	taci.componentID = pair->local->componentID;
2145 	taci.ta = &taddr;
2146 	elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_candidate_from_transport_address_and_componentID, &taci);
2147 	if (elem == NULL) {
2148 		memset(taddr_str, 0, sizeof(taddr_str));
2149 		ice_transport_address_to_printable_ip_address(&taddr, taddr_str, sizeof(taddr_str));
2150 		ms_message("ice: Discovered peer reflexive candidate %s for componentID %d", taddr_str, pair->local->componentID);
2151 		/* Add peer reflexive candidate to the local candidates list. */
2152 		candidate = ice_add_local_candidate(cl, "prflx", taddr.family, taddr.ip, taddr.port, pair->local->componentID, pair->local);
2153 		ice_compute_candidate_foundation(candidate, cl);
2154 	} else {
2155 		candidate = (IceCandidate *)elem->data;
2156 	}
2157 	return candidate;
2158 }
2159 
ice_compare_valid_pair_priorities(const IceValidCandidatePair * vp1,const IceValidCandidatePair * vp2)2160 static int ice_compare_valid_pair_priorities(const IceValidCandidatePair *vp1, const IceValidCandidatePair *vp2)
2161 {
2162 	return ice_compare_pair_priorities(vp1->valid, vp2->valid);
2163 }
2164 
ice_find_valid_pair(const IceValidCandidatePair * vp1,const IceValidCandidatePair * vp2)2165 static int ice_find_valid_pair(const IceValidCandidatePair *vp1, const IceValidCandidatePair *vp2)
2166 {
2167 	return !((vp1->valid == vp2->valid) && (vp1->generated_from == vp2->generated_from));
2168 }
2169 
2170 /* Construct a valid ICE candidate pair as defined in 7.1.3.2.2. */
ice_construct_valid_pair(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,IceCandidate * candidate,IceCandidatePair * succeeded_pair)2171 static IceCandidatePair * ice_construct_valid_pair(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, IceCandidate *candidate, IceCandidatePair *succeeded_pair)
2172 {
2173 	LocalCandidate_RemoteCandidate candidates;
2174 	IceCandidatePair *pair = NULL;
2175 	IceValidCandidatePair *valid_pair;
2176 	bctbx_list_t *elem;
2177 	OrtpEvent *ev;
2178 	char local_addr_str[64];
2179 	char remote_addr_str[64];
2180 
2181 	candidates.local = candidate;
2182 	candidates.remote = succeeded_pair->remote;
2183 	elem = bctbx_list_find_custom(cl->check_list, (bctbx_compare_func)ice_find_pair_from_candidates, &candidates);
2184 	if (elem == NULL) {
2185 		/* The candidate pair is not a known candidate pair, compute its priority and add it to the valid list. */
2186 		pair = ice_pair_new(cl, candidates.local, candidates.remote);
2187 		cl->pairs = bctbx_list_append(cl->pairs, pair);
2188 	} else {
2189 		/* The candidate pair is already in the check list, add it to the valid list. */
2190 		pair = (IceCandidatePair *)elem->data;
2191 	}
2192 	valid_pair = ms_new0(IceValidCandidatePair, 1);
2193 	valid_pair->valid = pair;
2194 	valid_pair->generated_from = succeeded_pair;
2195 	valid_pair->selected = FALSE;
2196 	memset(local_addr_str, 0, sizeof(local_addr_str));
2197 	memset(remote_addr_str, 0, sizeof(remote_addr_str));
2198 	ice_transport_address_to_printable_ip_address(&pair->local->taddr, local_addr_str, sizeof(local_addr_str));
2199 	ice_transport_address_to_printable_ip_address(&pair->remote->taddr, remote_addr_str, sizeof(remote_addr_str));
2200 	elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_valid_pair, valid_pair);
2201 	if (elem == NULL) {
2202 		cl->valid_list = bctbx_list_insert_sorted(cl->valid_list, valid_pair, (bctbx_compare_func)ice_compare_valid_pair_priorities);
2203 		ms_message("ice: Added pair %p to the valid list: %s:%s --> %s:%s", pair,
2204 			local_addr_str, candidate_type_values[pair->local->type], remote_addr_str, candidate_type_values[pair->remote->type]);
2205 		elem = bctbx_list_find_custom(cl->losing_pairs, (bctbx_compare_func)ice_find_pair_from_candidates, &candidates);
2206 		if (elem != NULL) {
2207 			cl->losing_pairs = bctbx_list_erase_link(cl->losing_pairs, elem);
2208 			/* Select the losing pair that has just become a valid pair. */
2209 			valid_pair->selected = TRUE;
2210 			if (ice_session_nb_losing_pairs(cl->session) == 0) {
2211 				/* Notify the application that the checks for losing pairs have completed. The answer can now be sent. */
2212 				ice_check_list_set_state(cl, ICL_Completed);
2213 				ev = ortp_event_new(ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED);
2214 				ortp_event_get_data(ev)->info.ice_processing_successful = TRUE;
2215 				rtp_session_dispatch_event(rtp_session, ev);
2216 			}
2217 		}
2218 	} else {
2219 		ms_message("ice: Pair already in the valid list: %s:%s --> %s:%s",
2220 			local_addr_str, candidate_type_values[pair->local->type], remote_addr_str, candidate_type_values[pair->remote->type]);
2221 		ms_free(valid_pair);
2222 	}
2223 	return pair;
2224 }
2225 
ice_compare_pair_foundations(const IceCandidatePair * p1,const IceCandidatePair * p2)2226 static int ice_compare_pair_foundations(const IceCandidatePair *p1, const IceCandidatePair *p2)
2227 {
2228 	return !((strlen(p1->local->foundation) == strlen(p2->local->foundation)) && (strcmp(p1->local->foundation, p2->local->foundation) == 0)
2229 		&& ((strlen(p1->remote->foundation) == strlen(p2->remote->foundation)) && (strcmp(p1->remote->foundation, p2->remote->foundation) == 0)));
2230 }
2231 
ice_change_state_of_frozen_pairs_to_waiting(IceCandidatePair * pair,const IceCandidatePair * succeeded_pair)2232 static void ice_change_state_of_frozen_pairs_to_waiting(IceCandidatePair *pair, const IceCandidatePair *succeeded_pair)
2233 {
2234 	if ((pair != succeeded_pair) && (pair->state == ICP_Frozen) && (ice_compare_pair_foundations(pair, succeeded_pair) == 0)) {
2235 		ms_message("ice: Change state of pair %p from Frozen to Waiting", pair);
2236 		ice_pair_set_state(pair, ICP_Waiting);
2237 	}
2238 }
2239 
2240 /* Update the pair states according to 7.1.3.2.3. */
ice_update_pair_states_on_binding_response(IceCheckList * cl,IceCandidatePair * pair)2241 static void ice_update_pair_states_on_binding_response(IceCheckList *cl, IceCandidatePair *pair)
2242 {
2243 	/* Set the state of the pair that generated the check to Succeeded. */
2244 	ice_pair_set_state(pair, ICP_Succeeded);
2245 
2246 	/* Change the state of all Frozen pairs with the same foundation to Waiting. */
2247 	bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_change_state_of_frozen_pairs_to_waiting, pair);
2248 }
2249 
2250 /* Update the nominated flag of a candidate pair according to 7.1.3.2.4. */
ice_update_nominated_flag_on_binding_response(const IceCheckList * cl,IceCandidatePair * valid_pair,const IceCandidatePair * succeeded_pair,IceCandidatePairState succeeded_pair_previous_state)2251 static void ice_update_nominated_flag_on_binding_response(const IceCheckList *cl, IceCandidatePair *valid_pair, const IceCandidatePair *succeeded_pair, IceCandidatePairState succeeded_pair_previous_state)
2252 {
2253 	switch (cl->session->role) {
2254 		case IR_Controlling:
2255 			if (succeeded_pair->use_candidate == TRUE) {
2256 				valid_pair->is_nominated = TRUE;
2257 			}
2258 			break;
2259 		case IR_Controlled:
2260 			if (succeeded_pair_previous_state == ICP_InProgress) {
2261 				valid_pair->is_nominated = TRUE;
2262 			}
2263 			break;
2264 	}
2265 }
2266 
ice_find_not_failed_or_succeeded_pair(const IceCandidatePair * pair,const void * dummy)2267 static int ice_find_not_failed_or_succeeded_pair(const IceCandidatePair *pair, const void *dummy)
2268 {
2269 	return !((pair->state != ICP_Failed) && (pair->state != ICP_Succeeded));
2270 }
2271 
ice_compare_transactionIDs(const IceStunServerRequestTransaction * transaction,const UInt96 * tr_id2)2272 static int ice_compare_transactionIDs(const IceStunServerRequestTransaction *transaction, const UInt96 *tr_id2)
2273 {
2274 	const UInt96 *tr_id1 = &transaction->transactionID;
2275 	return memcmp(tr_id1, tr_id2, sizeof(UInt96));
2276 }
2277 
ice_find_non_responded_gathering_stun_server_request(const IceStunServerRequest * request,const void * dummy)2278 static int ice_find_non_responded_gathering_stun_server_request(const IceStunServerRequest *request, const void *dummy)
2279 {
2280 	return (request->gathering == FALSE) || (request->responded == TRUE);
2281 }
2282 
ice_allow_turn_peer_address(IceCheckList * cl,int componentID,MSStunAddress * peer_address)2283 static void ice_allow_turn_peer_address(IceCheckList *cl, int componentID, MSStunAddress *peer_address) {
2284 	MSTurnContext *turn_context = ice_get_turn_context_from_check_list_componentID(cl, componentID);
2285 	ms_turn_context_allow_peer_address(turn_context, peer_address);
2286 }
2287 
ice_schedule_turn_allocation_refresh(IceCheckList * cl,int componentID,uint32_t lifetime)2288 static void ice_schedule_turn_allocation_refresh(IceCheckList *cl, int componentID, uint32_t lifetime) {
2289 	char source_addr_str[64];
2290 	int source_port = 0;
2291 	MSTurnContext *turn_context;
2292 	IceStunServerRequest *request;
2293 	RtpTransport *rtptp = NULL;
2294 	const OrtpStream *stream = NULL;
2295 	struct sockaddr *sa;
2296 	uint32_t ms = (uint32_t)((lifetime * .9f) * 1000); /* 90% of the lifetime */
2297 
2298 	turn_context = ice_get_turn_context_from_check_list_componentID(cl, componentID);
2299 	ice_get_transport_from_rtp_session_and_componentID(cl->rtp_session, componentID, &rtptp);
2300 	ice_get_ortp_stream_from_rtp_session_and_componentID(cl->rtp_session, componentID, &stream);
2301 	sa = (struct sockaddr *)&stream->loc_addr;
2302 	memset(source_addr_str, 0, sizeof(source_addr_str));
2303 	bctbx_sockaddr_to_ip_address(sa, stream->loc_addrlen, source_addr_str, sizeof(source_addr_str), &source_port);
2304 	request = ice_stun_server_request_new(cl, turn_context, rtptp, sa->sa_family, source_addr_str, source_port, MS_TURN_METHOD_REFRESH);
2305 	if (cl->session->short_turn_refresh == TRUE) ms = 5000; /* 5 seconds */
2306 	request->next_transmission_time = ice_add_ms(ice_current_time(), ms);
2307 	ice_check_list_add_stun_server_request(cl, request);
2308 }
2309 
ice_schedule_turn_permission_refresh(IceCheckList * cl,int componentID,MSStunAddress peer_address)2310 static void ice_schedule_turn_permission_refresh(IceCheckList *cl, int componentID, MSStunAddress peer_address) {
2311 	char source_addr_str[64];
2312 	int source_port = 0;
2313 	MSTurnContext *turn_context;
2314 	IceStunServerRequest *request;
2315 	RtpTransport *rtptp = NULL;
2316 	const OrtpStream *stream = NULL;
2317 	struct sockaddr *sa;
2318 	uint32_t ms = 240000; /* 4 minutes */
2319 
2320 	turn_context = ice_get_turn_context_from_check_list_componentID(cl, componentID);
2321 	ice_get_transport_from_rtp_session_and_componentID(cl->rtp_session, componentID, &rtptp);
2322 	ice_get_ortp_stream_from_rtp_session_and_componentID(cl->rtp_session, componentID, &stream);
2323 	sa = (struct sockaddr *)&stream->loc_addr;
2324 	memset(source_addr_str, 0, sizeof(source_addr_str));
2325 	bctbx_sockaddr_to_ip_address(sa, stream->loc_addrlen, source_addr_str, sizeof(source_addr_str), &source_port);
2326 	request = ice_stun_server_request_new(cl, turn_context, rtptp, sa->sa_family, source_addr_str, source_port, MS_TURN_METHOD_CREATE_PERMISSION);
2327 	request->peer_address = peer_address;
2328 	if (cl->session->short_turn_refresh == TRUE) ms = 5000; /* 5 seconds */
2329 	request->next_transmission_time = ice_add_ms(ice_current_time(), ms);
2330 	ice_check_list_add_stun_server_request(cl, request);
2331 }
2332 
ice_schedule_turn_channel_bind_refresh(IceCheckList * cl,int componentID,uint16_t channel_number,MSStunAddress peer_address)2333 static void ice_schedule_turn_channel_bind_refresh(IceCheckList *cl, int componentID, uint16_t channel_number, MSStunAddress peer_address) {
2334 	char source_addr_str[64];
2335 	int source_port = 0;
2336 	MSTurnContext *turn_context;
2337 	IceStunServerRequest *request;
2338 	RtpTransport *rtptp = NULL;
2339 	const OrtpStream *stream = NULL;
2340 	struct sockaddr *sa;
2341 	uint32_t ms = 540000; /* 9 minutes */
2342 
2343 	turn_context = ice_get_turn_context_from_check_list_componentID(cl, componentID);
2344 	ice_get_transport_from_rtp_session_and_componentID(cl->rtp_session, componentID, &rtptp);
2345 	ice_get_ortp_stream_from_rtp_session_and_componentID(cl->rtp_session, componentID, &stream);
2346 	sa = (struct sockaddr *)&stream->loc_addr;
2347 	memset(source_addr_str, 0, sizeof(source_addr_str));
2348 	bctbx_sockaddr_to_ip_address(sa, stream->loc_addrlen, source_addr_str, sizeof(source_addr_str), &source_port);
2349 	request = ice_stun_server_request_new(cl, turn_context, rtptp, sa->sa_family, source_addr_str, source_port, MS_TURN_METHOD_CHANNEL_BIND);
2350 	request->channel_number = channel_number;
2351 	request->peer_address = peer_address;
2352 	if (cl->session->short_turn_refresh == TRUE) ms = 5000; /* 5 seconds */
2353 	request->next_transmission_time = ice_add_ms(ice_current_time(), ms);
2354 	ice_check_list_add_stun_server_request(cl, request);
2355 }
2356 
ice_handle_received_turn_allocate_success_response(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)2357 static bool_t ice_handle_received_turn_allocate_success_response(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr) {
2358 	bctbx_list_t *base_elem;
2359 	IceCandidate *candidate;
2360 	OrtpEvent *ev;
2361 	bool_t stun_server_response = FALSE;
2362 	struct sockaddr *servaddr = (struct sockaddr *)&cl->session->ss;
2363 	socklen_t servaddrlen = 0;
2364 	UInt96 tr_id = ms_stun_message_get_tr_id(msg);
2365 	MSStunAddress serv_stun_addr;
2366 	MSStunAddress srflx_addr;
2367 	MSStunAddress relay_addr;
2368 	char srflx_addr_str[64];
2369 	char relay_addr_str[64];
2370 	int srflx_port = 0;
2371 	int relay_port = 0;
2372 	int componentID;
2373 
2374 	bctbx_sockaddr_ipv6_to_ipv4(servaddr, servaddr, &servaddrlen);
2375 	ms_sockaddr_to_stun_address(servaddr, &serv_stun_addr);
2376 	if (!ms_compare_stun_addresses(remote_addr, &serv_stun_addr)) {
2377 		IceStunServerRequest * request = ice_check_list_get_stun_server_request(cl, &tr_id);
2378 		if (request != NULL) {
2379 			componentID = ice_get_componentID_from_rtp_session(evt_data);
2380 			memset(&srflx_addr, 0, sizeof(srflx_addr));
2381 			memset(&relay_addr, 0, sizeof(relay_addr));
2382 			if ((componentID > 0) && (ice_parse_stun_server_response(msg, &srflx_addr, &relay_addr) >= 0)) {
2383 				ComponentID_Family cf = { componentID, AF_INET };
2384 				if (srflx_addr.family == MS_STUN_ADDR_FAMILY_IPV6) cf.family = AF_INET6;
2385 				base_elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_host_candidate, &cf);
2386 				if ((base_elem == NULL) && (cf.family == AF_INET)) {
2387 					/* Handle NAT64 case where the local candidate is IPv6 but the reflexive candidate returned by STUN is IPv4. */
2388 					cf.family = AF_INET6;
2389 					base_elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_host_candidate, &cf);
2390 				}
2391 				if (base_elem != NULL) {
2392 					candidate = (IceCandidate *)base_elem->data;
2393 					memset(srflx_addr_str, 0, sizeof(srflx_addr));
2394 					ms_stun_address_to_ip_address(&srflx_addr, srflx_addr_str, sizeof(srflx_addr_str), &srflx_port);
2395 					if (srflx_port != 0) {
2396 						candidate = ice_add_local_candidate(cl, "srflx", ms_stun_family_to_af(srflx_addr.family), srflx_addr_str, srflx_port, componentID, candidate);
2397 						ms_stun_address_to_printable_ip_address(&srflx_addr, srflx_addr_str, sizeof(srflx_addr_str));
2398 						ms_message("ice: Add candidate obtained by STUN/TURN: %s:srflx", srflx_addr_str);
2399 
2400 						if (cl->session->turn_enabled) {
2401 							request->turn_context->stats.nb_successful_allocate++;
2402 							ice_schedule_turn_allocation_refresh(cl, componentID, ms_stun_message_get_lifetime(msg));
2403 						}
2404 						if (relay_addr.family != 0){
2405 							memset(relay_addr_str, 0, sizeof(relay_addr_str));
2406 							ms_stun_address_to_ip_address(&relay_addr, relay_addr_str, sizeof(relay_addr_str), &relay_port);
2407 							if (relay_port != 0) {
2408 								if (cl->session->turn_enabled) {
2409 									ms_turn_context_set_allocated_relay_addr(request->turn_context, relay_addr);
2410 								}
2411 								ice_add_local_candidate(cl, "relay", ms_stun_family_to_af(relay_addr.family), relay_addr_str, relay_port, componentID, NULL);
2412 								ms_stun_address_to_printable_ip_address(&relay_addr, relay_addr_str, sizeof(relay_addr_str));
2413 								ms_message("ice: Add candidate obtained by STUN/TURN: %s:relay", relay_addr_str);
2414 							}
2415 						}
2416 					}
2417 				}
2418 				request->responded = TRUE;
2419 				if (cl->session->turn_enabled) {
2420 					ms_turn_context_set_state(request->turn_context, MS_TURN_CONTEXT_STATE_ALLOCATION_CREATED);
2421 					if (ms_stun_message_has_lifetime(msg)) ms_turn_context_set_lifetime(request->turn_context, ms_stun_message_get_lifetime(msg));
2422 				}
2423 			}
2424 			stun_server_response = TRUE;
2425 		}
2426 
2427 		if (bctbx_list_find_custom(cl->stun_server_requests, (bctbx_compare_func)ice_find_non_responded_gathering_stun_server_request, NULL) == NULL) {
2428 			ice_check_list_stop_gathering(cl);
2429 			ms_message("ice: Finished candidates gathering for check list %p", cl);
2430 			ice_dump_candidates(cl);
2431 			if (ice_find_check_list_gathering_candidates(cl->session) == NULL) {
2432 				/* Notify the application when there is no longer any check list gathering candidates. */
2433 				ev = ortp_event_new(ORTP_EVENT_ICE_GATHERING_FINISHED);
2434 				ortp_event_get_data(ev)->info.ice_processing_successful = TRUE;
2435 				cl->session->gathering_end_ts = evt_data->ts;
2436 				rtp_session_dispatch_event(rtp_session, ev);
2437 			}
2438 		}
2439 	}
2440 
2441 	return stun_server_response;
2442 }
2443 
ice_handle_received_create_permission_success_response(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)2444 static void ice_handle_received_create_permission_success_response(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr) {
2445 	int componentID = ice_get_componentID_from_rtp_session(evt_data);
2446 	UInt96 tr_id = ms_stun_message_get_tr_id(msg);
2447 	IceStunServerRequest *request = ice_check_list_get_stun_server_request(cl, &tr_id);
2448 	if (request != NULL) {
2449 		MSStunAddress peer_address = request->peer_address;
2450 		ice_check_list_remove_stun_server_request(cl, &tr_id);
2451 		ice_allow_turn_peer_address(cl, componentID, &peer_address);
2452 		ice_schedule_turn_permission_refresh(cl, componentID, peer_address);
2453 	}
2454 }
2455 
ice_handle_received_turn_refresh_success_response(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)2456 static void ice_handle_received_turn_refresh_success_response(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr) {
2457 	int componentID = ice_get_componentID_from_rtp_session(evt_data);
2458 	MSTurnContext *context = ice_get_turn_context_from_check_list_componentID(cl, componentID);
2459 	UInt96 tr_id = ms_stun_message_get_tr_id(msg);
2460 	ice_check_list_remove_stun_server_request(cl, &tr_id);
2461 	if (ms_turn_context_get_lifetime(context) == 0) {
2462 		/* TURN deallocation success */
2463 		ms_turn_context_set_state(context, MS_TURN_CONTEXT_STATE_IDLE);
2464 	} else {
2465 		ice_schedule_turn_allocation_refresh(cl, componentID, ms_stun_message_get_lifetime(msg));
2466 		context->stats.nb_successful_refresh++;
2467 	}
2468 }
2469 
ice_handle_received_turn_channel_bind_success_response(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,const MSStunAddress * remote_addr)2470 static void ice_handle_received_turn_channel_bind_success_response(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, const MSStunAddress *remote_addr) {
2471 	int componentID = ice_get_componentID_from_rtp_session(evt_data);
2472 	UInt96 tr_id = ms_stun_message_get_tr_id(msg);
2473 	IceStunServerRequest *request = ice_check_list_get_stun_server_request(cl, &tr_id);
2474 	if (request != NULL) {
2475 		uint16_t channel_number = request->channel_number;
2476 		MSStunAddress peer_address = request->peer_address;
2477 		MSTurnContext *context = ice_get_turn_context_from_check_list_componentID(cl, componentID);
2478 		ms_turn_context_set_state(context, MS_TURN_CONTEXT_STATE_CHANNEL_BOUND);
2479 		ice_check_list_remove_stun_server_request(cl, &tr_id);
2480 		ice_schedule_turn_channel_bind_refresh(cl, componentID, channel_number, peer_address);
2481 	}
2482 }
2483 
ice_handle_received_binding_response(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg,MSStunAddress * remote_addr)2484 static void ice_handle_received_binding_response(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg, MSStunAddress *remote_addr)
2485 {
2486 	IceCandidatePair *succeeded_pair;
2487 	IceCandidatePair *valid_pair;
2488 	IceCandidate *candidate;
2489 	IceCandidatePairState succeeded_pair_previous_state;
2490 	bctbx_list_t *elem;
2491 	UInt96 tr_id = ms_stun_message_get_tr_id(msg);
2492 
2493 	if (cl->gathering_candidates == TRUE) {
2494 		if (ice_handle_received_turn_allocate_success_response(cl, rtp_session, evt_data, msg, remote_addr) == TRUE)
2495 			return;
2496 	}
2497 
2498 	elem = bctbx_list_find_custom(cl->transaction_list, (bctbx_compare_func)ice_find_pair_from_transactionID, &tr_id);
2499 	if (elem == NULL) {
2500 		/* We received an error response concerning an unknown binding request, ignore it... */
2501 		char tr_id_str[25];
2502 		transactionID2string(&tr_id, tr_id_str);
2503 		ms_warning("ice: Received a binding response for an unknown transaction ID: %s", tr_id_str);
2504 		return;
2505 	}
2506 
2507 	succeeded_pair = (IceCandidatePair *)((IceTransaction *)elem->data)->pair;
2508 	if (ice_check_received_binding_response_addresses(rtp_session, evt_data, succeeded_pair, remote_addr) < 0) return;
2509 	if (ice_check_received_binding_response_attributes(msg, remote_addr,cl->session->check_message_integrity) < 0) return;
2510 
2511 	succeeded_pair_previous_state = succeeded_pair->state;
2512 	candidate = ice_discover_peer_reflexive_candidate(cl, succeeded_pair, msg);
2513 	valid_pair = ice_construct_valid_pair(cl, rtp_session, evt_data, candidate, succeeded_pair);
2514 	ice_update_pair_states_on_binding_response(cl, succeeded_pair);
2515 	ice_update_nominated_flag_on_binding_response(cl, valid_pair, succeeded_pair, succeeded_pair_previous_state);
2516 	ice_conclude_processing(cl, rtp_session);
2517 }
2518 
ice_handle_stun_server_error_response(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg)2519 static void ice_handle_stun_server_error_response(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg)
2520 {
2521 	bctbx_list_t *elem;
2522 	RtpTransport *rtptp = NULL;
2523 	char *reason = NULL;
2524 	uint16_t number = ms_stun_message_get_error_code(msg, &reason);
2525 
2526 	ice_get_transport_from_rtp_session(rtp_session, evt_data, &rtptp);
2527 	elem = bctbx_list_find_custom(cl->stun_server_requests, (bctbx_compare_func)ice_find_stun_server_request, rtptp);
2528 	if (elem != NULL) {
2529 		IceStunServerRequest *request = (IceStunServerRequest *)elem->data;
2530 		if ((request != NULL) && (number == 401) && (cl->session->stun_auth_requested_cb != NULL)) {
2531 			const char *username = NULL;
2532 			const char *password = NULL;
2533 			const char *ha1 = NULL;
2534 			const char *realm = ms_stun_message_get_realm(msg);
2535 			const char *nonce = ms_stun_message_get_nonce(msg);
2536 			cl->session->stun_auth_requested_cb(cl->session->stun_auth_requested_userdata, realm, nonce, &username, &password, &ha1);
2537 			if ((username != NULL) && (cl->session->turn_enabled)) {
2538 				IceStunServerRequestTransaction *transaction = NULL;
2539 				MSTurnContext *turn_context = ice_get_turn_context_from_check_list(cl, evt_data);
2540 				ms_turn_context_set_realm(turn_context, realm);
2541 				ms_turn_context_set_nonce(turn_context, nonce);
2542 				ms_turn_context_set_username(turn_context, username);
2543 				ms_turn_context_set_password(turn_context, password);
2544 				ms_turn_context_set_ha1(turn_context, ha1);
2545 				request->next_transmission_time = ice_add_ms(ice_current_time(), ICE_DEFAULT_RTO_DURATION);
2546 				transaction = ice_send_turn_server_allocate_request(request, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
2547 				ice_stun_server_request_add_transaction(request, transaction);
2548 			}
2549 		}
2550 	}
2551 }
2552 
ice_handle_received_error_response(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data,const MSStunMessage * msg)2553 static void ice_handle_received_error_response(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data, const MSStunMessage *msg)
2554 {
2555 	IceCandidatePair *pair;
2556 	char local_addr_str[64];
2557 	char remote_addr_str[64];
2558 
2559 	if (cl->gathering_candidates == TRUE) {
2560 		ice_handle_stun_server_error_response(cl, rtp_session, evt_data, msg);
2561 	} else {
2562 		UInt96 tr_id = ms_stun_message_get_tr_id(msg);
2563 		bctbx_list_t *elem = bctbx_list_find_custom(cl->transaction_list, (bctbx_compare_func)ice_find_pair_from_transactionID, &tr_id);
2564 		if (elem == NULL) {
2565 			/* We received an error response concerning an unknown binding request, ignore it... */
2566 			return;
2567 		}
2568 
2569 		pair = (IceCandidatePair *)((IceTransaction *)elem->data)->pair;
2570 		if (ms_stun_message_has_error_code(msg)
2571 				&& (ms_stun_message_get_error_code(msg, NULL) == MS_STUN_ERROR_CODE_UNAUTHORIZED)
2572 				&& pair->retry_with_dummy_message_integrity) {
2573 			ms_warning("ice pair [%p], retry skipping message integrity for compatibility with older version",pair);
2574 			pair->retry_with_dummy_message_integrity=FALSE;
2575 			pair->use_dummy_hmac=TRUE;
2576 			return;
2577 
2578 		} else {
2579 			ice_pair_set_state(pair, ICP_Failed);
2580 			memset(local_addr_str, 0, sizeof(local_addr_str));
2581 			memset(remote_addr_str, 0, sizeof(remote_addr_str));
2582 			ice_transport_address_to_printable_ip_address(&pair->local->taddr, local_addr_str, sizeof(local_addr_str));
2583 			ice_transport_address_to_printable_ip_address(&pair->remote->taddr, remote_addr_str, sizeof(remote_addr_str));
2584 			ms_message("ice: Error response, set state to Failed for pair %p: %s:%s --> %s:%s", pair,
2585 					local_addr_str, candidate_type_values[pair->local->type], remote_addr_str, candidate_type_values[pair->remote->type]);
2586 		}
2587 		if (ms_stun_message_has_error_code(msg) && (ms_stun_message_get_error_code(msg, NULL) == MS_ICE_ERROR_CODE_ROLE_CONFLICT)) {
2588 			/* Handle error 487 (Role Conflict) according to 7.1.3.1. */
2589 			switch (pair->role) {
2590 				case IR_Controlling:
2591 					ms_message("ice: Switch to the CONTROLLED role");
2592 					ice_session_set_role(cl->session, IR_Controlled);
2593 					break;
2594 				case IR_Controlled:
2595 					ms_message("ice: Switch to the CONTROLLING role");
2596 					ice_session_set_role(cl->session, IR_Controlling);
2597 					break;
2598 			}
2599 
2600 			/* Set the state of the pair to Waiting and trigger a check. */
2601 			ice_pair_set_state(pair, ICP_Waiting);
2602 			ice_check_list_queue_triggered_check(cl, pair);
2603 		}
2604 
2605 		ice_conclude_processing(cl, rtp_session);
2606 	}
2607 }
2608 
ice_find_stun_server_request_transaction(IceStunServerRequest * request,UInt96 * tr_id)2609 static int ice_find_stun_server_request_transaction(IceStunServerRequest *request, UInt96 *tr_id) {
2610 	return (bctbx_list_find_custom(request->transactions, (bctbx_compare_func)ice_compare_transactionIDs, tr_id) == NULL);
2611 }
2612 
ice_compare_stun_server_requests_to_remove(IceStunServerRequest * request)2613 static int ice_compare_stun_server_requests_to_remove(IceStunServerRequest *request) {
2614 	return request->to_remove == FALSE;
2615 }
2616 
ice_check_list_remove_stun_server_request(IceCheckList * cl,UInt96 * tr_id)2617 static void ice_check_list_remove_stun_server_request(IceCheckList *cl, UInt96 *tr_id) {
2618 	bctbx_list_t *elem = cl->stun_server_requests;
2619 	while (elem != NULL) {
2620 		elem = bctbx_list_find_custom(cl->stun_server_requests, (bctbx_compare_func)ice_find_stun_server_request_transaction, tr_id);
2621 		if (elem != NULL) {
2622 			IceStunServerRequest *request = (IceStunServerRequest *)elem->data;
2623 			ice_stun_server_request_free(request);
2624 			cl->stun_server_requests = bctbx_list_erase_link(cl->stun_server_requests, elem);
2625 		}
2626 	}
2627 }
2628 
ice_check_list_get_stun_server_request(IceCheckList * cl,UInt96 * tr_id)2629 static IceStunServerRequest * ice_check_list_get_stun_server_request(IceCheckList *cl, UInt96 *tr_id) {
2630 	bctbx_list_t *elem = bctbx_list_find_custom(cl->stun_server_requests, (bctbx_compare_func)ice_find_stun_server_request_transaction, tr_id);
2631 	if (elem == NULL) return NULL;
2632 	return (IceStunServerRequest *)elem->data;
2633 }
2634 
ice_set_transaction_response_time(IceCheckList * cl,UInt96 * tr_id,MSTimeSpec response_time)2635 static void ice_set_transaction_response_time(IceCheckList *cl, UInt96 *tr_id, MSTimeSpec response_time) {
2636 	IceStunServerRequest *request;
2637 	IceStunServerRequestTransaction *transaction;
2638 	bctbx_list_t *elem = bctbx_list_find_custom(cl->stun_server_requests, (bctbx_compare_func)ice_find_stun_server_request_transaction, tr_id);
2639 	if (elem == NULL) return;
2640 	request = (IceStunServerRequest *)elem->data;
2641 	elem = bctbx_list_find_custom(request->transactions, (bctbx_compare_func)ice_compare_transactionIDs, tr_id);
2642 	if (elem == NULL) return;
2643 	transaction = (IceStunServerRequestTransaction *)elem->data;
2644 	transaction->response_time = response_time;
2645 }
2646 
ice_handle_stun_packet(IceCheckList * cl,RtpSession * rtp_session,const OrtpEventData * evt_data)2647 void ice_handle_stun_packet(IceCheckList *cl, RtpSession *rtp_session, const OrtpEventData *evt_data)
2648 {
2649 	MSStunMessage *msg;
2650 	MSStunAddress source_stun_addr;
2651 	struct sockaddr_storage recv_addr;
2652 	socklen_t recv_addrlen = sizeof(recv_addr);
2653 	char source_addr_str[64];
2654 	char recv_addr_str[64];
2655 	mblk_t *mp = evt_data->packet;
2656 	char tr_id_str[25];
2657 	UInt96 tr_id;
2658 
2659 	if (cl->session == NULL) return;
2660 
2661 	msg = ms_stun_message_create_from_buffer_parsing(mp->b_rptr, (ssize_t)(mp->b_wptr - mp->b_rptr));
2662 	if (msg == NULL) {
2663 		ms_warning("ice: Received invalid STUN packet");
2664 		return;
2665 	}
2666 
2667 	memset(source_addr_str, 0, sizeof(source_addr_str));
2668 	memset(recv_addr_str, 0, sizeof(recv_addr_str));
2669 	tr_id = ms_stun_message_get_tr_id(msg);
2670 	transactionID2string(&tr_id, tr_id_str);
2671 	memset(&recv_addr, 0, recv_addrlen);
2672 	ortp_recvaddr_to_sockaddr(&evt_data->packet->recv_addr, (struct sockaddr *)&recv_addr, &recv_addrlen);
2673 	bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&recv_addr, (struct sockaddr *)&recv_addr, &recv_addrlen);
2674 	bctbx_sockaddr_to_printable_ip_address((struct sockaddr *)&recv_addr, recv_addrlen, recv_addr_str, sizeof(recv_addr_str));
2675 	bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&evt_data->source_addr, (struct sockaddr *)&evt_data->source_addr, &recv_addrlen);
2676 	ms_sockaddr_to_stun_address((struct sockaddr *)&evt_data->source_addr, &source_stun_addr);
2677 	ms_stun_address_to_printable_ip_address(&source_stun_addr, source_addr_str, sizeof(source_addr_str));
2678 
2679 	if (ms_stun_message_is_request(msg)) {
2680 		ms_message("ice: Recv binding request: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2681 		ice_handle_received_binding_request(cl, rtp_session, evt_data, msg, &source_stun_addr);
2682 	} else if (ms_stun_message_is_success_response(msg)) {
2683 		ice_set_transaction_response_time(cl, &tr_id, evt_data->ts);
2684 		switch (ms_stun_message_get_method(msg)) {
2685 			case MS_STUN_METHOD_BINDING:
2686 				ms_message("ice: Recv binding response: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2687 				ice_handle_received_binding_response(cl, rtp_session, evt_data, msg, &source_stun_addr);
2688 				break;
2689 			case MS_TURN_METHOD_ALLOCATE:
2690 				ms_message("ice: Recv TURN allocate success response: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2691 				ice_handle_received_turn_allocate_success_response(cl, rtp_session, evt_data, msg, &source_stun_addr);
2692 				break;
2693 			case MS_TURN_METHOD_CREATE_PERMISSION:
2694 				ms_message("ice: Recv TURN create permission success response: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2695 				ice_handle_received_create_permission_success_response(cl, rtp_session, evt_data, msg, &source_stun_addr);
2696 				break;
2697 			case MS_TURN_METHOD_REFRESH:
2698 				ms_message("ice: Recv TURN refresh success response: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2699 				ice_handle_received_turn_refresh_success_response(cl, rtp_session, evt_data, msg, &source_stun_addr);
2700 				break;
2701 			case MS_TURN_METHOD_CHANNEL_BIND:
2702 				ms_message("ice: Recv TURN channel bind success response: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2703 				ice_handle_received_turn_channel_bind_success_response(cl, rtp_session, evt_data, msg, &source_stun_addr);
2704 				break;
2705 			default:
2706 				ms_warning("ice: Recv unknown STUN success response: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2707 				break;
2708 		}
2709 
2710 	} else if (ms_stun_message_is_error_response(msg)) {
2711 		ice_set_transaction_response_time(cl, &tr_id, evt_data->ts);
2712 		ms_message("ice: Recv error response: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2713 		ice_handle_received_error_response(cl, rtp_session, evt_data, msg);
2714 	} else if (ms_stun_message_is_indication(msg)) {
2715 		ms_message("ice: Recv indication: %s <-- %s [%s]", recv_addr_str, source_addr_str, tr_id_str);
2716 	} else {
2717 		ms_warning("ice: STUN message type not handled");
2718 	}
2719 
2720 	ms_stun_message_destroy(msg);
2721 }
2722 
2723 
2724 /******************************************************************************
2725  * ADD CANDIDATES                                                             *
2726  *****************************************************************************/
2727 
ice_candidate_new(const char * type,int family,const char * ip,int port,uint16_t componentID)2728 static IceCandidate * ice_candidate_new(const char *type, int family, const char *ip, int port, uint16_t componentID)
2729 {
2730 	IceCandidate *candidate;
2731 	IceCandidateType candidate_type;
2732 
2733 	if (strcmp(type, "host") == 0) {
2734 		candidate_type = ICT_HostCandidate;
2735 	}
2736 	else if (strcmp(type, "srflx") == 0) {
2737 		candidate_type = ICT_ServerReflexiveCandidate;
2738 	}
2739 	else if (strcmp(type, "prflx") == 0) {
2740 		candidate_type = ICT_PeerReflexiveCandidate;
2741 	}
2742 	else if (strcmp(type, "relay") == 0) {
2743 		candidate_type = ICT_RelayedCandidate;
2744 	}
2745 	else {
2746 		ms_error("ice: Invalid candidate type");
2747 		return NULL;
2748 	}
2749 
2750 	candidate = ms_new0(IceCandidate, 1);
2751 	strncpy(candidate->taddr.ip, ip, sizeof(candidate->taddr.ip));
2752 	candidate->taddr.port = port;
2753 	candidate->taddr.family = family;
2754 	candidate->type = candidate_type;
2755 	candidate->componentID = componentID;
2756 	candidate->is_default = FALSE;
2757 
2758 	switch (candidate->type) {
2759 		case ICT_HostCandidate:
2760 			candidate->base = candidate;
2761 			break;
2762 		default:
2763 			candidate->base = NULL;
2764 			break;
2765 	}
2766 
2767 	return candidate;
2768 }
2769 
ice_compute_candidate_priority(IceCandidate * candidate)2770 static void ice_compute_candidate_priority(IceCandidate *candidate)
2771 {
2772 	// TODO: Handle local preferences for multihomed hosts.
2773 	uint8_t type_preference = type_preference_values[candidate->type];
2774 	uint16_t local_preference = 65535;	/* Value recommended for non-multihomed hosts in 4.1.2.1 */
2775 	candidate->priority = (type_preference << 24) | (local_preference << 8) | (256 - candidate->componentID);
2776 }
2777 
ice_find_componentID(const uint16_t * cid1,const uint16_t * cid2)2778 static int ice_find_componentID(const uint16_t *cid1, const uint16_t *cid2)
2779 {
2780 	return !(*cid1 == *cid2);
2781 }
2782 
ice_add_componentID(bctbx_list_t ** list,uint16_t * componentID)2783 static void ice_add_componentID(bctbx_list_t **list, uint16_t *componentID)
2784 {
2785 	bctbx_list_t *elem = bctbx_list_find_custom(*list, (bctbx_compare_func)ice_find_componentID, componentID);
2786 	if (elem == NULL) {
2787 		*list = bctbx_list_append(*list, componentID);
2788 	}
2789 }
2790 
ice_remove_componentID(bctbx_list_t ** list,uint16_t componentID)2791 static void ice_remove_componentID(bctbx_list_t **list, uint16_t componentID){
2792 	*list = bctbx_list_remove_custom(*list, (bctbx_compare_func)ice_find_componentID, &componentID);
2793 }
2794 
ice_add_local_candidate(IceCheckList * cl,const char * type,int family,const char * ip,int port,uint16_t componentID,IceCandidate * base)2795 IceCandidate * ice_add_local_candidate(IceCheckList* cl, const char* type, int family, const char* ip, int port, uint16_t componentID, IceCandidate* base)
2796 {
2797 	bctbx_list_t *elem;
2798 	IceCandidate *candidate;
2799 
2800 	if (bctbx_list_size(cl->local_candidates) >= ICE_MAX_NB_CANDIDATES) {
2801 		ms_error("ice: Candidate list limited to %d candidates", ICE_MAX_NB_CANDIDATES);
2802 		return NULL;
2803 	}
2804 
2805 	candidate = ice_candidate_new(type, family, ip, port, componentID);
2806 	if (candidate->base == NULL) candidate->base = base;
2807 	ice_compute_candidate_priority(candidate);
2808 
2809 	elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_compare_candidates, candidate);
2810 	if (elem != NULL) {
2811 		/* This candidate is already in the list, do not add it again. */
2812 		ms_free(candidate);
2813 		return NULL;
2814 	}
2815 
2816 	ice_add_componentID(&cl->local_componentIDs, &candidate->componentID);
2817 	cl->local_candidates = bctbx_list_append(cl->local_candidates, candidate);
2818 
2819 	return candidate;
2820 }
2821 
ice_add_remote_candidate(IceCheckList * cl,const char * type,int family,const char * ip,int port,uint16_t componentID,uint32_t priority,const char * const foundation,bool_t is_default)2822 IceCandidate * ice_add_remote_candidate(IceCheckList *cl, const char *type, int family, const char *ip, int port, uint16_t componentID, uint32_t priority, const char * const foundation, bool_t is_default)
2823 {
2824 	bctbx_list_t *elem;
2825 	IceCandidate *candidate;
2826 
2827 	if (bctbx_list_size(cl->local_candidates) >= ICE_MAX_NB_CANDIDATES) {
2828 		ms_error("ice: Candidate list limited to %d candidates", ICE_MAX_NB_CANDIDATES);
2829 		return NULL;
2830 	}
2831 
2832 	candidate = ice_candidate_new(type, family, ip, port, componentID);
2833 	/* If the priority is 0, compute it. It is used for debugging purpose in mediastream to set priorities of remote candidates. */
2834 	if (priority == 0) ice_compute_candidate_priority(candidate);
2835 	else candidate->priority = priority;
2836 
2837 	elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_compare_candidates, candidate);
2838 	if (elem != NULL) {
2839 		/* This candidate is already in the list, do not add it again. */
2840 		ms_free(candidate);
2841 		return NULL;
2842 	}
2843 
2844 	strncpy(candidate->foundation, foundation, sizeof(candidate->foundation) - 1);
2845 	candidate->is_default = is_default;
2846 	ice_add_componentID(&cl->remote_componentIDs, &candidate->componentID);
2847 	cl->remote_candidates = bctbx_list_append(cl->remote_candidates, candidate);
2848 	if (cl->session->turn_enabled) {
2849 		ComponentID_Family cf = { componentID, family };
2850 		bctbx_list_t *elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_host_candidate, &cf);
2851 		if (elem != NULL) {
2852 			IceStunServerRequest *request;
2853 			IceStunServerRequestTransaction *transaction;
2854 			IceCandidate *local_candidate = (IceCandidate *)elem->data;
2855 			RtpTransport *rtptp = NULL;
2856 			ice_get_transport_from_rtp_session_and_componentID(cl->rtp_session, componentID, &rtptp);
2857 			if (rtptp != NULL) {
2858 				MSStunAddress peer_address = ms_ip_address_to_stun_address(AF_INET, SOCK_DGRAM, ip, 3478);
2859 				if (peer_address.family == MS_STUN_ADDR_FAMILY_IPV6) peer_address.ip.v6.port = 0;
2860 				else peer_address.ip.v4.port = 0;
2861 				request = ice_stun_server_request_new(cl, ice_get_turn_context_from_check_list_componentID(cl, componentID), rtptp,
2862 					local_candidate->taddr.family, local_candidate->taddr.ip, local_candidate->taddr.port, MS_TURN_METHOD_CREATE_PERMISSION);
2863 				request->peer_address = peer_address;
2864 				request->next_transmission_time = ice_add_ms(ice_current_time(), ICE_DEFAULT_RTO_DURATION);
2865 				transaction = ice_send_stun_server_request(request, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
2866 				ice_stun_server_request_add_transaction(request, transaction);
2867 				ice_check_list_add_stun_server_request(cl, request);
2868 			}
2869 		}
2870 	}
2871 	return candidate;
2872 }
2873 
2874 
2875 /******************************************************************************
2876  * LOSING PAIRS HANDLING                                                      *
2877  *****************************************************************************/
2878 
ice_find_pair_in_valid_list(IceValidCandidatePair * valid_pair,IceCandidatePair * pair)2879 static int ice_find_pair_in_valid_list(IceValidCandidatePair *valid_pair, IceCandidatePair *pair)
2880 {
2881 	return !((ice_compare_transport_addresses(&valid_pair->valid->local->taddr, &pair->local->taddr) == 0)
2882 		&& (valid_pair->valid->local->componentID == pair->local->componentID)
2883 		&& (ice_compare_transport_addresses(&valid_pair->valid->remote->taddr, &pair->remote->taddr) == 0)
2884 		&& (valid_pair->valid->remote->componentID == pair->remote->componentID));
2885 }
2886 
ice_check_if_losing_pair_should_cause_restart(const IceCandidatePair * pair,LosingRemoteCandidate_InProgress_Failed * lif)2887 static void ice_check_if_losing_pair_should_cause_restart(const IceCandidatePair *pair, LosingRemoteCandidate_InProgress_Failed *lif)
2888 {
2889 	if (ice_compare_candidates(pair->remote, lif->losing_remote_candidate) == 0) {
2890 		if (pair->state == ICP_InProgress) lif->in_progress_candidates = TRUE;
2891 		if (pair->state == ICP_Failed) lif->failed_candidates = TRUE;
2892 	}
2893 }
2894 
ice_add_losing_pair(IceCheckList * cl,uint16_t componentID,int local_family,const char * local_addr,int local_port,int remote_family,const char * remote_addr,int remote_port)2895 void ice_add_losing_pair(IceCheckList *cl, uint16_t componentID, int local_family, const char *local_addr, int local_port, int remote_family, const char *remote_addr, int remote_port)
2896 {
2897 	IceTransportAddress taddr;
2898 	TransportAddress_ComponentID taci;
2899 	Type_ComponentID tc;
2900 	bctbx_list_t *elem;
2901 	bctbx_list_t *srflx_elem = NULL;
2902 	LocalCandidate_RemoteCandidate lr;
2903 	IceCandidatePair *pair;
2904 	IceValidCandidatePair *valid_pair;
2905 	bool_t added_missing_relay_candidate = FALSE;
2906 	char taddr_str[64];
2907 
2908 	memset(taddr_str, 0, sizeof(taddr_str));
2909 	snprintf(taddr.ip, sizeof(taddr.ip), "%s", local_addr);
2910 	taddr.port = local_port;
2911 	taddr.family = local_family;
2912 	elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_candidate_from_transport_address, &taddr);
2913 	if (elem == NULL) {
2914 		/* Workaround to detect if the local candidate that has not been found has been added by the proxy server.
2915 		   If that is the case, add it to the local candidates now. */
2916 		elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_find_candidate_from_ip_address, local_addr);
2917 		if (elem != NULL) {
2918 			tc.componentID = componentID;
2919 			tc.type = ICT_ServerReflexiveCandidate;
2920 			srflx_elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_find_candidate_from_type_and_componentID, &tc);
2921 		}
2922 		ice_transport_address_to_printable_ip_address(&taddr, taddr_str, sizeof(taddr_str));
2923 		if (srflx_elem != NULL) {
2924 			ms_message("ice: Add missing local candidate %s:relay", taddr_str);
2925 			added_missing_relay_candidate = TRUE;
2926 			lr.local = ice_add_local_candidate(cl, "relay", local_family, local_addr, local_port, componentID, srflx_elem->data);
2927 			ice_compute_candidate_foundation(lr.local, cl);
2928 		} else {
2929 			ms_warning("ice: Local candidate %s should have been found", taddr_str);
2930 			return;
2931 		}
2932 	} else {
2933 		lr.local = (IceCandidate *)elem->data;
2934 	}
2935 	snprintf(taddr.ip, sizeof(taddr.ip), "%s", remote_addr);
2936 	taddr.port = remote_port;
2937 	taddr.family = remote_family;
2938 	taci.componentID = lr.local->componentID;
2939 	taci.ta = &taddr;
2940 	elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_find_candidate_from_transport_address_and_componentID, &taci);
2941 	if (elem == NULL) {
2942 		ice_transport_address_to_printable_ip_address(&taddr, taddr_str, sizeof(taddr_str));
2943 		ms_warning("ice: Remote candidate %s should have been found", taddr_str);
2944 		return;
2945 	}
2946 	lr.remote = (IceCandidate *)elem->data;
2947 	if (added_missing_relay_candidate == TRUE) {
2948 		/* If we just added a missing relay candidate, also add the candidate pair. */
2949 		pair = ice_pair_new(cl, lr.local, lr.remote);
2950 		cl->pairs = bctbx_list_append(cl->pairs, pair);
2951 	}
2952 	elem = bctbx_list_find_custom(cl->pairs, (bctbx_compare_func)ice_find_pair_from_candidates, &lr);
2953 	if (elem == NULL) {
2954 		if (added_missing_relay_candidate == FALSE) {
2955 			/* Candidate pair has not been created but the candidates exist.
2956 			It must be that the local candidate is a reflexive or relayed candidate.
2957 			Therefore create this pair and use it. */
2958 			pair = ice_pair_new(cl, lr.local, lr.remote);
2959 			cl->pairs = bctbx_list_append(cl->pairs, pair);
2960 		} else return;
2961 	} else {
2962 		pair = (IceCandidatePair *)elem->data;
2963 	}
2964 	elem = bctbx_list_find_custom(cl->valid_list, (bctbx_compare_func)ice_find_pair_in_valid_list, pair);
2965 	if (elem == NULL) {
2966 		LosingRemoteCandidate_InProgress_Failed lif;
2967 		/* The pair has not been found in the valid list, therefore it is a losing pair. */
2968 		lif.losing_remote_candidate = pair->remote;
2969 		lif.failed_candidates = FALSE;
2970 		lif.in_progress_candidates = FALSE;
2971 		bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_check_if_losing_pair_should_cause_restart, &lif);
2972 		if ((lif.in_progress_candidates == FALSE) && (lif.failed_candidates == TRUE)) {
2973 			/* A network failure, such as a network partition or serious packet loss has most likely occured, restart ICE after some delay. */
2974 			ms_warning("ice: ICE restart is needed!");
2975 			cl->session->event_time = ice_add_ms(ice_current_time(), 1000);
2976 			cl->session->event_value = ORTP_EVENT_ICE_RESTART_NEEDED;
2977 			cl->session->send_event = TRUE;
2978 		} else if (lif.in_progress_candidates == TRUE) {
2979 			/* Wait for the in progress checks to complete. */
2980 			ms_message("ice: Added losing pair, wait for InProgress checks to complete");
2981 			elem = bctbx_list_find(cl->losing_pairs, pair);
2982 			if (elem == NULL) {
2983 				cl->losing_pairs = bctbx_list_append(cl->losing_pairs, pair);
2984 			}
2985 		}
2986 	} else {
2987 		valid_pair = (IceValidCandidatePair *)elem->data;
2988 		valid_pair->selected = TRUE;
2989 		ms_message("ice: Select losing valid pair: cl=%p, componentID=%u, local_addr=%s, local_port=%d, remote_addr=%s, remote_port=%d",
2990 			cl, componentID, local_addr, local_port, remote_addr, remote_port);
2991 	}
2992 }
2993 
ice_check_list_nb_losing_pairs(const IceCheckList * cl)2994 static int ice_check_list_nb_losing_pairs(const IceCheckList *cl)
2995 {
2996 	return (int)bctbx_list_size(cl->losing_pairs);
2997 }
2998 
ice_session_nb_losing_pairs(const IceSession * session)2999 int ice_session_nb_losing_pairs(const IceSession *session)
3000 {
3001 	int i;
3002 	int nb_losing_pairs = 0;
3003 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3004 		if (session->streams[i] != NULL)
3005 			nb_losing_pairs += ice_check_list_nb_losing_pairs(session->streams[i]);
3006 	}
3007 	return nb_losing_pairs;
3008 }
3009 
ice_check_list_unselect_valid_pairs(IceCheckList * cl)3010 void ice_check_list_unselect_valid_pairs(IceCheckList *cl)
3011 {
3012 	bctbx_list_for_each(cl->valid_list, (void (*)(void *))ice_unselect_valid_pair);
3013 }
3014 
3015 
3016 /******************************************************************************
3017  * COMPUTE CANDIDATES FOUNDATIONS                                             *
3018  *****************************************************************************/
3019 
ice_find_candidate_with_same_foundation(const IceCandidate * c1,const IceCandidate * c2)3020 static int ice_find_candidate_with_same_foundation(const IceCandidate *c1, const IceCandidate *c2)
3021 {
3022 	if ((c1 != c2) && c1->base && c2->base && (c1->type == c2->type)
3023 		&& (strlen(c1->base->taddr.ip) == strlen(c2->base->taddr.ip))
3024 		&& (strcmp(c1->base->taddr.ip, c2->base->taddr.ip) == 0))
3025 		return 0;
3026 	else return 1;
3027 }
3028 
ice_compute_candidate_foundation(IceCandidate * candidate,IceCheckList * cl)3029 static void ice_compute_candidate_foundation(IceCandidate *candidate, IceCheckList *cl)
3030 {
3031 	bctbx_list_t *l = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_candidate_with_same_foundation, candidate);
3032 	if (l != NULL) {
3033 		/* We found a candidate that should have the same foundation, so copy it from this candidate. */
3034 		IceCandidate *other_candidate = (IceCandidate *)l->data;
3035 		if (strlen(other_candidate->foundation) > 0) {
3036 			strncpy(candidate->foundation, other_candidate->foundation, sizeof(candidate->foundation) - 1);
3037 			return;
3038 		}
3039 		/* If the foundation of the other candidate is empty we need to assign a new one, so continue. */
3040 	}
3041 
3042 	/* No candidate that should have the same foundation has been found, assign a new one. */
3043 	snprintf(candidate->foundation, sizeof(candidate->foundation) - 1, "%u", cl->foundation_generator);
3044 	cl->foundation_generator++;
3045 }
3046 
ice_check_list_compute_candidates_foundations(IceCheckList * cl)3047 static void ice_check_list_compute_candidates_foundations(IceCheckList *cl)
3048 {
3049 	if (cl->state == ICL_Running) {
3050 		bctbx_list_for_each2(cl->local_candidates, (void (*)(void*,void*))ice_compute_candidate_foundation, cl);
3051 	}
3052 }
3053 
ice_session_compute_candidates_foundations(IceSession * session)3054 void ice_session_compute_candidates_foundations(IceSession *session)
3055 {
3056 	int i;
3057 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3058 		if (session->streams[i] != NULL)
3059 			ice_check_list_compute_candidates_foundations(session->streams[i]);
3060 	}
3061 }
3062 
3063 
3064 /******************************************************************************
3065  * ELIMINATE REDUNDANT CANDIDATES                                             *
3066  *****************************************************************************/
3067 
ice_find_redundant_candidate(const IceCandidate * c1,const IceCandidate * c2)3068 static int ice_find_redundant_candidate(const IceCandidate *c1, const IceCandidate *c2)
3069 {
3070 	if (c1 == c2) return 1;
3071 	return !(!ice_compare_transport_addresses(&c1->taddr, &c2->taddr) && (c1->base == c2->base));
3072 }
3073 
ice_check_list_eliminate_redundant_candidates(IceCheckList * cl)3074 static void ice_check_list_eliminate_redundant_candidates(IceCheckList *cl)
3075 {
3076 	bctbx_list_t *elem;
3077 	bctbx_list_t *other_elem;
3078 	IceCandidate *candidate;
3079 	IceCandidate *other_candidate;
3080 	bool_t elem_removed;
3081 
3082 	if (cl->state == ICL_Running) {
3083 		do {
3084 			elem_removed = FALSE;
3085 			/* Do not use bctbx_list_for_each2() here, we may remove list elements. */
3086 			for (elem = cl->local_candidates; elem != NULL; elem = elem->next) {
3087 				candidate = (IceCandidate *)elem->data;
3088 				other_elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_redundant_candidate, candidate);
3089 				if (other_elem != NULL) {
3090 					other_candidate = (IceCandidate *)other_elem->data;
3091 					if (other_candidate->priority < candidate->priority) {
3092 						ice_free_candidate(other_candidate);
3093 						cl->local_candidates = bctbx_list_erase_link(cl->local_candidates, other_elem);
3094 					} else {
3095 						ice_free_candidate(candidate);
3096 						cl->local_candidates = bctbx_list_erase_link(cl->local_candidates, elem);
3097 					}
3098 					elem_removed = TRUE;
3099 					break;
3100 				}
3101 			}
3102 		} while (elem_removed);
3103 	}
3104 }
3105 
ice_session_eliminate_redundant_candidates(IceSession * session)3106 void ice_session_eliminate_redundant_candidates(IceSession *session)
3107 {
3108 	int i;
3109 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3110 		if (session->streams[i] != NULL)
3111 			ice_check_list_eliminate_redundant_candidates(session->streams[i]);
3112 	}
3113 }
3114 
3115 
3116 /******************************************************************************
3117  * CHOOSE DEFAULT CANDIDATES                                                  *
3118  *****************************************************************************/
3119 
ice_find_candidate_from_type_and_componentID(const IceCandidate * candidate,const Type_ComponentID * tc)3120 static int ice_find_candidate_from_type_and_componentID(const IceCandidate *candidate, const Type_ComponentID *tc)
3121 {
3122 	return !((candidate->type == tc->type) && (candidate->componentID == tc->componentID));
3123 }
3124 
ice_choose_local_or_remote_default_candidates(IceCheckList * cl,bctbx_list_t * list)3125 static void ice_choose_local_or_remote_default_candidates(IceCheckList *cl, bctbx_list_t *list)
3126 {
3127 	Type_ComponentID tc;
3128 	bctbx_list_t *l;
3129 	int i,k;
3130 
3131 	/* Choose the default candidate for each componentID as defined in 4.1.4. */
3132 	for (i = ICE_MIN_COMPONENTID; i <= ICE_MAX_COMPONENTID; i++) {
3133 		tc.componentID = i;
3134 		l = NULL;
3135 		for(k = 0; k < ICT_CandidateTypeMax && cl->session->default_types[k] != ICT_CandidateInvalid; ++k){
3136 			tc.type = cl->session->default_types[k];
3137 			l = bctbx_list_find_custom(list, (bctbx_compare_func)ice_find_candidate_from_type_and_componentID, &tc);
3138 			if (l) break;
3139 		}
3140 		if (l != NULL) {
3141 			IceCandidate *candidate = (IceCandidate *)l->data;
3142 			candidate->is_default = TRUE;
3143 			if (cl->session->turn_enabled) {
3144 				ms_turn_context_set_force_rtp_sending_via_relay(ice_get_turn_context_from_check_list_componentID(cl, i), candidate->type == ICT_RelayedCandidate);
3145 			}
3146 		}
3147 	}
3148 }
3149 
ice_check_list_choose_default_candidates(IceCheckList * cl)3150 static void ice_check_list_choose_default_candidates(IceCheckList *cl)
3151 {
3152 	if (cl->state == ICL_Running) {
3153 		ice_choose_local_or_remote_default_candidates(cl, cl->local_candidates);
3154 	}
3155 }
3156 
ice_session_choose_default_candidates(IceSession * session)3157 void ice_session_choose_default_candidates(IceSession *session)
3158 {
3159 	int i;
3160 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3161 		if (session->streams[i] != NULL)
3162 			ice_check_list_choose_default_candidates(session->streams[i]);
3163 	}
3164 }
3165 
ice_check_list_choose_default_remote_candidates(IceCheckList * cl)3166 static void ice_check_list_choose_default_remote_candidates(IceCheckList *cl)
3167 {
3168 	ice_choose_local_or_remote_default_candidates(cl, cl->remote_candidates);
3169 }
3170 
ice_session_choose_default_remote_candidates(IceSession * session)3171 void ice_session_choose_default_remote_candidates(IceSession *session)
3172 {
3173 	int i;
3174 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3175 		if (session->streams[i] != NULL)
3176 			ice_check_list_choose_default_remote_candidates(session->streams[i]);
3177 	}
3178 }
3179 
3180 
3181 /******************************************************************************
3182  * FORM CANDIDATES PAIRS                                                      *
3183  *****************************************************************************/
3184 
ice_compare_pair_priorities(const IceCandidatePair * p1,const IceCandidatePair * p2)3185 static int ice_compare_pair_priorities(const IceCandidatePair *p1, const IceCandidatePair *p2)
3186 {
3187 	return (p1->priority < p2->priority);
3188 }
3189 
3190 /* Form candidate pairs, compute their priorities and sort them by decreasing priorities according to 5.7.1 and 5.7.2. */
ice_form_candidate_pairs(IceCheckList * cl)3191 static void ice_form_candidate_pairs(IceCheckList *cl)
3192 {
3193 	bctbx_list_t *local_list = cl->local_candidates;
3194 	bctbx_list_t *remote_list;
3195 	IceCandidatePair *pair;
3196 	IceCandidate *local_candidate;
3197 	IceCandidate *remote_candidate;
3198 
3199 	while (local_list != NULL) {
3200 		remote_list = cl->remote_candidates;
3201 		while (remote_list != NULL) {
3202 			local_candidate = (IceCandidate*)local_list->data;
3203 			remote_candidate = (IceCandidate*)remote_list->data;
3204 			if ((local_candidate->componentID == remote_candidate->componentID) && (local_candidate->taddr.family == remote_candidate->taddr.family)) {
3205 				pair = ice_pair_new(cl, local_candidate, remote_candidate);
3206 				cl->pairs = bctbx_list_append(cl->pairs, pair);
3207 			}
3208 			remote_list = bctbx_list_next(remote_list);
3209 		}
3210 		local_list = bctbx_list_next(local_list);
3211 	}
3212 }
3213 
ice_replace_srflx_by_base_in_pair(IceCandidatePair * pair)3214 static void ice_replace_srflx_by_base_in_pair(IceCandidatePair *pair)
3215 {
3216 	/* Replace local server reflexive candidates by their bases. */
3217 	if (pair->local->type == ICT_ServerReflexiveCandidate) {
3218 		pair->local = pair->local->base;
3219 	}
3220 }
3221 
ice_compare_transport_addresses(const IceTransportAddress * ta1,const IceTransportAddress * ta2)3222 static int ice_compare_transport_addresses(const IceTransportAddress *ta1, const IceTransportAddress *ta2)
3223 {
3224 	return !((ta1->family == ta2->family)
3225 		&& (ta1->port == ta2->port)
3226 		&& (strcmp(ta1->ip, ta2->ip) == 0));
3227 }
3228 
ice_compare_candidates(const IceCandidate * c1,const IceCandidate * c2)3229 static int ice_compare_candidates(const IceCandidate *c1, const IceCandidate *c2)
3230 {
3231 	return !((c1->type == c2->type)
3232 		&& (ice_compare_transport_addresses(&c1->taddr, &c2->taddr) == 0)
3233 		&& (c1->componentID == c2->componentID)
3234 		&& (c1->priority == c2->priority));
3235 }
3236 
ice_compare_pairs(const IceCandidatePair * p1,const IceCandidatePair * p2)3237 static int ice_compare_pairs(const IceCandidatePair *p1, const IceCandidatePair *p2)
3238 {
3239 	return !((ice_compare_candidates(p1->local, p2->local) == 0)
3240 		&& (ice_compare_candidates(p1->remote, p2->remote) == 0));
3241 }
3242 
ice_prune_duplicate_pair(IceCandidatePair * pair,bctbx_list_t ** pairs,IceCheckList * cl)3243 static int ice_prune_duplicate_pair(IceCandidatePair *pair, bctbx_list_t **pairs, IceCheckList *cl)
3244 {
3245 	bctbx_list_t *other_pair = bctbx_list_find_custom(*pairs, (bctbx_compare_func)ice_compare_pairs, pair);
3246 	if (other_pair != NULL) {
3247 		IceCandidatePair *other_candidate_pair = (IceCandidatePair *)other_pair->data;
3248 		if (other_candidate_pair->priority > pair->priority) {
3249 			/* Found duplicate with higher priority so prune current pair. */
3250 			*pairs = bctbx_list_remove(*pairs, pair);
3251 			ice_free_candidate_pair(pair, cl);
3252 			return 1;
3253 		}
3254 	}
3255 	return 0;
3256 }
3257 
ice_create_check_list(IceCandidatePair * pair,IceCheckList * cl)3258 static void ice_create_check_list(IceCandidatePair *pair, IceCheckList *cl)
3259 {
3260 	cl->check_list = bctbx_list_insert_sorted(cl->check_list, pair, (bctbx_compare_func)ice_compare_pair_priorities);
3261 }
3262 
3263 /* Prune pairs according to 5.7.3. */
ice_prune_candidate_pairs(IceCheckList * cl)3264 static void ice_prune_candidate_pairs(IceCheckList *cl)
3265 {
3266 	bctbx_list_t *list;
3267 	bctbx_list_t *next;
3268 	bctbx_list_t *prev;
3269 	int nb_pairs;
3270 	int nb_pairs_to_remove;
3271 	int i;
3272 
3273 	bctbx_list_for_each(cl->pairs, (void (*)(void*))ice_replace_srflx_by_base_in_pair);
3274 	/* Do not use bctbx_list_for_each2() here, because ice_prune_duplicate_pair() can remove list elements. */
3275 	for (list = cl->pairs; list != NULL; list = list->next) {
3276 		next = list->next;
3277 		if (ice_prune_duplicate_pair(list->data, &cl->pairs, cl)) {
3278 			if (next && next->prev) list = next->prev;
3279 			else break;	/* The end of the list has been reached, prevent accessing a wrong list->next */
3280 		}
3281 	}
3282 
3283 	/* Create the check list. */
3284 	bctbx_list_free(cl->check_list);
3285 	cl->check_list = NULL;
3286 	bctbx_list_for_each2(cl->pairs, (void (*)(void*,void*))ice_create_check_list, cl);
3287 
3288 	/* Limit the number of connectivity checks. */
3289 	nb_pairs = (int)bctbx_list_size(cl->check_list);
3290 	if (nb_pairs > cl->session->max_connectivity_checks) {
3291 		nb_pairs_to_remove = nb_pairs - cl->session->max_connectivity_checks;
3292 		list = cl->check_list;
3293 		for (i = 0; i < (nb_pairs - 1); i++) list = bctbx_list_next(list);
3294 		for (i = 0; i < nb_pairs_to_remove; i++) {
3295 			cl->pairs = bctbx_list_remove(cl->pairs, list->data);
3296 			ice_free_candidate_pair(list->data, cl);
3297 			prev = list->prev;
3298 			cl->check_list = bctbx_list_erase_link(cl->check_list, list);
3299 			list = prev;
3300 		}
3301 	}
3302 }
3303 
ice_find_pair_foundation(const IcePairFoundation * f1,const IcePairFoundation * f2)3304 static int ice_find_pair_foundation(const IcePairFoundation *f1, const IcePairFoundation *f2)
3305 {
3306 	return !((strlen(f1->local) == strlen(f2->local)) && (strcmp(f1->local, f2->local) == 0)
3307 		&& (strlen(f1->remote) == strlen(f2->remote)) && (strcmp(f1->remote, f2->remote) == 0));
3308 }
3309 
ice_generate_pair_foundations_list(const IceCandidatePair * pair,bctbx_list_t ** list)3310 static void ice_generate_pair_foundations_list(const IceCandidatePair *pair, bctbx_list_t **list)
3311 {
3312 	IcePairFoundation foundation;
3313 	IcePairFoundation *dyn_foundation;
3314 	bctbx_list_t *elem;
3315 
3316 	memset(&foundation, 0, sizeof(foundation));
3317 	strncpy(foundation.local, pair->local->foundation, sizeof(foundation.local) - 1);
3318 	strncpy(foundation.remote, pair->remote->foundation, sizeof(foundation.remote) - 1);
3319 
3320 	elem = bctbx_list_find_custom(*list, (bctbx_compare_func)ice_find_pair_foundation, &foundation);
3321 	if (elem == NULL) {
3322 		dyn_foundation = ms_new0(IcePairFoundation, 1);
3323 		memcpy(dyn_foundation, &foundation, sizeof(foundation));
3324 		*list = bctbx_list_append(*list, dyn_foundation);
3325 	}
3326 }
3327 
ice_find_lowest_componentid_pair_with_specified_foundation(IceCandidatePair * pair,Foundation_Pair_Priority_ComponentID * fc)3328 static void ice_find_lowest_componentid_pair_with_specified_foundation(IceCandidatePair *pair, Foundation_Pair_Priority_ComponentID *fc)
3329 {
3330 	if ((strlen(pair->local->foundation) == strlen(fc->foundation->local)) && (strcmp(pair->local->foundation, fc->foundation->local) == 0)
3331 		&& (strlen(pair->remote->foundation) == strlen(fc->foundation->remote)) && (strcmp(pair->remote->foundation, fc->foundation->remote) == 0)
3332 		&& ((fc->componentID == ICE_INVALID_COMPONENTID) || ((pair->local->componentID < fc->componentID) && (pair->priority > fc->priority)))) {
3333 		fc->componentID = pair->local->componentID;
3334 		fc->priority = pair->priority;
3335 		fc->pair = pair;
3336 	}
3337 }
3338 
ice_set_lowest_componentid_pair_with_foundation_to_waiting_state(const IcePairFoundation * foundation,IceCheckList * cl)3339 static void ice_set_lowest_componentid_pair_with_foundation_to_waiting_state(const IcePairFoundation *foundation, IceCheckList *cl)
3340 {
3341 	Foundation_Pair_Priority_ComponentID fc;
3342 	fc.foundation = foundation;
3343 	fc.pair = NULL;
3344 	fc.componentID = ICE_INVALID_COMPONENTID;
3345 	fc.priority = 0;
3346 	bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_find_lowest_componentid_pair_with_specified_foundation, &fc);
3347 	if (fc.pair != NULL) {
3348 		/* Set the state of the pair to Waiting. */
3349 		ice_pair_set_state(fc.pair, ICP_Waiting);
3350 	}
3351 }
3352 
3353 /* Compute pairs states according to 5.7.4. */
ice_compute_pairs_states(IceCheckList * cl)3354 static void ice_compute_pairs_states(IceCheckList *cl)
3355 {
3356 	bctbx_list_for_each2(cl->foundations, (void (*)(void*,void*))ice_set_lowest_componentid_pair_with_foundation_to_waiting_state, cl);
3357 }
3358 
ice_check_list_pair_candidates(IceCheckList * cl)3359 static void ice_check_list_pair_candidates(IceCheckList *cl)
3360 {
3361 	if (cl->state == ICL_Running) {
3362 		ice_form_candidate_pairs(cl);
3363 		ice_prune_candidate_pairs(cl);
3364 		/* Generate pair foundations list. */
3365 		bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_generate_pair_foundations_list, &cl->foundations);
3366 	}
3367 }
3368 
ice_session_pair_candidates(IceSession * session)3369 static void ice_session_pair_candidates(IceSession *session)
3370 {
3371 	IceCheckList *cl = NULL;
3372 	int i;
3373 
3374 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3375 		if ((session->streams[i] != NULL) && (ice_check_list_state(session->streams[i]) == ICL_Running)) {
3376 			cl = session->streams[i];
3377 			break;
3378 		}
3379 	}
3380 	if (cl != NULL) {
3381 		for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3382 			if (session->streams[i] != NULL)
3383 				ice_check_list_pair_candidates(session->streams[i]);
3384 		}
3385 		ice_compute_pairs_states(cl);
3386 		ice_dump_candidate_pairs_foundations(cl);
3387 		ice_dump_candidate_pairs(cl);
3388 		ice_dump_check_list(cl);
3389 	}
3390 }
3391 
ice_session_start_connectivity_checks(IceSession * session)3392 void ice_session_start_connectivity_checks(IceSession *session)
3393 {
3394 	ice_session_pair_candidates(session);
3395 	session->state = IS_Running;
3396 }
3397 
3398 
3399 /******************************************************************************
3400  * CONCLUDE ICE PROCESSING                                                    *
3401  *****************************************************************************/
3402 
ice_perform_regular_nomination(IceValidCandidatePair * valid_pair,CheckList_RtpSession * cr)3403 static void ice_perform_regular_nomination(IceValidCandidatePair *valid_pair, CheckList_RtpSession *cr)
3404 {
3405 	if (valid_pair->generated_from->use_candidate == FALSE) {
3406 		bctbx_list_t *elem = bctbx_list_find_custom(cr->cl->valid_list, (bctbx_compare_func)ice_find_use_candidate_valid_pair_from_componentID, &valid_pair->generated_from->local->componentID);
3407 		if (elem == NULL) {
3408 			if (valid_pair->valid->remote->type == ICT_RelayedCandidate) {
3409 				MSTimeSpec curtime = ice_current_time();
3410 				if (cr->cl->nomination_delay_running == FALSE) {
3411 					/* There is a potential valid pair but it is a relayed candidate, wait a little so that a better choice may be found. */
3412 					ms_message("ice: Potential relayed valid pair, wait for a better pair.");
3413 					cr->cl->nomination_delay_running = TRUE;
3414 					cr->cl->nomination_delay_start_time = ice_current_time();
3415 				} else if (ice_compare_time(curtime, cr->cl->nomination_delay_start_time) >= ICE_NOMINATION_DELAY) {
3416 					ms_message("ice: Nomination delay timeout while performing nomination, select the potential relayed candidate anyway.");
3417 					cr->cl->nomination_delay_running = FALSE;
3418 					valid_pair->generated_from->use_candidate = TRUE;
3419 					ice_check_list_queue_triggered_check(cr->cl, valid_pair->generated_from);
3420 				}
3421 			} else {
3422 				ms_message("ice: We were waiting for a better pair and found one, use it!");
3423 				cr->cl->nomination_delay_running = FALSE;
3424 				valid_pair->generated_from->use_candidate = TRUE;
3425 				ice_check_list_queue_triggered_check(cr->cl, valid_pair->generated_from);
3426 			}
3427 		}
3428 	}
3429 }
3430 
ice_remove_waiting_and_frozen_pairs_from_list(bctbx_list_t ** list,uint16_t componentID)3431 static void ice_remove_waiting_and_frozen_pairs_from_list(bctbx_list_t **list, uint16_t componentID)
3432 {
3433 	IceCandidatePair *pair;
3434 	bctbx_list_t *elem;
3435 	bctbx_list_t *next;
3436 
3437 	for (elem = *list; elem != NULL; elem = elem->next) {
3438 		pair = (IceCandidatePair *)elem->data;
3439 		if (((pair->state == ICP_Waiting) || (pair->state == ICP_Frozen)) && (pair->local->componentID == componentID)) {
3440 			next = elem->next;
3441 			*list = bctbx_list_erase_link(*list, elem);
3442 			if (next && next->prev) elem = next->prev;
3443 			else break;	/* The end of the list has been reached, prevent accessing a wrong list->next */
3444 		}
3445 	}
3446 }
3447 
ice_conclude_waiting_frozen_and_inprogress_pairs(const IceValidCandidatePair * valid_pair,IceCheckList * cl)3448 static void ice_conclude_waiting_frozen_and_inprogress_pairs(const IceValidCandidatePair *valid_pair, IceCheckList *cl)
3449 {
3450 	if (valid_pair->valid->is_nominated == TRUE) {
3451 		bctbx_list_t *elem;
3452 		ice_remove_waiting_and_frozen_pairs_from_list(&cl->check_list, valid_pair->valid->local->componentID);
3453 		ice_remove_waiting_and_frozen_pairs_from_list(&cl->triggered_checks_queue, valid_pair->valid->local->componentID);
3454 
3455 		for (elem = cl->check_list ; elem != NULL; elem = elem->next){
3456 			IceCandidatePair *pair = (IceCandidatePair*) elem->data;
3457 			if ((pair->state == ICP_InProgress) && (pair->local->componentID == valid_pair->valid->local->componentID)
3458 				&& pair->priority < valid_pair->valid->priority){
3459 				/* Set the retransmission number to the max to stop retransmissions for this pair. */
3460 				pair->retransmissions = ICE_MAX_RETRANSMISSIONS;
3461 			}
3462 		}
3463 	}
3464 }
3465 
ice_find_use_candidate_valid_pair_from_componentID(const IceValidCandidatePair * valid_pair,const uint16_t * componentID)3466 static int ice_find_use_candidate_valid_pair_from_componentID(const IceValidCandidatePair *valid_pair, const uint16_t *componentID)
3467 {
3468 	return !((valid_pair->generated_from->use_candidate == TRUE) && (valid_pair->generated_from->local->componentID == *componentID));
3469 }
3470 
ice_find_nominated_valid_pair_from_componentID(const IceValidCandidatePair * valid_pair,const uint16_t * componentID)3471 static int ice_find_nominated_valid_pair_from_componentID(const IceValidCandidatePair *valid_pair, const uint16_t *componentID)
3472 {
3473 	return !((valid_pair->valid->is_nominated == TRUE) && (valid_pair->valid->local->componentID == *componentID));
3474 }
3475 
ice_find_nominated_valid_pair_for_componentID(const uint16_t * componentID,CheckList_Bool * cb)3476 static void ice_find_nominated_valid_pair_for_componentID(const uint16_t *componentID, CheckList_Bool *cb)
3477 {
3478 	bctbx_list_t *elem = bctbx_list_find_custom(cb->cl->valid_list, (bctbx_compare_func)ice_find_nominated_valid_pair_from_componentID, componentID);
3479 	if (elem == NULL) {
3480 		/* This component ID is not present in the valid list. */
3481 		cb->result = FALSE;
3482 	}
3483 }
3484 
ice_find_selected_valid_pair_from_componentID(const IceValidCandidatePair * valid_pair,const uint16_t * componentID)3485 static int ice_find_selected_valid_pair_from_componentID(const IceValidCandidatePair *valid_pair, const uint16_t *componentID)
3486 {
3487 	return !((valid_pair->selected == TRUE) && (valid_pair->valid->local->componentID == *componentID));
3488 }
3489 
ice_find_selected_valid_pair_for_componentID(const uint16_t * componentID,CheckList_Bool * cb)3490 static void ice_find_selected_valid_pair_for_componentID(const uint16_t *componentID, CheckList_Bool *cb)
3491 {
3492 	bctbx_list_t *elem = bctbx_list_find_custom(cb->cl->valid_list, (bctbx_compare_func)ice_find_selected_valid_pair_from_componentID, componentID);
3493 	if (elem == NULL) {
3494 		/* This component ID is not present in the valid list. */
3495 		cb->result = FALSE;
3496 	}
3497 }
3498 
ice_check_all_pairs_in_failed_or_succeeded_state(const IceCandidatePair * pair,CheckList_Bool * cb)3499 static void ice_check_all_pairs_in_failed_or_succeeded_state(const IceCandidatePair *pair, CheckList_Bool *cb)
3500 {
3501 	bctbx_list_t *elem = bctbx_list_find_custom(cb->cl->check_list, (bctbx_compare_func)ice_find_not_failed_or_succeeded_pair, NULL);
3502 	if (elem != NULL) {
3503 		cb->result = FALSE;
3504 	}
3505 }
3506 
ice_pair_stop_retransmissions(IceCandidatePair * pair,IceCheckList * cl)3507 static void ice_pair_stop_retransmissions(IceCandidatePair *pair, IceCheckList *cl)
3508 {
3509 	bctbx_list_t *elem;
3510 	if (pair->state == ICP_InProgress) {
3511 		ice_pair_set_state(pair, ICP_Failed);
3512 		elem = bctbx_list_find(cl->triggered_checks_queue, pair);
3513 		if (elem != NULL) {
3514 			cl->triggered_checks_queue = bctbx_list_erase_link(cl->triggered_checks_queue, elem);
3515 		}
3516 	}
3517 }
3518 
ice_check_list_stop_retransmissions(IceCheckList * cl)3519 static void ice_check_list_stop_retransmissions(IceCheckList *cl)
3520 {
3521 	bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_pair_stop_retransmissions, cl);
3522 }
3523 
ice_session_find_running_check_list(const IceSession * session)3524 static IceCheckList * ice_session_find_running_check_list(const IceSession *session)
3525 {
3526 	int i;
3527 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3528 		if ((session->streams[i] != NULL) && (ice_check_list_state(session->streams[i]) == ICL_Running))
3529 			return session->streams[i];
3530 	}
3531 	return NULL;
3532 }
3533 
ice_session_find_unsuccessful_check_list(const IceSession * session)3534 static IceCheckList * ice_session_find_unsuccessful_check_list(const IceSession *session)
3535 {
3536 	int i;
3537 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3538 		if ((session->streams[i] != NULL) && (ice_check_list_state(session->streams[i]) != ICL_Completed))
3539 			return session->streams[i];
3540 	}
3541 	return NULL;
3542 }
3543 
ice_session_contains_check_list(const IceSession * session,const IceCheckList * cl)3544 static bool_t ice_session_contains_check_list(const IceSession *session, const IceCheckList *cl) {
3545 	int i;
3546 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3547 		if ((session->streams[i] != NULL) && (session->streams[i] == cl))
3548 			return TRUE;
3549 	}
3550 	return FALSE;
3551 }
3552 
ice_notify_session_processing_finished(IceCheckList * cl,RtpSession * rtp_session)3553 static void ice_notify_session_processing_finished(IceCheckList *cl, RtpSession *rtp_session) {
3554 	IceCheckList *next_cl;
3555 	if (ice_session_contains_check_list(cl->session, cl) == FALSE) {
3556 		ms_error("ice: Could not find check list in the session");
3557 		return;
3558 	}
3559 	next_cl = ice_session_find_running_check_list(cl->session);
3560 	if (next_cl == NULL) {
3561 		/* This was the last check list of the session. */
3562 		if (ice_session_find_unsuccessful_check_list(cl->session) == NULL) {
3563 			/* All the check lists of the session have completed successfully. */
3564 			cl->session->state = IS_Completed;
3565 		} else {
3566 			/* Some check lists have failed, consider the session to be a failure. */
3567 			cl->session->state = IS_Failed;
3568 		}
3569 		cl->session->event_time = ice_add_ms(ice_current_time(), 1000);
3570 		cl->session->event_value = ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED;
3571 		cl->session->send_event = TRUE;
3572 	}
3573 }
3574 
ice_check_list_create_turn_channel(IceCheckList * cl,RtpTransport * rtptp,struct sockaddr * local_addr,socklen_t local_addrlen,IceTransportAddress * remote_taddr,uint16_t componentID)3575 static void ice_check_list_create_turn_channel(IceCheckList *cl, RtpTransport *rtptp, struct sockaddr *local_addr, socklen_t local_addrlen, IceTransportAddress *remote_taddr, uint16_t componentID) {
3576 	IceStunServerRequestTransaction *transaction;
3577 	IceStunServerRequest *request;
3578 	MSTurnContext *turn_context = ice_get_turn_context_from_check_list_componentID(cl, componentID);
3579 	MSStunAddress peer_address = ice_transport_address_to_stun_address(remote_taddr);
3580 	char local_ip[64];
3581 	int local_port = 0;
3582 
3583 	bctbx_sockaddr_to_ip_address(local_addr, local_addrlen, local_ip, sizeof(local_ip), &local_port);
3584 	request = ice_stun_server_request_new(cl, turn_context, rtptp, local_addr->sa_family, local_ip, local_port, MS_TURN_METHOD_CHANNEL_BIND);
3585 	request->peer_address = peer_address;
3586 	request->channel_number = 0x4000 | componentID;
3587 	ms_turn_context_set_channel_number(turn_context, request->channel_number);
3588 	ms_turn_context_set_state(turn_context, MS_TURN_CONTEXT_STATE_BINDING_CHANNEL);
3589 	request->next_transmission_time = ice_add_ms(ice_current_time(), ICE_DEFAULT_RTO_DURATION);
3590 	transaction = ice_send_stun_server_request(request, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
3591 	ice_stun_server_request_add_transaction(request, transaction);
3592 	ice_check_list_add_stun_server_request(cl, request);
3593 }
3594 
3595 /* Conclude ICE processing as defined in 8.1. */
ice_conclude_processing(IceCheckList * cl,RtpSession * rtp_session)3596 static void ice_conclude_processing(IceCheckList *cl, RtpSession *rtp_session)
3597 {
3598 	CheckList_RtpSession cr;
3599 	CheckList_Bool cb;
3600 	OrtpEvent *ev;
3601 	int nb_losing_pairs = 0;
3602 	IceCandidate *rtp_local_candidate = NULL;
3603 	IceCandidate *rtcp_local_candidate = NULL;
3604 	IceCandidate *rtp_remote_candidate = NULL;
3605 	IceCandidate *rtcp_remote_candidate = NULL;
3606 	RtpTransport *rtptp;
3607 
3608 	if (cl->state == ICL_Running) {
3609 		if (cl->session->role == IR_Controlling) {
3610 			/* Perform regular nomination for valid pairs. */
3611 			cr.cl = cl;
3612 			cr.rtp_session = rtp_session;
3613 			bctbx_list_for_each2(cl->valid_list, (void (*)(void*,void*))ice_perform_regular_nomination, &cr);
3614 		}
3615 
3616 		bctbx_list_for_each2(cl->valid_list, (void (*)(void*,void*))ice_conclude_waiting_frozen_and_inprogress_pairs, cl);
3617 
3618 		cb.cl = cl;
3619 		cb.result = TRUE;
3620 		bctbx_list_for_each2(cl->local_componentIDs, (void (*)(void*,void*))ice_find_nominated_valid_pair_for_componentID, &cb);
3621 		if (cb.result == TRUE) {
3622 			nb_losing_pairs = ice_check_list_nb_losing_pairs(cl);
3623 			if ((cl->state != ICL_Completed) && (nb_losing_pairs == 0)) {
3624 				bool_t result;
3625 				cl->state = ICL_Completed;
3626 				cl->nomination_delay_running = FALSE;
3627 				ice_check_list_select_candidates(cl);
3628 				ms_message("ice: Finished ICE check list [%p] processing successfully!",cl);
3629 				ice_dump_valid_list(cl);
3630 				/* Initialise keepalive time. */
3631 				cl->keepalive_time = ice_current_time();
3632 				/*don't stop retransmissions for the controlled side, so that we get a chance to complete the pairs that the remote has selected.*/
3633 				if (cl->session->role == IR_Controlling) ice_check_list_stop_retransmissions(cl);
3634 				result = ice_check_list_selected_valid_remote_candidate(cl, &rtp_remote_candidate, &rtcp_remote_candidate);
3635 				if (result == TRUE) {
3636 					rtp_session_set_remote_addr_full(rtp_session, rtp_remote_candidate->taddr.ip, rtp_remote_candidate->taddr.port, rtcp_remote_candidate->taddr.ip, rtcp_remote_candidate->taddr.port);
3637 					if (cl->session->turn_enabled) {
3638 						ice_check_list_selected_valid_local_candidate(cl, &rtp_local_candidate, &rtcp_local_candidate);
3639 						if (rtp_local_candidate) {
3640 							ms_turn_context_set_force_rtp_sending_via_relay(ice_get_turn_context_from_check_list_componentID(cl, 1), rtp_local_candidate->type == ICT_RelayedCandidate);
3641 							if (rtp_local_candidate->type == ICT_RelayedCandidate) {
3642 								rtp_session_get_transports(cl->rtp_session, &rtptp, NULL);
3643 								ice_check_list_create_turn_channel(cl, rtptp, (struct sockaddr *)&cl->rtp_session->rtp.gs.loc_addr, cl->rtp_session->rtp.gs.loc_addrlen, &rtp_remote_candidate->taddr, 1);
3644 							} else {
3645 								ice_check_list_deallocate_rtp_turn_candidate(cl);
3646 							}
3647 						}
3648 						if (rtcp_local_candidate) {
3649 							ms_turn_context_set_force_rtp_sending_via_relay(ice_get_turn_context_from_check_list_componentID(cl, 2), rtcp_local_candidate->type == ICT_RelayedCandidate);
3650 							if (rtcp_local_candidate->type == ICT_RelayedCandidate) {
3651 								rtp_session_get_transports(cl->rtp_session, NULL, &rtptp);
3652 								ice_check_list_create_turn_channel(cl, rtptp, (struct sockaddr *)&cl->rtp_session->rtcp.gs.loc_addr, cl->rtp_session->rtcp.gs.loc_addrlen, &rtcp_remote_candidate->taddr, 2);
3653 							} else {
3654 								ice_check_list_deallocate_rtcp_turn_candidate(cl);
3655 							}
3656 						}
3657 					}
3658 				} else {
3659 					ms_error("Cannot get remote candidate for check list [%p]",cl);
3660 				}
3661 				/* Notify the application of the successful processing. */
3662 				ev = ortp_event_new(ORTP_EVENT_ICE_CHECK_LIST_PROCESSING_FINISHED);
3663 				ortp_event_get_data(ev)->info.ice_processing_successful = TRUE;
3664 				rtp_session_dispatch_event(rtp_session, ev);
3665 				ice_notify_session_processing_finished(cl, rtp_session);
3666 			}
3667 		} else {
3668 			cb.cl = cl;
3669 			cb.result = TRUE;
3670 			bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_check_all_pairs_in_failed_or_succeeded_state, &cb);
3671 			if (cb.result == TRUE) {
3672 				if (cl->state != ICL_Failed) {
3673 					cl->state = ICL_Failed;
3674 					ms_message("ice: Failed ICE check list processing!");
3675 					ice_dump_valid_list(cl);
3676 					/* Notify the application of the failed processing. */
3677 					ev = ortp_event_new(ORTP_EVENT_ICE_CHECK_LIST_PROCESSING_FINISHED);
3678 					ortp_event_get_data(ev)->info.ice_processing_successful = FALSE;
3679 					rtp_session_dispatch_event(rtp_session, ev);
3680 					ice_notify_session_processing_finished(cl, rtp_session);
3681 				}
3682 			}
3683 		}
3684 	}
3685 }
3686 
3687 
3688 /******************************************************************************
3689  * RESTART ICE PROCESSING                                                     *
3690  *****************************************************************************/
3691 
ice_check_list_restart(IceCheckList * cl)3692 static void ice_check_list_restart(IceCheckList *cl)
3693 {
3694 	if (cl->remote_ufrag) ms_free(cl->remote_ufrag);
3695 	if (cl->remote_pwd) ms_free(cl->remote_pwd);
3696 	cl->remote_ufrag = cl->remote_pwd = NULL;
3697 
3698 	bctbx_list_for_each(cl->stun_server_requests, (void (*)(void*))ice_stun_server_request_free);
3699 	bctbx_list_for_each(cl->transaction_list, (void (*)(void*))ice_free_transaction);
3700 	bctbx_list_for_each(cl->foundations, (void (*)(void*))ice_free_pair_foundation);
3701 	bctbx_list_for_each2(cl->pairs, (void (*)(void*,void*))ice_free_candidate_pair, cl);
3702 	bctbx_list_for_each(cl->valid_list, (void (*)(void*))ice_free_valid_pair);
3703 	bctbx_list_for_each(cl->remote_candidates, (void (*)(void*))ice_free_candidate);
3704 	bctbx_list_free(cl->stun_server_requests);
3705 	bctbx_list_free(cl->transaction_list);
3706 	bctbx_list_free(cl->foundations);
3707 	bctbx_list_free(cl->remote_componentIDs);
3708 	bctbx_list_free(cl->valid_list);
3709 	bctbx_list_free(cl->check_list);
3710 	bctbx_list_free(cl->triggered_checks_queue);
3711 	bctbx_list_free(cl->losing_pairs);
3712 	bctbx_list_free(cl->pairs);
3713 	bctbx_list_free(cl->remote_candidates);
3714 	cl->stun_server_requests = cl->foundations = cl->remote_componentIDs = NULL;
3715 	cl->valid_list = cl->check_list = cl->triggered_checks_queue = cl->losing_pairs = cl->pairs = cl->remote_candidates = cl->transaction_list = NULL;
3716 	cl->state = ICL_Running;
3717 	cl->mismatch = FALSE;
3718 	cl->gathering_candidates = FALSE;
3719 	cl->gathering_finished = FALSE;
3720 	cl->nomination_delay_running = FALSE;
3721 	cl->ta_time = ice_current_time();
3722 	memset(&cl->keepalive_time, 0, sizeof(cl->keepalive_time));
3723 	memset(&cl->gathering_start_time, 0, sizeof(cl->gathering_start_time));
3724 	memset(&cl->nomination_delay_start_time, 0, sizeof(cl->nomination_delay_start_time));
3725 }
3726 
ice_session_restart(IceSession * session,IceRole role)3727 void ice_session_restart(IceSession *session, IceRole role){
3728 	int i;
3729 
3730 	ms_warning("ICE session restart");
3731 	if (session->local_ufrag) ms_free(session->local_ufrag);
3732 	if (session->local_pwd) ms_free(session->local_pwd);
3733 	if (session->remote_ufrag) ms_free(session->remote_ufrag);
3734 	if (session->remote_pwd) ms_free(session->remote_pwd);
3735 
3736 	session->state = IS_Stopped;
3737 	session->tie_breaker = generate_tie_breaker();
3738 	session->local_ufrag = generate_ufrag();
3739 	session->local_pwd = generate_pwd();
3740 	session->remote_ufrag = NULL;
3741 	session->remote_pwd = NULL;
3742 	memset(&session->event_time, 0, sizeof(session->event_time));
3743 	session->send_event = FALSE;
3744 
3745 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3746 		if (session->streams[i] != NULL)
3747 			ice_check_list_restart(session->streams[i]);
3748 	}
3749 	ice_session_set_role(session, role);
3750 }
3751 
ice_session_reset(IceSession * session,IceRole role)3752 void ice_session_reset(IceSession *session, IceRole role) {
3753 	int i;
3754 
3755 	ice_session_restart(session, role);
3756 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3757 		IceCheckList *cl = session->streams[i];
3758 		if (cl != NULL) {
3759 			cl->local_candidates = bctbx_list_free_with_data(cl->local_candidates, (bctbx_list_free_func)ice_free_candidate);
3760 			bctbx_list_free(cl->local_componentIDs);
3761 			cl->local_componentIDs = NULL;
3762 		}
3763 	}
3764 }
3765 
3766 /******************************************************************************
3767  * GLOBAL PROCESS                                                             *
3768  *****************************************************************************/
3769 
ice_find_gathering_stun_server_request(const IceStunServerRequest * request)3770 static int ice_find_gathering_stun_server_request(const IceStunServerRequest *request) {
3771 	return request->gathering == FALSE;
3772 }
3773 
ice_remove_gathering_stun_server_requests(IceCheckList * cl)3774 static void ice_remove_gathering_stun_server_requests(IceCheckList *cl) {
3775 	bctbx_list_t *elem = cl->stun_server_requests;
3776 	while (elem != NULL) {
3777 		elem = bctbx_list_find_custom(cl->stun_server_requests, (bctbx_compare_func)ice_find_gathering_stun_server_request, NULL);
3778 		if (elem != NULL) {
3779 			IceStunServerRequest *request = (IceStunServerRequest *)elem->data;
3780 			ice_stun_server_request_free(request);
3781 			cl->stun_server_requests = bctbx_list_erase_link(cl->stun_server_requests, elem);
3782 		}
3783 	}
3784 }
3785 
ice_check_list_stop_gathering(IceCheckList * cl)3786 static void ice_check_list_stop_gathering(IceCheckList *cl) {
3787 	cl->gathering_candidates = FALSE;
3788 	cl->gathering_finished = TRUE;
3789 	ice_check_list_sum_gathering_round_trip_times(cl);
3790 	ice_remove_gathering_stun_server_requests(cl);
3791 }
3792 
3793 
ice_check_gathering_timeout(IceCheckList * cl,RtpSession * rtp_session,MSTimeSpec curtime)3794 static bool_t ice_check_gathering_timeout(IceCheckList *cl, RtpSession *rtp_session, MSTimeSpec curtime)
3795 {
3796 	OrtpEvent *ev;
3797 	IceCheckList *cl_it;
3798 	int i;
3799 	bool_t timeout = FALSE;
3800 
3801 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3802 		cl_it = cl->session->streams[i];
3803 		if ((cl_it != NULL)
3804 			&& (cl_it->gathering_candidates == TRUE)
3805 			&& (ice_compare_time(curtime, cl_it->gathering_start_time) >= ICE_GATHERING_CANDIDATES_TIMEOUT)) {
3806 			timeout = TRUE;
3807 			break;
3808 		}
3809 	}
3810 	if (timeout == TRUE) {
3811 		for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
3812 			if (cl_it->session->streams[i] != NULL)
3813 				ice_check_list_stop_gathering(cl_it->session->streams[i]);
3814 		}
3815 		/* Notify the application that the gathering process has timed out. */
3816 		ev = ortp_event_new(ORTP_EVENT_ICE_GATHERING_FINISHED);
3817 		ortp_event_get_data(ev)->info.ice_processing_successful = FALSE;
3818 		rtp_session_dispatch_event(rtp_session, ev);
3819 	}
3820 	return timeout;
3821 }
3822 
ice_send_stun_server_requests(IceStunServerRequest * request,IceCheckList * cl)3823 static void ice_send_stun_server_requests(IceStunServerRequest *request, IceCheckList *cl)
3824 {
3825 	IceStunServerRequestTransaction *transaction = NULL;
3826 	MSTimeSpec curtime = ice_current_time();
3827 
3828 	if ((request->responded == FALSE) && (ice_compare_time(curtime, request->next_transmission_time) >= 0)) {
3829 		if (bctbx_list_size(request->transactions) < ICE_MAX_STUN_REQUEST_RETRANSMISSIONS) {
3830 			request->next_transmission_time = ice_add_ms(curtime, ICE_DEFAULT_RTO_DURATION);
3831 			transaction = ice_send_stun_server_request(request, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
3832 			if (transaction != NULL) {
3833 				ice_stun_server_request_add_transaction(request, transaction);
3834 			} else {
3835 				request->to_remove = TRUE;
3836 			}
3837 		}
3838 	}
3839 }
3840 
ice_handle_connectivity_check_retransmission(IceCandidatePair * pair,const CheckList_RtpSession_Time * params)3841 static void ice_handle_connectivity_check_retransmission(IceCandidatePair *pair, const CheckList_RtpSession_Time *params)
3842 {
3843 	if ((pair->state == ICP_InProgress) && (ice_compare_time(params->time, pair->transmission_time) >= pair->rto)) {
3844 		ice_send_binding_request(params->cl, pair, params->rtp_session);
3845 	}
3846 }
3847 
ice_find_pair_from_state(const IceCandidatePair * pair,const IceCandidatePairState * state)3848 static int ice_find_pair_from_state(const IceCandidatePair *pair, const IceCandidatePairState *state)
3849 {
3850 	return !(pair->state == *state);
3851 }
3852 
ice_check_retransmissions_pending(const IceCandidatePair * pair,bool_t * retransmissions_pending)3853 static void ice_check_retransmissions_pending(const IceCandidatePair *pair, bool_t *retransmissions_pending)
3854 {
3855 	if ((pair->state == ICP_InProgress) && (pair->retransmissions <= ICE_MAX_RETRANSMISSIONS))
3856 		*retransmissions_pending = TRUE;
3857 }
3858 
ice_check_list_retransmit_connectivity_checks(IceCheckList * cl,RtpSession * rtp_session,MSTimeSpec curtime)3859 static void ice_check_list_retransmit_connectivity_checks(IceCheckList *cl, RtpSession *rtp_session, MSTimeSpec curtime)
3860 {
3861 	CheckList_RtpSession_Time params;
3862 	params.cl = cl;
3863 	params.rtp_session = rtp_session;
3864 	params.time = curtime;
3865 	bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_handle_connectivity_check_retransmission, &params);
3866 }
3867 
ice_check_list_send_triggered_check(IceCheckList * cl,RtpSession * rtp_session)3868 static IceCandidatePair *ice_check_list_send_triggered_check(IceCheckList *cl, RtpSession *rtp_session)
3869 {
3870 	IceCandidatePair *pair = ice_check_list_pop_triggered_check(cl);
3871 	if (pair != NULL) {
3872 		ice_send_binding_request(cl, pair, rtp_session);
3873 	}
3874 	return pair;
3875 }
3876 
3877 /* Schedule checks as defined in 5.8. */
ice_check_list_process(IceCheckList * cl,RtpSession * rtp_session)3878 void ice_check_list_process(IceCheckList *cl, RtpSession *rtp_session)
3879 {
3880 	IceCandidatePairState state;
3881 	IceCandidatePair *pair;
3882 	bctbx_list_t *elem;
3883 	MSTimeSpec curtime;
3884 	bool_t retransmissions_pending = FALSE;
3885 
3886 	if (cl->session == NULL) return;
3887 	curtime = ice_current_time();
3888 
3889 	/* Check for gathering timeout */
3890 	if ((cl->gathering_candidates == TRUE) && ice_check_gathering_timeout(cl, rtp_session, curtime)) {
3891 		ms_message("ice: Gathering timeout for checklist [%p]", cl);
3892 	}
3893 
3894 	/* Send STUN/TURN server requests (to gather candidates, create/refresh TURN permissions, refresh TURN allocations or bind TURN channels). */
3895 	bctbx_list_for_each2(cl->stun_server_requests, (void (*)(void*,void*))ice_send_stun_server_requests, cl);
3896 	cl->stun_server_requests = bctbx_list_remove_custom(cl->stun_server_requests, (bctbx_compare_func)ice_compare_stun_server_requests_to_remove, NULL);
3897 
3898 	/* Send event if needed. */
3899 	if ((cl->session->send_event == TRUE) && (ice_compare_time(curtime, cl->session->event_time) >= 0)) {
3900 		OrtpEvent *ev;
3901 		cl->session->send_event = FALSE;
3902 		ev = ortp_event_new(cl->session->event_value);
3903 		ortp_event_get_data(ev)->info.ice_processing_successful = (cl->session->state == IS_Completed);
3904 		rtp_session_dispatch_event(rtp_session, ev);
3905 	}
3906 
3907 	if ((cl->session->state == IS_Stopped) || (cl->session->state == IS_Failed)) return;
3908 
3909 	switch (cl->state) {
3910 		case ICL_Completed:
3911 			/* Handle keepalive. */
3912 			if (ice_compare_time(curtime, cl->keepalive_time) >= (cl->session->keepalive_timeout * 1000)) {
3913 				ice_send_keepalive_packets(cl, rtp_session);
3914 				cl->keepalive_time = curtime;
3915 			}
3916 			/* Check if some retransmissions are needed. */
3917 			ice_check_list_retransmit_connectivity_checks(cl, rtp_session, curtime);
3918 			if (ice_compare_time(curtime, cl->ta_time) < cl->session->ta) return;
3919 			cl->ta_time = curtime;
3920 			/* Send a triggered connectivity check if there is one. */
3921 			if (ice_check_list_send_triggered_check(cl, rtp_session) != NULL) return;
3922 			break;
3923 		case ICL_Running:
3924 			/* Check nomination delay. */
3925 			if ((cl->nomination_delay_running == TRUE) && (ice_compare_time(curtime, cl->nomination_delay_start_time) >= ICE_NOMINATION_DELAY)) {
3926 				ms_message("ice: Nomination delay timeout, select the potential relayed candidate anyway.");
3927 				ice_conclude_processing(cl, rtp_session);
3928 				if (cl->session->state == IS_Completed) return;
3929 			}
3930 			/* Check if some retransmissions are needed. */
3931 			ice_check_list_retransmit_connectivity_checks(cl, rtp_session, curtime);
3932 			if (ice_compare_time(curtime, cl->ta_time) < cl->session->ta) return;
3933 			cl->ta_time = curtime;
3934 			/* Send a triggered connectivity check if there is one. */
3935 			if (ice_check_list_send_triggered_check(cl, rtp_session) != NULL) return;
3936 
3937 			/* Send ordinary connectivity checks only when the check list is Running and active. */
3938 			if (ice_check_list_is_frozen(cl)) {
3939 				ice_compute_pairs_states(cl); /* Begin processing on this check list. */
3940 			} else {
3941 				/* Send an ordinary connectivity check for the pair in the Waiting state and with the highest priority if there is one. */
3942 				state = ICP_Waiting;
3943 				elem = bctbx_list_find_custom(cl->check_list, (bctbx_compare_func)ice_find_pair_from_state, &state);
3944 				if (elem != NULL) {
3945 					pair = (IceCandidatePair *)elem->data;
3946 					ice_send_binding_request(cl, pair, rtp_session);
3947 					return;
3948 				}
3949 
3950 				/* Send an ordinary connectivity check for the pair in the Frozen state and with the highest priority if there is one. */
3951 				state = ICP_Frozen;
3952 				elem = bctbx_list_find_custom(cl->check_list, (bctbx_compare_func)ice_find_pair_from_state, &state);
3953 				if (elem != NULL) {
3954 					pair = (IceCandidatePair *)elem->data;
3955 					ice_send_binding_request(cl, pair, rtp_session);
3956 					return;
3957 				}
3958 
3959 				/* Check if there are some retransmissions pending. */
3960 				bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_check_retransmissions_pending, &retransmissions_pending);
3961 				if (retransmissions_pending == FALSE) {
3962 					ms_message("ice: There is no connectivity check left to be sent and no retransmissions pending, concluding checklist [%p]",cl);
3963 					ice_conclude_processing(cl, rtp_session);
3964 				}
3965 			}
3966 			break;
3967 		case ICL_Failed:
3968 			/* Nothing to be done. */
3969 			break;
3970 	}
3971 }
3972 
3973 /******************************************************************************
3974  * OTHER FUNCTIONS                                                            *
3975  *****************************************************************************/
3976 
ice_current_time(void)3977 static MSTimeSpec ice_current_time(void)
3978 {
3979 	MSTimeSpec cur_time;
3980 	ms_get_cur_time(&cur_time);
3981 	return cur_time;
3982 }
3983 
ice_add_ms(MSTimeSpec orig,uint32_t ms)3984 static MSTimeSpec ice_add_ms(MSTimeSpec orig, uint32_t ms)
3985 {
3986 	if (ms == 0) return orig;
3987 	orig.tv_sec += ms / 1000;
3988 	orig.tv_nsec += (ms % 1000) * 1000000;
3989 	return orig;
3990 }
3991 
ice_compare_time(MSTimeSpec ts1,MSTimeSpec ts2)3992 static int32_t ice_compare_time(MSTimeSpec ts1, MSTimeSpec ts2)
3993 {
3994 	int32_t ms = (int32_t)((ts1.tv_sec - ts2.tv_sec) * 1000);
3995 	ms += (int32_t)((ts1.tv_nsec - ts2.tv_nsec) / 1000000);
3996 	return ms;
3997 }
3998 
transactionID2string(const UInt96 * tr_id,char * tr_id_str)3999 static void transactionID2string(const UInt96 *tr_id, char *tr_id_str)
4000 {
4001 	int j, pos;
4002 
4003 	for (j = 0, pos = 0; j < 12; j++) {
4004 		pos += sprintf(&tr_id_str[pos], "%02x", ((unsigned char *)tr_id)[j]);
4005 	}
4006 	tr_id_str[pos] = '\0';
4007 }
4008 
ice_set_credentials(char ** ufrag,char ** pwd,const char * ufrag_str,const char * pwd_str)4009 static void ice_set_credentials(char **ufrag, char **pwd, const char *ufrag_str, const char *pwd_str)
4010 {
4011 	size_t len_ufrag = MIN(strlen(ufrag_str), ICE_MAX_UFRAG_LEN);
4012 	size_t len_pwd = MIN(strlen(pwd_str), ICE_MAX_PWD_LEN);
4013 
4014 	if (*ufrag) ms_free(*ufrag);
4015 	if (*pwd) ms_free(*pwd);
4016 	*ufrag=ms_strdup(ufrag_str);
4017 	*pwd=ms_strdup(pwd_str);
4018 	(*ufrag)[len_ufrag] = '\0';
4019 	(*pwd)[len_pwd] = '\0';
4020 }
4021 
ice_find_host_candidate(const IceCandidate * candidate,const ComponentID_Family * cf)4022 static int ice_find_host_candidate(const IceCandidate *candidate, const ComponentID_Family *cf) {
4023 	if ((candidate->type == ICT_HostCandidate) && (candidate->componentID == cf->componentID) && (candidate->taddr.family == cf->family)) return 0;
4024 	else return 1;
4025 }
4026 
ice_set_base_for_srflx_candidate(IceCandidate * candidate,IceCandidate * base)4027 static void ice_set_base_for_srflx_candidate(IceCandidate *candidate, IceCandidate *base)
4028 {
4029 	if ((candidate->type == ICT_ServerReflexiveCandidate) && (candidate->base == NULL) && (candidate->componentID == base->componentID))
4030 		candidate->base = base;
4031 }
4032 
ice_set_base_for_srflx_candidate_with_componentID(uint16_t * componentID,IceCheckList * cl)4033 static void ice_set_base_for_srflx_candidate_with_componentID(uint16_t *componentID, IceCheckList *cl)
4034 {
4035 	IceCandidate *base;
4036 	ComponentID_Family cf = { *componentID, AF_INET };
4037 	bctbx_list_t *elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_host_candidate, &cf);
4038 	if (elem != NULL) {
4039 		base = (IceCandidate *)elem->data;
4040 		bctbx_list_for_each2(cl->local_candidates, (void (*)(void*,void*))ice_set_base_for_srflx_candidate, (void *)base);
4041 	}
4042 }
4043 
ice_check_list_set_base_for_srflx_candidates(IceCheckList * cl)4044 static void ice_check_list_set_base_for_srflx_candidates(IceCheckList *cl)
4045 {
4046 	bctbx_list_for_each2(cl->local_componentIDs, (void (*)(void*,void*))ice_set_base_for_srflx_candidate_with_componentID, cl);
4047 }
4048 
ice_session_set_base_for_srflx_candidates(IceSession * session)4049 void ice_session_set_base_for_srflx_candidates(IceSession *session)
4050 {
4051 	int i;
4052 	for (i = 0; i < ICE_SESSION_MAX_CHECK_LISTS; i++) {
4053 		if (session->streams[i] != NULL)
4054 			ice_check_list_set_base_for_srflx_candidates(session->streams[i]);
4055 	}
4056 }
4057 
ice_find_candidate_with_componentID(const IceCandidate * candidate,const uint16_t * componentID)4058 static int ice_find_candidate_with_componentID(const IceCandidate *candidate, const uint16_t *componentID)
4059 {
4060 	if (candidate->componentID == *componentID) return 0;
4061 	else return 1;
4062 }
4063 
ice_check_list_remove_rtcp_candidates(IceCheckList * cl)4064 void ice_check_list_remove_rtcp_candidates(IceCheckList *cl)
4065 {
4066 	bctbx_list_t *elem;
4067 	uint16_t rtcp_componentID = ICE_RTCP_COMPONENT_ID;
4068 
4069 	ice_remove_componentID(&cl->local_componentIDs, rtcp_componentID);
4070 
4071 	while ((elem = bctbx_list_find_custom(cl->local_candidates, (bctbx_compare_func)ice_find_candidate_with_componentID, &rtcp_componentID)) != NULL) {
4072 		IceCandidate *candidate = (IceCandidate *)elem->data;
4073 		cl->local_candidates = bctbx_list_remove(cl->local_candidates, candidate);
4074 		ice_free_candidate(candidate);
4075 	}
4076 	ice_remove_componentID(&cl->remote_componentIDs, rtcp_componentID);
4077 	while ((elem = bctbx_list_find_custom(cl->remote_candidates, (bctbx_compare_func)ice_find_candidate_with_componentID, &rtcp_componentID)) != NULL) {
4078 		IceCandidate *candidate = (IceCandidate *)elem->data;
4079 		cl->remote_candidates = bctbx_list_remove(cl->remote_candidates, candidate);
4080 		ice_free_candidate(candidate);
4081 	}
4082 }
4083 
4084 
4085 /******************************************************************************
4086  * RESULT ACCESSORS                                                           *
4087  *****************************************************************************/
4088 
ice_get_valid_pair_for_componentID(const uint16_t * componentID,CheckList_MSListPtr * cm)4089 static void ice_get_valid_pair_for_componentID(const uint16_t *componentID, CheckList_MSListPtr *cm)
4090 {
4091 	bctbx_list_t *elem = bctbx_list_find_custom(cm->cl->valid_list, (bctbx_compare_func)ice_find_nominated_valid_pair_from_componentID, componentID);
4092 	if (elem != NULL) {
4093 		IceValidCandidatePair *valid_pair = (IceValidCandidatePair *)elem->data;
4094 		*cm->list = bctbx_list_append(*cm->list, valid_pair->valid);
4095 	}
4096 }
4097 
ice_get_valid_pairs(const IceCheckList * cl)4098 static bctbx_list_t * ice_get_valid_pairs(const IceCheckList *cl)
4099 {
4100 	CheckList_MSListPtr cm;
4101 	bctbx_list_t *valid_pairs = NULL;
4102 
4103 	cm.cl = cl;
4104 	cm.list = &valid_pairs;
4105 	bctbx_list_for_each2(cl->local_componentIDs, (void (*)(void*,void*))ice_get_valid_pair_for_componentID, &cm);
4106 	return valid_pairs;
4107 }
4108 
ice_get_remote_transport_addresses_from_valid_pair(const IceCandidatePair * pair,TransportAddresses * taddrs)4109 static void ice_get_remote_transport_addresses_from_valid_pair(const IceCandidatePair *pair, TransportAddresses *taddrs)
4110 {
4111 	if (pair->local->componentID == 1) {
4112 		*(taddrs->rtp_taddr) = &pair->remote->taddr;
4113 	} else if (pair->local->componentID == 2) {
4114 		*(taddrs->rtcp_taddr) = &pair->remote->taddr;
4115 	}
4116 }
4117 
ice_get_remote_transport_addresses_from_valid_pairs(const IceCheckList * cl,IceTransportAddress ** rtp_taddr,IceTransportAddress ** rtcp_taddr)4118 void ice_get_remote_transport_addresses_from_valid_pairs(const IceCheckList *cl, IceTransportAddress **rtp_taddr, IceTransportAddress **rtcp_taddr)
4119 {
4120 	TransportAddresses taddrs;
4121 	bctbx_list_t *ice_pairs = ice_get_valid_pairs(cl);
4122 	taddrs.rtp_taddr = rtp_taddr;
4123 	taddrs.rtcp_taddr = rtcp_taddr;
4124 	bctbx_list_for_each2(ice_pairs, (void (*)(void*,void*))ice_get_remote_transport_addresses_from_valid_pair, &taddrs);
4125 	bctbx_list_free(ice_pairs);
4126 }
4127 
ice_get_local_transport_address_from_valid_pair(const IceCandidatePair * pair,TransportAddresses * taddrs)4128 static void ice_get_local_transport_address_from_valid_pair(const IceCandidatePair *pair, TransportAddresses *taddrs)
4129 {
4130 	if (pair->local->componentID == 1) {
4131 		*(taddrs->rtp_taddr) = &pair->local->taddr;
4132 	} else if (pair->local->componentID == 2) {
4133 		*(taddrs->rtcp_taddr) = &pair->local->taddr;
4134 	}
4135 }
4136 
ice_get_local_transport_addresses_from_valid_pairs(const IceCheckList * cl,IceTransportAddress ** rtp_taddr,IceTransportAddress ** rtcp_taddr)4137 static void ice_get_local_transport_addresses_from_valid_pairs(const IceCheckList *cl, IceTransportAddress **rtp_taddr, IceTransportAddress **rtcp_taddr)
4138 {
4139 	TransportAddresses taddrs;
4140 	bctbx_list_t *ice_pairs = ice_get_valid_pairs(cl);
4141 	taddrs.rtp_taddr = rtp_taddr;
4142 	taddrs.rtcp_taddr = rtcp_taddr;
4143 	bctbx_list_for_each2(ice_pairs, (void (*)(void*,void*))ice_get_local_transport_address_from_valid_pair, &taddrs);
4144 	bctbx_list_free(ice_pairs);
4145 }
4146 
ice_check_list_print_route(const IceCheckList * cl,const char * message)4147 void ice_check_list_print_route(const IceCheckList *cl, const char *message)
4148 {
4149 	char local_rtp_addr[64], local_rtcp_addr[64];
4150 	char remote_rtp_addr[64], remote_rtcp_addr[64];
4151 	IceTransportAddress *local_rtp_taddr = NULL;
4152 	IceTransportAddress *local_rtcp_taddr = NULL;
4153 	IceTransportAddress *remote_rtp_taddr = NULL;
4154 	IceTransportAddress *remote_rtcp_taddr = NULL;
4155 
4156 	if (cl->state == ICL_Completed) {
4157 		ice_get_local_transport_addresses_from_valid_pairs(cl, &local_rtp_taddr, &local_rtcp_taddr);
4158 		ice_get_remote_transport_addresses_from_valid_pairs(cl, &remote_rtp_taddr, &remote_rtcp_taddr);
4159 		ice_transport_address_to_printable_ip_address(local_rtp_taddr, local_rtp_addr, sizeof(local_rtp_addr));
4160 		ice_transport_address_to_printable_ip_address(local_rtcp_taddr, local_rtcp_addr, sizeof(local_rtcp_addr));
4161 		ice_transport_address_to_printable_ip_address(remote_rtp_taddr, remote_rtp_addr, sizeof(remote_rtp_addr));
4162 		ice_transport_address_to_printable_ip_address(remote_rtcp_taddr, remote_rtcp_addr, sizeof(remote_rtcp_addr));
4163 		ms_message("%s", message);
4164 		ms_message("\tRTP: %s --> %s", local_rtp_addr, remote_rtp_addr);
4165 		ms_message("\tRTCP: %s --> %s", local_rtcp_addr, remote_rtcp_addr);
4166 	}
4167 }
4168 
4169 /******************************************************************************
4170  * DEBUG FUNCTIONS                                                            *
4171  *****************************************************************************/
4172 
ice_dump_session(const IceSession * session)4173 void ice_dump_session(const IceSession* session)
4174 {
4175 	if (session == NULL) return;
4176 	ms_message("Session:\n"
4177 		"\trole=%s tie-breaker=%" PRIx64 "\n"
4178 		"\tlocal_ufrag=%s local_pwd=%s\n\tremote_ufrag=%s remote_pwd=%s",
4179 		role_values[session->role], session->tie_breaker, session->local_ufrag, session->local_pwd, session->remote_ufrag, session->remote_pwd);
4180 }
4181 
ice_dump_candidate(const IceCandidate * candidate,const char * const prefix)4182 static void ice_dump_candidate(const IceCandidate *candidate, const char * const prefix)
4183 {
4184 	ms_message("%s[%p]: %stype=%s ip=%s port=%u componentID=%d priority=%u foundation=%s base=%p", prefix, candidate,
4185 		((candidate->is_default == TRUE) ? "* " : "  "),
4186 		candidate_type_values[candidate->type], candidate->taddr.ip, candidate->taddr.port,
4187 		candidate->componentID, candidate->priority, candidate->foundation, candidate->base);
4188 }
4189 
ice_dump_candidates(const IceCheckList * cl)4190 void ice_dump_candidates(const IceCheckList* cl)
4191 {
4192 	if (cl == NULL) return;
4193 	ms_message("Local candidates:");
4194 	bctbx_list_for_each2(cl->local_candidates, (void (*)(void*,void*))ice_dump_candidate, "\t");
4195 	ms_message("Remote candidates:");
4196 	bctbx_list_for_each2(cl->remote_candidates, (void (*)(void*,void*))ice_dump_candidate, "\t");
4197 }
4198 
ice_dump_candidate_pair(const IceCandidatePair * pair,int * i)4199 static void ice_dump_candidate_pair(const IceCandidatePair *pair, int *i)
4200 {
4201 	ms_message("\t%d [%p]: %sstate=%s use=%d nominated=%d priority=%" PRIu64, *i, pair, ((pair->is_default == TRUE) ? "* " : "  "),
4202 		candidate_pair_state_values[pair->state], pair->use_candidate, pair->is_nominated, pair->priority);
4203 	ice_dump_candidate(pair->local, "\t\tLocal: ");
4204 	ice_dump_candidate(pair->remote, "\t\tRemote: ");
4205 	(*i)++;
4206 }
4207 
ice_dump_candidate_pairs(const IceCheckList * cl)4208 void ice_dump_candidate_pairs(const IceCheckList* cl)
4209 {
4210 	int i = 1;
4211 	if (cl == NULL) return;
4212 	ms_message("Candidate pairs:");
4213 	bctbx_list_for_each2(cl->pairs, (void (*)(void*,void*))ice_dump_candidate_pair, (void*)&i);
4214 }
4215 
ice_dump_candidate_pair_foundation(const IcePairFoundation * foundation)4216 static void ice_dump_candidate_pair_foundation(const IcePairFoundation *foundation)
4217 {
4218 	ms_message("\t%s\t%s", foundation->local, foundation->remote);
4219 }
4220 
ice_dump_candidate_pairs_foundations(const IceCheckList * cl)4221 void ice_dump_candidate_pairs_foundations(const IceCheckList* cl)
4222 {
4223 	if (cl == NULL) return;
4224 	ms_message("Candidate pairs foundations:");
4225 	bctbx_list_for_each(cl->foundations, (void (*)(void*))ice_dump_candidate_pair_foundation);
4226 }
4227 
ice_dump_valid_pair(const IceValidCandidatePair * valid_pair,int * i)4228 static void ice_dump_valid_pair(const IceValidCandidatePair *valid_pair, int *i)
4229 {
4230 	int j = *i;
4231 	ice_dump_candidate_pair(valid_pair->valid, &j);
4232 	if (valid_pair->selected) {
4233 		ms_message("\t--> selected");
4234 	}
4235 	*i = j;
4236 }
4237 
ice_dump_valid_list(const IceCheckList * cl)4238 void ice_dump_valid_list(const IceCheckList* cl)
4239 {
4240 	int i = 1;
4241 	if (cl == NULL) return;
4242 	ms_message("Valid list:");
4243 	bctbx_list_for_each2(cl->valid_list, (void (*)(void*,void*))ice_dump_valid_pair, &i);
4244 }
4245 
ice_dump_check_list(const IceCheckList * cl)4246 void ice_dump_check_list(const IceCheckList* cl)
4247 {
4248 	int i = 1;
4249 	if (cl == NULL) return;
4250 	ms_message("Check list:");
4251 	bctbx_list_for_each2(cl->check_list, (void (*)(void*,void*))ice_dump_candidate_pair, (void*)&i);
4252 }
4253 
ice_dump_triggered_checks_queue(const IceCheckList * cl)4254 void ice_dump_triggered_checks_queue(const IceCheckList* cl)
4255 {
4256 	int i = 1;
4257 	if (cl == NULL) return;
4258 	ms_message("Triggered checks queue:");
4259 	bctbx_list_for_each2(cl->triggered_checks_queue, (void (*)(void*,void*))ice_dump_candidate_pair, (void*)&i);
4260 }
4261 
ice_dump_componentID(const uint16_t * componentID)4262 static void ice_dump_componentID(const uint16_t *componentID)
4263 {
4264 	ms_message("\t%u", *componentID);
4265 }
4266 
ice_dump_componentIDs(const IceCheckList * cl)4267 void ice_dump_componentIDs(const IceCheckList* cl)
4268 {
4269 	if (cl == NULL) return;
4270 	ms_message("Component IDs:");
4271 	bctbx_list_for_each(cl->local_componentIDs, (void (*)(void*))ice_dump_componentID);
4272 }
ice_check_list_state_to_string(const IceCheckListState state)4273 const char* ice_check_list_state_to_string(const IceCheckListState state) {
4274 	switch (state) {
4275 		case 	ICL_Running: return "ICL_Running";
4276 		case 	ICL_Completed: return "ICL_Completed";
4277 		case 	ICL_Failed: return "ICL_Failed";
4278 	}
4279 	return "Invalid ICE state";
4280 }
4281