ice.c 125 KB
Newer Older
Ghislain MARY's avatar
Ghislain MARY committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Belledonne Communications

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/


#if !defined(WIN32) && !defined(_WIN32_WCE)
#ifdef __APPLE__
#include <sys/types.h>
#endif
#include <sys/socket.h>
#include <netdb.h>
#endif

Ghislain MARY's avatar
Ghislain MARY committed
29 30
#include <inttypes.h>

Ghislain MARY's avatar
Ghislain MARY committed
31
#include "mediastreamer2/ice.h"
32
#include "ortp/ortp.h"
Ghislain MARY's avatar
Ghislain MARY committed
33 34


35 36 37
#define ICE_MAX_NB_CANDIDATES		10
#define ICE_MAX_NB_CANDIDATE_PAIRS	(ICE_MAX_NB_CANDIDATES*ICE_MAX_NB_CANDIDATES)

Ghislain MARY's avatar
Ghislain MARY committed
38 39
#define ICE_MIN_COMPONENTID		1
#define ICE_MAX_COMPONENTID		256
40
#define ICE_INVALID_COMPONENTID		0
Ghislain MARY's avatar
Ghislain MARY committed
41 42
#define ICE_MAX_UFRAG_LEN		256
#define ICE_MAX_PWD_LEN			256
Ghislain MARY's avatar
Ghislain MARY committed
43 44
#define ICE_DEFAULT_TA_DURATION		40	/* In milliseconds */
#define ICE_DEFAULT_RTO_DURATION	200	/* In milliseconds */
Ghislain MARY's avatar
Ghislain MARY committed
45
#define ICE_DEFAULT_KEEPALIVE_TIMEOUT   15	/* In seconds */
46
#define ICE_GATHERING_CANDIDATES_TIMEOUT	2500	/* In milliseconds */
47
#define ICE_NOMINATION_DELAY		1000	/* In milliseconds */
48
#define ICE_MAX_RETRANSMISSIONS		7
49
#define ICE_MAX_STUN_REQUEST_RETRANSMISSIONS	7
Ghislain MARY's avatar
Ghislain MARY committed
50

51

52 53 54 55 56
typedef struct _Type_ComponentID {
	IceCandidateType type;
	uint16_t componentID;
} Type_ComponentID;

57 58
typedef struct _Foundation_Pair_Priority_ComponentID {
	const IcePairFoundation *foundation;
59 60 61
	IceCandidatePair *pair;
	uint64_t priority;
	uint16_t componentID;
62
} Foundation_Pair_Priority_ComponentID;
63

64 65
typedef struct _CheckList_RtpSession {
	IceCheckList *cl;
66
	const RtpSession *rtp_session;
67 68
} CheckList_RtpSession;

69 70
typedef struct _CheckList_RtpSession_Time {
	IceCheckList *cl;
71
	const RtpSession *rtp_session;
Ghislain MARY's avatar
Ghislain MARY committed
72
	MSTimeSpec time;
73 74
} CheckList_RtpSession_Time;

75 76 77 78 79
typedef struct _CheckList_Bool {
	IceCheckList *cl;
	bool_t result;
} CheckList_Bool;

80
typedef struct _CheckList_MSListPtr {
81
	const IceCheckList *cl;
82 83 84
	MSList **list;
} CheckList_MSListPtr;

85 86 87 88 89
typedef struct _LocalCandidate_RemoteCandidate {
	IceCandidate *local;
	IceCandidate *remote;
} LocalCandidate_RemoteCandidate;

90
typedef struct _Addr_Ports {
91 92
	char *rtp_addr;
	char *rtcp_addr;
93 94 95 96 97
	int addr_len;
	int *rtp_port;
	int *rtcp_port;
} Addr_Ports;

98
typedef struct _Time_Bool {
Ghislain MARY's avatar
Ghislain MARY committed
99
	MSTimeSpec time;
100 101 102
	bool_t result;
} Time_Bool;

103 104 105 106 107
typedef struct _Session_Index {
	IceSession *session;
	int index;
} Session_Index;

108 109 110 111 112 113
typedef struct _LosingRemoteCandidate_InProgress_Failed {
	const IceCandidate *losing_remote_candidate;
	bool_t in_progress_candidates;
	bool_t failed_candidates;
} LosingRemoteCandidate_InProgress_Failed;

114 115 116 117 118
typedef struct _StunRequestRoundTripTime {
	int nb_responses;
	int sum;
} StunRequestRoundTripTime;

119

Ghislain MARY's avatar
Ghislain MARY committed
120 121
static MSTimeSpec ice_current_time(void);
static MSTimeSpec ice_add_ms(MSTimeSpec orig, uint32_t ms);
122
static int32_t ice_compare_time(MSTimeSpec ts1, MSTimeSpec ts2);
123
static char * ice_inet_ntoa(struct sockaddr *addr, int addrlen, char *dest, int destlen);
Ghislain MARY's avatar
Ghislain MARY committed
124
static void transactionID2string(const UInt96 *tr_id, char *tr_id_str);
125
static void ice_send_stun_server_binding_request(ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check);
126
static int ice_compare_transport_addresses(const IceTransportAddress *ta1, const IceTransportAddress *ta2);
127
static int ice_compare_pair_priorities(const IceCandidatePair *p1, const IceCandidatePair *p2);
128 129
static int ice_compare_pairs(const IceCandidatePair *p1, const IceCandidatePair *p2);
static int ice_compare_candidates(const IceCandidate *c1, const IceCandidate *c2);
130
static int ice_find_host_candidate(const IceCandidate *candidate, const uint16_t *componentID);
131
static int ice_find_candidate_from_type_and_componentID(const IceCandidate *candidate, const Type_ComponentID *tc);
132
static int ice_find_use_candidate_valid_pair_from_componentID(const IceValidCandidatePair* valid_pair, const uint16_t* componentID);
133
static int ice_find_nominated_valid_pair_from_componentID(const IceValidCandidatePair* valid_pair, const uint16_t* componentID);
134
static int ice_find_selected_valid_pair_from_componentID(const IceValidCandidatePair* valid_pair, const uint16_t* componentID);
135
static void ice_find_selected_valid_pair_for_componentID(const uint16_t *componentID, CheckList_Bool *cb);
136
static int ice_find_running_check_list(const IceCheckList *cl);
137
static int ice_find_pair_in_valid_list(IceValidCandidatePair *valid_pair, IceCandidatePair *pair);
138
static void ice_pair_set_state(IceCandidatePair *pair, IceCandidatePairState state);
139
static void ice_compute_candidate_foundation(IceCandidate *candidate, IceCheckList *cl);
Ghislain MARY's avatar
Ghislain MARY committed
140
static void ice_set_credentials(char **ufrag, char **pwd, const char *ufrag_str, const char *pwd_str);
141
static void ice_conclude_processing(IceCheckList* cl, RtpSession* rtp_session);
Ghislain MARY's avatar
Ghislain MARY committed
142 143


