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, ¶ms);
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