144 145 146 147
/******************************************************************************
 * CONSTANTS DEFINITIONS                                                      *
 *****************************************************************************/

148 149
uint32_t stun_magic_cookie = 0x2112A442;

Ghislain MARY's avatar
Ghislain MARY committed
150 151 152 153 154
static const char * const role_values[] = {
	"Controlling",	/* IR_Controlling */
	"Controlled",	/* IR_Controlled */
};

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
static const char * const candidate_type_values[] = {
	"host",		/* ICT_HostCandidate */
	"srflx",	/* ICT_ServerReflexiveCandidate */
	"prflx",	/* ICT_PeerReflexiveCandidate */
	"relay"		/* ICT_RelayedCandidate */
};

/**
 * ICE candidate type preference values as recommended in 4.1.1.2.
 */
static const uint8_t type_preference_values[] = {
	126,	/* ICT_HostCandidate */
	100,	/* ICT_ServerReflexiveCandidate */
	110,	/* ICT_PeerReflexiveCandidate */
	0	/* ICT_RelayedCandidate */
};

172 173 174 175 176 177 178 179 180 181
static const char * const candidate_pair_state_values[] = {
	"Waiting",	/* ICP_Waiting */
	"In-Progress",	/* ICP_InProgress */
	"Succeeded",	/* ICP_Succeeded */
	"Failed",	/* ICP_Failed */
	"Frozen"	/* ICP_Frozen */
};


/******************************************************************************
Ghislain MARY's avatar
Ghislain MARY committed
182 183 184
 * SESSION INITIALISATION AND DEINITIALISATION                                *
 *****************************************************************************/

Ghislain MARY's avatar
Ghislain MARY committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
static uint64_t generate_tie_breaker(void)
{
	return (((uint64_t)random()) << 32) | (((uint64_t)random()) & 0xffffffff);
}

static char * generate_ufrag(void)
{
	char *ufrag = ms_malloc(9);
	sprintf(ufrag, "%08lx", random());
	ufrag[8] = '\0';
	return ufrag;
}

static char * generate_pwd(void)
{
	char *pwd = ms_malloc(25);
	sprintf(pwd, "%08lx%08lx%08lx", random(), random(), random());
	pwd[24] = '\0';
	return pwd;
}

Ghislain MARY's avatar
Ghislain MARY committed
206 207 208
static void ice_session_init(IceSession *session)
{
	session->streams = NULL;
Ghislain MARY's avatar
Ghislain MARY committed
209
	session->state = IS_Stopped;
Ghislain MARY's avatar
Ghislain MARY committed
210
	session->role = IR_Controlling;
Ghislain MARY's avatar
Ghislain MARY committed
211
	session->tie_breaker = generate_tie_breaker();
212
	session->ta = ICE_DEFAULT_TA_DURATION;
Ghislain MARY's avatar
Ghislain MARY committed
213
	session->keepalive_timeout = ICE_DEFAULT_KEEPALIVE_TIMEOUT;
Ghislain MARY's avatar
Ghislain MARY committed
214
	session->max_connectivity_checks = ICE_MAX_NB_CANDIDATE_PAIRS;
Ghislain MARY's avatar
Ghislain MARY committed
215 216
	session->local_ufrag = generate_ufrag();
	session->local_pwd = generate_pwd();
Ghislain MARY's avatar
Ghislain MARY committed
217 218
	session->remote_ufrag = NULL;
	session->remote_pwd = NULL;
Ghislain MARY's avatar
Ghislain MARY committed
219
	memset(&session->event_time, 0, sizeof(session->event_time));
220
	session->send_event = FALSE;
221 222
	session->gathering_start_ts.tv_sec = session->gathering_start_ts.tv_nsec = -1;
	session->gathering_end_ts.tv_sec = session->gathering_end_ts.tv_nsec = -1;
Ghislain MARY's avatar
Ghislain MARY committed
223 224 225 226 227 228
}

IceSession * ice_session_new(void)
{
	IceSession *session = ms_new(IceSession, 1);
	if (session == NULL) {
229 230 231
		ms_error("ice: Memory allocation of ICE session failed");
		return NULL;
	}
Ghislain MARY's avatar
Ghislain MARY committed
232 233 234 235 236 237
	ice_session_init(session);
	return session;
}

void ice_session_destroy(IceSession *session)
{
238 239 240 241 242 243 244 245 246
	if (session != NULL) {
		ms_list_for_each(session->streams, (void (*)(void*))ice_check_list_destroy);
		if (session->local_ufrag) ms_free(session->local_ufrag);
		if (session->local_pwd) ms_free(session->local_pwd);
		if (session->remote_ufrag) ms_free(session->remote_ufrag);
		if (session->remote_pwd) ms_free(session->remote_pwd);
		ms_list_free(session->streams);
		ms_free(session);
	}
Ghislain MARY's avatar
Ghislain MARY committed
247 248 249 250 251
}


/******************************************************************************
 * CHECK LIST INITIALISATION AND DEINITIALISATION                             *
252
 *****************************************************************************/
253

254 255
static void ice_check_list_init(IceCheckList *cl)
{
Ghislain MARY's avatar
Ghislain MARY committed
256
	cl->session = NULL;
257
	cl->rtp_session = NULL;
Ghislain MARY's avatar
Ghislain MARY committed
258
	cl->remote_ufrag = cl->remote_pwd = NULL;
259
	cl->stun_server_checks = NULL;
Ghislain MARY's avatar
Ghislain MARY committed
260
	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;
Ghislain MARY's avatar
Ghislain MARY committed
261
	cl->local_componentIDs = cl->remote_componentIDs = cl->foundations = NULL;
262
	cl->state = ICL_Running;
263
	cl->foundation_generator = 1;
Ghislain MARY's avatar
Ghislain MARY committed
264
	cl->mismatch = FALSE;
265
	cl->gathering_candidates = FALSE;
266
	cl->gathering_finished = FALSE;
267 268 269 270 271
	cl->nomination_delay_running = FALSE;
	memset(&cl->ta_time, 0, sizeof(cl->ta_time));
	memset(&cl->keepalive_time, 0, sizeof(cl->keepalive_time));
	memset(&cl->gathering_start_time, 0, sizeof(cl->gathering_start_time));
	memset(&cl->nomination_delay_start_time, 0, sizeof(cl->nomination_delay_start_time));
272 273
}

274
IceCheckList * ice_check_list_new(void)
275 276 277 278 279 280 281
{
	IceCheckList *cl = ms_new(IceCheckList, 1);
	if (cl == NULL) {
		ms_error("ice_check_list_new: Memory allocation failed");
		return NULL;
	}
	ice_check_list_init(cl);
282 283 284
	return cl;
}

285
static void ice_compute_pair_priority(IceCandidatePair *pair, const IceRole *role)
286 287
{
	/* Use formula defined in 5.7.2 to compute pair priority. */
Ghislain MARY's avatar
Ghislain MARY committed
288 289
	uint64_t G = 0;
	uint64_t D = 0;
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305

	switch (*role) {
		case IR_Controlling:
			G = pair->local->priority;
			D = pair->remote->priority;
			break;
		case IR_Controlled:
			G = pair->remote->priority;
			D = pair->local->priority;
			break;
	}
	pair->priority = (MIN(G, D) << 32) | (MAX(G, D) << 1) | (G > D ? 1 : 0);
}

static IceCandidatePair *ice_pair_new(IceCheckList *cl, IceCandidate* local_candidate, IceCandidate *remote_candidate)
{
306
	IceCandidatePair *pair = ms_new0(IceCandidatePair, 1);
307 308
	pair->local = local_candidate;
	pair->remote = remote_candidate;
309
	pair->state = ICP_Frozen;
310 311
	pair->is_default = FALSE;
	pair->is_nominated = FALSE;
312
	pair->use_candidate = FALSE;
313
	pair->wait_transaction_timeout = FALSE;
314 315 316 317 318 319 320 321 322
	if ((pair->local->is_default == TRUE) && (pair->remote->is_default == TRUE)) pair->is_default = TRUE;
	else pair->is_default = FALSE;
	pair->rto = ICE_DEFAULT_RTO_DURATION;
	pair->retransmissions = 0;
	pair->role = cl->session->role;
	ice_compute_pair_priority(pair, &cl->session->role);
	return pair;
}

323 324 325 326 327
static void ice_free_stun_server_check_transaction(IceStunServerCheckTransaction *transaction)
{
	ms_free(transaction);
}

328 329
static void ice_free_stun_server_check(IceStunServerCheck *check)
{
330
	ms_list_for_each(check->transactions, (void (*)(void*))ice_free_stun_server_check_transaction);
331 332 333
	ms_free(check);
}

Ghislain MARY's avatar
Ghislain MARY committed
334 335 336 337 338
static void ice_free_transaction(IceTransaction *transaction)
{
	ms_free(transaction);
}

339 340 341 342 343
static void ice_free_pair_foundation(IcePairFoundation *foundation)
{
	ms_free(foundation);
}

344 345 346 347 348
static void ice_free_valid_pair(IceValidCandidatePair *valid_pair)
{
	ms_free(valid_pair);
}

349
static void ice_free_candidate_pair(IceCandidatePair *pair, IceCheckList *cl)
Ghislain MARY's avatar
Ghislain MARY committed
350
{
351 352 353 354 355 356
	MSList *elem;
	while ((elem = ms_list_find(cl->check_list, pair)) != NULL) {
		cl->check_list = ms_list_remove(cl->check_list, pair);
	}
	while ((elem = ms_list_find_custom(cl->valid_list, (MSCompareFunc)ice_find_pair_in_valid_list, pair)) != NULL) {
		ice_free_valid_pair(elem->data);
357
		cl->valid_list = ms_list_remove_link(cl->valid_list, elem);
358
	}
Ghislain MARY's avatar
Ghislain MARY committed
359 360 361
	ms_free(pair);
}

362 363 364 365 366
static void ice_free_candidate(IceCandidate *candidate)
{
	ms_free(candidate);
}

367 368
void ice_check_list_destroy(IceCheckList *cl)
{
Ghislain MARY's avatar
Ghislain MARY committed
369 370
	if (cl->remote_ufrag) ms_free(cl->remote_ufrag);
	if (cl->remote_pwd) ms_free(cl->remote_pwd);
371
	ms_list_for_each(cl->stun_server_checks, (void (*)(void*))ice_free_stun_server_check);
Ghislain MARY's avatar
Ghislain MARY committed
372
	ms_list_for_each(cl->transaction_list, (void (*)(void*))ice_free_transaction);
373
	ms_list_for_each(cl->foundations, (void (*)(void*))ice_free_pair_foundation);
374
	ms_list_for_each2(cl->pairs, (void (*)(void*,void*))ice_free_candidate_pair, cl);
375
	ms_list_for_each(cl->valid_list, (void (*)(void*))ice_free_valid_pair);
376 377
	ms_list_for_each(cl->remote_candidates, (void (*)(void*))ice_free_candidate);
	ms_list_for_each(cl->local_candidates, (void (*)(void*))ice_free_candidate);
378
	ms_list_free(cl->stun_server_checks);
Ghislain MARY's avatar
Ghislain MARY committed
379
	ms_list_free(cl->transaction_list);
380
	ms_list_free(cl->foundations);
Ghislain MARY's avatar
Ghislain MARY committed
381 382
	ms_list_free(cl->local_componentIDs);
	ms_list_free(cl->remote_componentIDs);
Ghislain MARY's avatar
Ghislain MARY committed
383
	ms_list_free(cl->valid_list);
384
	ms_list_free(cl->check_list);
385
	ms_list_free(cl->triggered_checks_queue);
386
	ms_list_free(cl->losing_pairs);
387 388 389
	ms_list_free(cl->pairs);
	ms_list_free(cl->remote_candidates);
	ms_list_free(cl->local_candidates);
390
	memset(cl, 0, sizeof(IceCheckList));
391 392 393 394
	ms_free(cl);
}


395 396 397 398
/******************************************************************************
 * CANDIDATE ACCESSORS                                                        *
 *****************************************************************************/

399
const char *ice_candidate_type(const IceCandidate *candidate)
400 401 402 403
{
	return candidate_type_values[candidate->type];
}

404 405 406 407 408 409 410 411 412 413 414 415
/******************************************************************************
 * CANDIDATE PAIR ACCESSORS                                                   *
 *****************************************************************************/

static void ice_pair_set_state(IceCandidatePair *pair, IceCandidatePairState state)
{
	if (pair->state != state) {
		pair->state = state;
	}
}


416 417 418 419
/******************************************************************************
 * CHECK LIST ACCESSORS                                                       *
 *****************************************************************************/

420
IceCheckListState ice_check_list_state(const IceCheckList* cl)
421 422 423 424
{
	return cl->state;
}

425
static int ice_find_check_list_from_state(const IceCheckList *cl, const IceCheckListState *state)
426
{
427
	return (cl->state != *state);
428 429
}

430 431
void ice_check_list_set_state(IceCheckList *cl, IceCheckListState state)
{
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
	IceCheckListState check_state;

	if (cl->state != state) {
		cl->state = state;
		check_state = ICL_Running;
		if (ms_list_find_custom(cl->session->streams, (MSCompareFunc)ice_find_check_list_from_state, &check_state) == NULL) {
			check_state = ICL_Failed;
			if (ms_list_find_custom(cl->session->streams, (MSCompareFunc)ice_find_check_list_from_state, &check_state) != NULL) {
				/* Set the state of the session to Failed if at least one check list is in the Failed state. */
				cl->session->state = IS_Failed;
			} else {
				/* All the check lists are in the Completed state, set the state of the session to Completed. */
				cl->session->state = IS_Completed;
			}
		}
447
	}
448 449
}

450 451 452 453 454
void ice_check_list_set_rtp_session(IceCheckList *cl, RtpSession *rtp_session)
{
	cl->rtp_session = rtp_session;
}

455
const char * ice_check_list_local_ufrag(const IceCheckList* cl)
Ghislain MARY's avatar
Ghislain MARY committed
456 457 458 459 460
{
	/* Do not handle media specific ufrag for the moment, so use the session local ufrag. */
	return cl->session->local_ufrag;
}

461
const char * ice_check_list_local_pwd(const IceCheckList* cl)
Ghislain MARY's avatar
Ghislain MARY committed
462 463 464 465 466
{
	/* Do not handle media specific pwd for the moment, so use the session local pwd. */
	return cl->session->local_pwd;
}

467
const char * ice_check_list_remote_ufrag(const IceCheckList* cl)
Ghislain MARY's avatar
Ghislain MARY committed
468 469 470 471 472
{
	if (cl->remote_ufrag) return cl->remote_ufrag;
	else return cl->session->remote_ufrag;
}

473
const char * ice_check_list_remote_pwd(const IceCheckList* cl)
Ghislain MARY's avatar
Ghislain MARY committed
474 475 476 477 478
{
	if (cl->remote_pwd) return cl->remote_pwd;
	else return cl->session->remote_pwd;
}

479
static int ice_find_default_local_candidate(const IceCandidate *candidate, const uint16_t *componentID)
480
{
481
	return !((candidate->componentID == *componentID) && (candidate->is_default == TRUE));
482 483
}

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
bool_t ice_check_list_remote_credentials_changed(IceCheckList *cl, const char *ufrag, const char *pwd)
{
	const char *old_ufrag;
	const char *old_pwd;
	if ((cl->remote_ufrag == NULL) || (cl->remote_pwd == NULL)) {
		if (cl->remote_ufrag == NULL) old_ufrag = cl->session->remote_ufrag;
		else old_ufrag = cl->remote_ufrag;
		if ((strlen(ufrag) != strlen(old_ufrag)) || (strcmp(ufrag, old_ufrag) != 0)) return TRUE;
		if (cl->remote_pwd == NULL) old_pwd = cl->session->remote_pwd;
		else old_pwd = cl->remote_pwd;
		if ((strlen(pwd) != strlen(old_pwd)) || (strcmp(pwd, old_pwd) != 0)) return TRUE;
		return FALSE;
	}
	if (strlen(ufrag) != strlen(cl->remote_ufrag) || (strcmp(ufrag, cl->remote_ufrag) != 0)) return TRUE;
	if (strlen(pwd) != strlen(cl->remote_pwd) || (strcmp(pwd, cl->remote_pwd) != 0)) return TRUE;
	return FALSE;
}

502 503 504 505 506
void ice_check_list_set_remote_credentials(IceCheckList *cl, const char *ufrag, const char *pwd)
{
	ice_set_credentials(&cl->remote_ufrag, &cl->remote_pwd, ufrag, pwd);
}

507
bool_t ice_check_list_default_local_candidate(const IceCheckList *cl, const char **rtp_addr, int *rtp_port, const char **rtcp_addr, int *rtcp_port)
508 509
{
	IceCandidate *candidate = NULL;
510 511 512 513 514 515 516 517 518 519 520 521 522
	uint16_t componentID;
	MSList *rtp_elem;
	MSList *rtcp_elem;

	componentID = 1;
	rtp_elem = ms_list_find_custom(cl->local_candidates, (MSCompareFunc)ice_find_default_local_candidate, &componentID);
	if (rtp_elem == NULL) return FALSE;
	componentID = 2;
	rtcp_elem = ms_list_find_custom(cl->local_candidates, (MSCompareFunc)ice_find_default_local_candidate, &componentID);

	candidate = (IceCandidate *)rtp_elem->data;
	if (rtp_addr != NULL) *rtp_addr = candidate->taddr.ip;
	if (rtp_port != NULL) *rtp_port = candidate->taddr.port;
523 524 525 526
	if (rtcp_elem == NULL) {
		if ((rtcp_addr != NULL) || (rtcp_port != NULL)) return FALSE;
		else return TRUE;
	}
527 528 529 530
	candidate = (IceCandidate *)rtcp_elem->data;
	if (rtcp_addr != NULL) *rtcp_addr = candidate->taddr.ip;
	if (rtcp_port != NULL) *rtcp_port = candidate->taddr.port;
	return TRUE;
531 532
}

533
bool_t ice_check_list_selected_valid_local_candidate(const IceCheckList *cl, const char **rtp_addr, int *rtp_port, const char **rtcp_addr, int *rtcp_port)
Ghislain MARY's avatar
Ghislain MARY committed
534 535
{
	IceCandidate *candidate = NULL;
536 537 538 539 540 541
	IceValidCandidatePair *valid_pair = NULL;
	uint16_t componentID;
	MSList *rtp_elem;
	MSList *rtcp_elem;

	componentID = 1;
542
	rtp_elem = ms_list_find_custom(cl->valid_list, (MSCompareFunc)ice_find_selected_valid_pair_from_componentID, &componentID);
543 544
	if (rtp_elem == NULL) return FALSE;
	componentID = 2;
545
	rtcp_elem = ms_list_find_custom(cl->valid_list, (MSCompareFunc)ice_find_selected_valid_pair_from_componentID, &componentID);
546 547 548 549 550

	valid_pair = (IceValidCandidatePair *)rtp_elem->data;
	candidate = valid_pair->valid->local;
	if (rtp_addr != NULL) *rtp_addr = candidate->taddr.ip;
	if (rtp_port != NULL) *rtp_port = candidate->taddr.port;
551 552 553 554
	if (rtcp_elem == NULL) {
		if ((rtcp_addr != NULL) || (rtcp_port != NULL)) return FALSE;
		else return TRUE;
	}
555 556 557 558 559
	valid_pair = (IceValidCandidatePair *)rtcp_elem->data;
	candidate = valid_pair->valid->local;
	if (rtcp_addr != NULL) *rtcp_addr = candidate->taddr.ip;
	if (rtcp_port != NULL) *rtcp_port = candidate->taddr.port;
	return TRUE;
Ghislain MARY's avatar
Ghislain MARY committed
560 561
}

562
bool_t ice_check_list_selected_valid_remote_candidate(const IceCheckList *cl, const char **rtp_addr, int *rtp_port, const char **rtcp_addr, int *rtcp_port)
563 564 565 566 567 568 569 570
{
	IceCandidate *candidate = NULL;
	IceValidCandidatePair *valid_pair = NULL;
	uint16_t componentID;
	MSList *rtp_elem;
	MSList *rtcp_elem;

	componentID = 1;
571
	rtp_elem = ms_list_find_custom(cl->valid_list, (MSCompareFunc)ice_find_selected_valid_pair_from_componentID, &componentID);
572 573
	if (rtp_elem == NULL) return FALSE;
	componentID = 2;
574
	rtcp_elem = ms_list_find_custom(cl->valid_list, (MSCompareFunc)ice_find_selected_valid_pair_from_componentID, &componentID);
575 576 577 578 579 580 581 582 583 584 585 586 587

	valid_pair = (IceValidCandidatePair *)rtp_elem->data;
	candidate = valid_pair->valid->remote;
	if (rtp_addr != NULL) *rtp_addr = candidate->taddr.ip;
	if (rtp_port != NULL) *rtp_port = candidate->taddr.port;
	if (rtcp_elem == NULL) return FALSE;
	valid_pair = (IceValidCandidatePair *)rtcp_elem->data;
	candidate = valid_pair->valid->remote;
	if (rtcp_addr != NULL) *rtcp_addr = candidate->taddr.ip;
	if (rtcp_port != NULL) *rtcp_port = candidate->taddr.port;
	return TRUE;
}

588 589 590 591 592 593 594 595 596 597
IceCandidateType ice_check_list_selected_valid_candidate_type(const IceCheckList *cl)
{
	MSList *elem;
	uint16_t componentID = 1;

	elem = ms_list_find_custom(cl->valid_list, (MSCompareFunc)ice_find_selected_valid_pair_from_componentID, &componentID);
	if (elem == NULL) return ICT_RelayedCandidate;
	return ((IceValidCandidatePair *)elem->data)->valid->remote->type;
}

598 599 600 601 602 603 604 605 606 607 608 609 610 611
void ice_check_list_check_completed(IceCheckList *cl)
{
	CheckList_Bool cb;

	if (cl->state != ICL_Completed) {
		cb.cl = cl;
		cb.result = TRUE;
		ms_list_for_each2(cl->local_componentIDs, (void (*)(void*,void*))ice_find_selected_valid_pair_for_componentID, &cb);
		if (cb.result == TRUE) {
			ice_check_list_set_state(cl, ICL_Completed);
		}
	}
}

612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
static void ice_check_list_queue_triggered_check(IceCheckList *cl, IceCandidatePair *pair)
{
	MSList *elem = ms_list_find(cl->triggered_checks_queue, pair);
	if (elem != NULL) {
		/* The pair is already in the triggered checks queue, do not add it again. */
	} else {
		cl->triggered_checks_queue = ms_list_append(cl->triggered_checks_queue, pair);
	}
}

static IceCandidatePair * ice_check_list_pop_triggered_check(IceCheckList *cl)
{
	IceCandidatePair *pair;

	if (ms_list_size(cl->triggered_checks_queue) == 0) return NULL;
	pair = ms_list_nth_data(cl->triggered_checks_queue, 0);
	if (pair != NULL) {
		/* Remove the first element in the triggered checks queue. */
		cl->triggered_checks_queue = ms_list_remove_link(cl->triggered_checks_queue, cl->triggered_checks_queue);
	}
	return pair;
}

635 636 637 638 639 640 641 642 643 644 645
static int ice_find_non_frozen_pair(const IceCandidatePair *pair, const void *dummy)
{
	return (pair->state == ICP_Frozen);
}

static bool_t ice_check_list_is_frozen(const IceCheckList *cl)
{
	MSList *elem = ms_list_find_custom(cl->check_list, (MSCompareFunc)ice_find_non_frozen_pair, NULL);
	return (elem == NULL);
}

Ghislain MARY's avatar
Ghislain MARY committed
646 647 648 649 650
bool_t ice_check_list_is_mismatch(const IceCheckList *cl)
{
	return cl->mismatch;
}

Ghislain MARY's avatar
Ghislain MARY committed
651 652 653 654 655

/******************************************************************************
 * SESSION ACCESSORS                                                          *
 *****************************************************************************/

656 657 658 659 660
IceCheckList * ice_session_check_list(const IceSession *session, unsigned int n)
{
	return (IceCheckList *)ms_list_nth_data(session->streams, n);
}

661
const char * ice_session_local_ufrag(const IceSession *session)
Ghislain MARY's avatar
Ghislain MARY committed
662 663 664 665
{
	return session->local_ufrag;
}

666
const char * ice_session_local_pwd(const IceSession *session)
Ghislain MARY's avatar
Ghislain MARY committed
667 668 669 670
{
	return session->local_pwd;
}

671
const char * ice_session_remote_ufrag(const IceSession *session)
Ghislain MARY's avatar
Ghislain MARY committed
672 673 674 675
{
	return session->remote_ufrag;
}

676
const char * ice_session_remote_pwd(const IceSession *session)
Ghislain MARY's avatar
Ghislain MARY committed
677 678 679 680
{
	return session->remote_pwd;
}

681 682 683 684 685 686 687 688 689 690
static void ice_check_list_compute_pair_priorities(IceCheckList *cl)
{
	ms_list_for_each2(cl->pairs, (void (*)(void*,void*))ice_compute_pair_priority, &cl->session->role);
}

static void ice_session_compute_pair_priorities(IceSession *session)
{
	ms_list_for_each(session->streams, (void (*)(void*))ice_check_list_compute_pair_priorities);
}

691 692 693 694 695 696
IceSessionState ice_session_state(const IceSession *session)
{
	return session->state;
}

IceRole ice_session_role(const IceSession *session)
Ghislain MARY's avatar
Ghislain MARY committed
697 698 699 700
{
	return session->role;
}

Ghislain MARY's avatar
Ghislain MARY committed
701 702
void ice_session_set_role(IceSession *session, IceRole role)
{
703 704 705 706 707
	if (session->role != role) {
		/* Compute new candidate pair priorities if the role changes. */
		session->role = role;
		ice_session_compute_pair_priorities(session);
	}
Ghislain MARY's avatar
Ghislain MARY committed
708 709
}

Ghislain MARY's avatar
Ghislain MARY committed
710 711 712 713 714
void ice_session_set_local_credentials(IceSession *session, const char *ufrag, const char *pwd)
{
	ice_set_credentials(&session->local_ufrag, &session->local_pwd, ufrag, pwd);
}

715 716 717 718 719 720 721 722
bool_t ice_session_remote_credentials_changed(IceSession *session, const char *ufrag, const char *pwd)
{
	if ((session->remote_ufrag == NULL) || (session->remote_pwd == NULL)) return TRUE;
	if (strlen(ufrag) != strlen(session->remote_ufrag) || (strcmp(ufrag, session->remote_ufrag) != 0)) return TRUE;
	if (strlen(pwd) != strlen(session->remote_pwd) || (strcmp(pwd, session->remote_pwd) != 0)) return TRUE;
	return FALSE;
}

Ghislain MARY's avatar
Ghislain MARY committed
723 724 725 726 727
void ice_session_set_remote_credentials(IceSession *session, const char *ufrag, const char *pwd)
{
	ice_set_credentials(&session->remote_ufrag, &session->remote_pwd, ufrag, pwd);
}

Ghislain MARY's avatar
Ghislain MARY committed
728 729 730 731 732
void ice_session_set_max_connectivity_checks(IceSession *session, uint8_t max_connectivity_checks)
{
	session->max_connectivity_checks = max_connectivity_checks;
}

Ghislain MARY's avatar
Ghislain MARY committed
733 734 735 736 737 738
void ice_session_set_keepalive_timeout(IceSession *session, uint8_t timeout)
{
	if (timeout < ICE_DEFAULT_KEEPALIVE_TIMEOUT) timeout = ICE_DEFAULT_KEEPALIVE_TIMEOUT;
	session->keepalive_timeout = timeout;
}

Ghislain MARY's avatar
Ghislain MARY committed
739 740 741 742 743

/******************************************************************************
 * SESSION HANDLING                                                           *
 *****************************************************************************/

744 745 746 747 748
int ice_session_nb_check_lists(IceSession *session)
{
	return ms_list_size(session->streams);
}

749 750 751 752 753 754 755 756 757 758 759 760
static int ice_find_completed_check_list(const IceCheckList *cl, const void *dummy)
{
	return (cl->state != ICL_Completed);
}

bool_t ice_session_has_completed_check_list(const IceSession *session)
{
	MSList *elem = ms_list_find_custom(session->streams, (MSCompareFunc)ice_find_completed_check_list, NULL);
	if (elem == NULL) return FALSE;
	else return TRUE;
}

Ghislain MARY's avatar
Ghislain MARY committed
761
void ice_session_add_check_list(IceSession *session, IceCheckList *cl)
762
{
Ghislain MARY's avatar
Ghislain MARY committed
763 764
	session->streams = ms_list_append(session->streams, cl);
	cl->session = session;
765 766 767
	if (cl->state == ICL_Running) {
		session->state = IS_Running;
	}
768 769
}

770 771
void ice_session_remove_check_list(IceSession *session, IceCheckList *cl)
{
772
	if (cl == NULL) return;
773 774 775 776
	session->streams = ms_list_remove(session->streams, cl);
	ice_check_list_destroy(cl);
}

Ghislain MARY's avatar
Ghislain MARY committed
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
static int ice_find_default_candidate_from_componentID(const IceCandidate *candidate, const uint16_t *componentID)
{
	return !((candidate->is_default == TRUE) && (candidate->componentID == *componentID));
}

static void ice_find_default_remote_candidate_for_componentID(const uint16_t *componentID, IceCheckList *cl)
{
	MSList *elem = ms_list_find_custom(cl->remote_candidates, (MSCompareFunc)ice_find_default_candidate_from_componentID, componentID);
	if (elem == NULL) {
		cl->mismatch = TRUE;
		cl->state = ICL_Failed;
	}
}

static void ice_check_list_check_mismatch(IceCheckList *cl)
{
	ms_list_for_each2(cl->remote_componentIDs, (void (*)(void*,void*))ice_find_default_remote_candidate_for_componentID, cl);
}

void ice_session_check_mismatch(IceSession *session)
{
	ms_list_for_each(session->streams, (void (*)(void*))ice_check_list_check_mismatch);
}

801

802 803 804 805
/******************************************************************************
 * CANDIDATES GATHERING                                                       *
 *****************************************************************************/

806
static void ice_check_list_candidates_gathered_result_ptr(const IceCheckList *cl, bool_t *result)
807
{
808 809 810 811 812 813
	if (cl->gathering_finished == FALSE) *result = FALSE;
}

bool_t ice_check_list_candidates_gathered(const IceCheckList *cl)
{
	return cl->gathering_finished;
814 815 816 817 818
}

bool_t ice_session_candidates_gathered(const IceSession *session)
{
	bool_t result = TRUE;
819
	ms_list_for_each2(session->streams, (void (*)(void*,void*))ice_check_list_candidates_gathered_result_ptr, &result);
820 821 822
	return result;
}

823 824 825 826 827
static void ice_check_list_gathering_needed(const IceCheckList *cl, bool_t *gathering_needed)
{
	if (cl->gathering_finished == FALSE) *gathering_needed = TRUE;
}

828
static void ice_check_list_gather_candidates(IceCheckList *cl, Session_Index *si)
829 830 831
{
	IceStunServerCheck *check;
	ortp_socket_t sock = -1;
Ghislain MARY's avatar
Ghislain MARY committed
832
	MSTimeSpec curtime = ice_current_time();
833

834
	if ((cl->rtp_session != NULL) && (cl->gathering_candidates == FALSE) && (cl->state != ICL_Completed) && (ice_check_list_candidates_gathered(cl) == FALSE)) {
835
		cl->gathering_candidates = TRUE;
836
		cl->gathering_start_time = curtime;
837 838 839 840
		sock = rtp_session_get_rtp_socket(cl->rtp_session);
		if (sock > 0) {
			check = (IceStunServerCheck *)ms_new0(IceStunServerCheck, 1);
			check->sock = sock;
841
			check->srcport = rtp_session_get_local_port(cl->rtp_session);
842
			if (si->index == 0) {
843 844
				check->next_transmission_time = ice_add_ms(curtime, ICE_DEFAULT_RTO_DURATION);
				ice_send_stun_server_binding_request(sock, (struct sockaddr *)&cl->session->ss, cl->session->ss_len, check);
845
			} else {
846
				check->next_transmission_time = ice_add_ms(curtime, 2 * si->index * ICE_DEFAULT_TA_DURATION);
847 848 849 850 851 852 853
			}
			cl->stun_server_checks = ms_list_append(cl->stun_server_checks, check);
		}
		sock = rtp_session_get_rtcp_socket(cl->rtp_session);
		if (sock > 0) {
			check = (IceStunServerCheck *)ms_new0(IceStunServerCheck, 1);
			check->sock = sock;
854
			check->srcport = rtp_session_get_local_port(cl->rtp_session) + 1;
855
			check->next_transmission_time = ice_add_ms(curtime, 2 * si->index * ICE_DEFAULT_TA_DURATION + ICE_DEFAULT_TA_DURATION);
856 857
			cl->stun_server_checks = ms_list_append(cl->stun_server_checks, check);
		}
858
		si->index++;
859 860 861 862 863
	}
}

void ice_session_gather_candidates(IceSession *session, struct sockaddr_storage ss, socklen_t ss_len)
{
864
	Session_Index si;
865 866
	OrtpEvent *ev;
	bool_t gathering_needed = FALSE;
867 868
	session->ss = ss;
	session->ss_len = ss_len;
869 870
	si.session = session;
	si.index = 0;
871
	ms_get_cur_time(&session->gathering_start_ts);
872 873 874 875 876 877 878 879 880 881
	ms_list_for_each2(session->streams, (void (*)(void*,void*))ice_check_list_gathering_needed, &gathering_needed);
	if (gathering_needed == TRUE) {
		ms_list_for_each2(session->streams, (void (*)(void*,void*))ice_check_list_gather_candidates, &si);
	} else {
		/* Notify end of gathering since it has already been done. */
		ev = ortp_event_new(ORTP_EVENT_ICE_GATHERING_FINISHED);
		ortp_event_get_data(ev)->info.ice_processing_successful = TRUE;
		session->gathering_end_ts = session->gathering_start_ts;
		rtp_session_dispatch_event(ice_session_check_list(session, 0)->rtp_session, ev);
	}
882 883
}

884 885 886 887 888 889 890
int ice_session_gathering_duration(IceSession *session)
{
	if ((session->gathering_start_ts.tv_sec == -1) || (session->gathering_end_ts.tv_sec == -1)) return -1;
	return ((session->gathering_end_ts.tv_sec - session->gathering_start_ts.tv_sec) * 1000.0)
		+ ((session->gathering_end_ts.tv_nsec - session->gathering_start_ts.tv_nsec) / 1000000.0);
}

891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
static void ice_transaction_sum_gathering_round_trip_time(const IceStunServerCheckTransaction *transaction, StunRequestRoundTripTime *rtt)
{
	if ((transaction->response_time.tv_sec != 0) && (transaction->response_time.tv_nsec != 0)) {
		rtt->nb_responses++;
		rtt->sum += ice_compare_time(transaction->response_time, transaction->request_time);
	}
}

static void ice_stun_server_check_sum_gathering_round_trip_time(const IceStunServerCheck *check, StunRequestRoundTripTime *rtt)
{
	ms_list_for_each2(check->transactions, (void (*)(void*,void*))ice_transaction_sum_gathering_round_trip_time, rtt);
}

static void ice_check_list_sum_gathering_round_trip_times(const IceCheckList *cl, StunRequestRoundTripTime *rtt)
{
	ms_list_for_each2(cl->stun_server_checks, (void (*)(void*,void*))ice_stun_server_check_sum_gathering_round_trip_time, rtt);
}

int ice_session_average_gathering_round_trip_time(IceSession *session)
{
	StunRequestRoundTripTime rtt;

	if ((session->gathering_start_ts.tv_sec == -1) || (session->gathering_end_ts.tv_sec == -1)) return -1;
	memset(&rtt, 0, sizeof(rtt));
	ms_list_for_each2(session->streams, (void (*)(void*,void*))ice_check_list_sum_gathering_round_trip_times, &rtt);
	if (rtt.nb_responses == 0) return -1;
	return (rtt.sum / rtt.nb_responses);
}

920

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
/******************************************************************************
 * CANDIDATES SELECTION                                                       *
 *****************************************************************************/

static void ice_unselect_valid_pair(IceValidCandidatePair *valid_pair)
{
	valid_pair->selected = FALSE;
}

static void ice_check_list_select_candidates(IceCheckList *cl)
{
	IceValidCandidatePair *valid_pair = NULL;
	uint16_t componentID;
	MSList *elem;

936 937
	if (cl->state != ICL_Completed) return;

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
	ms_list_for_each(cl->valid_list, (void (*)(void*))ice_unselect_valid_pair);
	for (componentID = 1; componentID <= 2; componentID++) {
		elem = ms_list_find_custom(cl->valid_list, (MSCompareFunc)ice_find_nominated_valid_pair_from_componentID, &componentID);
		if (elem == NULL) continue;
		valid_pair = (IceValidCandidatePair *)elem->data;
		valid_pair->selected = TRUE;
	}
}

void ice_session_select_candidates(IceSession *session)
{
	ms_list_for_each(session->streams, (void (*)(void*))ice_check_list_select_candidates);
}


Ghislain MARY's avatar
Ghislain MARY committed
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
/******************************************************************************
 * TRANSACTION HANDLING                                                       *
 *****************************************************************************/

static IceTransaction * ice_create_transaction(IceCheckList *cl, IceCandidatePair *pair, const UInt96 *tr_id)
{
	IceTransaction *transaction = ms_new0(IceTransaction, 1);
	transaction->pair = pair;
	memcpy(&transaction->transactionID, tr_id, sizeof(transaction->transactionID));
	cl->transaction_list = ms_list_prepend(cl->transaction_list, transaction);
	return transaction;
}

static int ice_find_transaction_from_pair(const IceTransaction *transaction, const IceCandidatePair *pair)
{
	return (transaction->pair != pair);
}

static IceTransaction * ice_find_transaction(const IceCheckList *cl, const IceCandidatePair *pair)
{
	MSList *elem = ms_list_find_custom(cl->transaction_list, (MSCompareFunc)ice_find_transaction_from_pair, pair);
	if (elem == NULL) return NULL;
	return (IceTransaction *)elem->data;
}


979 980 981 982
/******************************************************************************
 * STUN PACKETS HANDLING                                                      *
 *****************************************************************************/

983
static void ice_send_stun_server_binding_request(ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check)
984 985 986 987 988 989 990
{
	StunMessage msg;
	StunAtrString username;
	StunAtrString password;
	char buf[STUN_MAX_MESSAGE_SIZE];
	int len = STUN_MAX_MESSAGE_SIZE;
	const struct sockaddr_in *servaddr = (const struct sockaddr_in *)server;
991
	char tr_id_str[25];
992 993 994 995

	memset(&msg, 0, sizeof(StunMessage));
	memset(&username,0,sizeof(username));
	memset(&password,0,sizeof(password));
996
	stunBuildReqSimple(&msg, &username, FALSE, FALSE, check->sock);
997 998
	len = stunEncodeMessage(&msg, buf, len, &password);
	if (len > 0) {
999 1000 1001 1002
		IceStunServerCheckTransaction *transaction = ms_new0(IceStunServerCheckTransaction, 1);
		transaction->request_time = ice_current_time();
		memcpy(&transaction->transactionID, &msg.msgHdr.tr_id, sizeof(transaction->transactionID));
		check->transactions = ms_list_append(check->transactions, transaction);
1003
		transactionID2string(&msg.msgHdr.tr_id, tr_id_str);
1004
		ms_message("ice: Send STUN binding request from port %u [%s]", check->srcport, tr_id_str);
1005 1006 1007 1008 1009 1010
		sendMessage(sock, buf, len, htonl(servaddr->sin_addr.s_addr), htons(servaddr->sin_port));
	}
}

static int ice_parse_stun_server_binding_response(const StunMessage *msg, char *addr, int addr_len, int *port)
{
1011
	struct sockaddr_in addr_in;
1012 1013 1014

	if (msg->hasXorMappedAddress) {
		*port = msg->xorMappedAddress.ipv4.port;
1015
		addr_in.sin_addr.s_addr = htonl(msg->xorMappedAddress.ipv4.addr);
1016 1017
	} else if (msg->hasMappedAddress) {
		*port = msg->mappedAddress.ipv4.port;
1018
		addr_in.sin_addr.s_addr = htonl(msg->mappedAddress.ipv4.addr);
1019 1020
	} else return -1;

1021 1022 1023
	addr_in.sin_family = AF_INET;
	addr_in.sin_port = htons(*port);
	ice_inet_ntoa((struct sockaddr *)&addr_in, sizeof(addr_in), addr, addr_len);
1024 1025 1026
	return 0;
}

1027
/* Send a STUN binding request for ICE connectivity checks according to 7.1.2. */
1028
static void ice_send_binding_request(IceCheckList *cl, IceCandidatePair *pair, const RtpSession *rtp_session)
1029 1030 1031
{
	StunMessage msg;
	StunAddress4 dest;
1032 1033
	StunAtrString username;
	StunAtrString password;
Ghislain MARY's avatar
Ghislain MARY committed
1034
	IceTransaction *transaction;
1035 1036 1037
	char buf[STUN_MAX_MESSAGE_SIZE];
	int len = STUN_MAX_MESSAGE_SIZE;
	int socket = 0;