sal_sdp.c 18.7 KB
Newer Older
jehan's avatar
jehan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
linphone
Copyright (C) 2012  Belledonne Communications, Grenoble, France

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.
*/
#include "sal_impl.h"
#define keywordcmp(key,b) strncmp(key,b,sizeof(key))

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

static void add_ice_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){
	char buffer[1024];
	const SalIceCandidate *candidate;
	int nb;
	int i;

	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) {
		candidate = &desc->ice_candidates[i];
		if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break;
		nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s",
			candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type);
		if (nb < 0) {
			ms_error("Cannot add ICE candidate attribute!");
			return;
		}
		if (candidate->raddr[0] != '\0') {
			nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport);
			if (nb < 0) {
				ms_error("Cannot add ICE candidate attribute!");
				return;
			}
		}
		belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("candidate",buffer));
	}
}

static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){
	char buffer[1024];
	char *ptr = buffer;
	const SalIceRemoteCandidate *candidate;
	int offset = 0;
	int i;

	buffer[0] = '\0';
	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) {
		candidate = &desc->ice_remote_candidates[i];
		if ((candidate->addr[0] != '\0') && (candidate->port != 0)) {
			offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port);
			if (offset < 0) {
				ms_error("Cannot add ICE remote-candidates attribute!");
				return;
			}
			ptr += offset;
		}
	}
	if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer));
}

71
static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMediaDescription *md, const SalStreamDescription *stream ) {
jehan's avatar
jehan committed
72 73
	belle_sdp_mime_parameter_t* mime_param;
	belle_sdp_media_description_t* media_desc;
74
	int j;
jehan's avatar
jehan committed
75 76 77
	MSList* pt_it;
	PayloadType* pt;
	char buffer[1024];
jehan's avatar
jehan committed
78
	char* dir=NULL;
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
	const char *rtp_addr;
	const char *rtcp_addr;
	int rtp_port;
	int rtcp_port;
	bool_t different_rtp_and_rtcp_addr;
	
	rtp_addr=stream->rtp_addr;
	rtcp_addr=stream->rtcp_addr;
	rtp_port=stream->rtp_port;
	rtcp_port=stream->rtcp_port;
	
	media_desc = belle_sdp_media_description_create ( sal_stream_type_to_string ( stream->type )
				 ,stream->rtp_port
				 ,1
				 ,sal_media_proto_to_string ( stream->proto )
				 ,NULL );
	for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) {
		pt= ( PayloadType* ) pt_it->data;
		mime_param= belle_sdp_mime_parameter_create ( pt->mime_type
					, payload_type_get_number ( pt )
					, pt->clock_rate
					,stream->type==SalAudio?1:-1 );
		belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp );
		if ( stream->ptime>0 ) {
			belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime );
		}
		belle_sdp_media_description_append_values_from_mime_parameter ( media_desc,mime_param );
		belle_sip_object_unref ( mime_param );
	}
108 109 110 111 112 113 114 115 116
	/*only add a c= line within the stream description if address are differents*/
	if (rtp_addr[0]!='\0' && strcmp(rtp_addr,md->addr)!=0){
		bool_t inet6;
		if (strchr(rtp_addr,':')!=NULL){
			inet6=TRUE;
		}else inet6=FALSE;
		belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr));
	}
	
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	if ( stream->bandwidth>0 )
		belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth );

	if ( stream->proto == SalProtoRtpSavp ) {
		/* add crypto lines */
		for ( j=0; j<SAL_CRYPTO_ALGO_MAX; j++ ) {

			switch ( stream->crypto[j].algo ) {
				case AES_128_SHA1_80:
					snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s",
							   stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", stream->crypto[j].master_key );
					belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
					break;
				case AES_128_SHA1_32:
					snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s",
							   stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", stream->crypto[j].master_key );
					belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
					break;
				case AES_128_NO_AUTH:
					ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" );
					break;
				case NO_CIPHER_SHA1_80:
					ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" );
					break;
				default:
					j = SAL_CRYPTO_ALGO_MAX;
					/* no break */
			}
		}
	}
	switch ( stream->dir ) {
		case SalStreamSendRecv:
			/*dir="sendrecv";*/
			dir=NULL;
			break;
		case SalStreamRecvOnly:
			dir="recvonly";
			break;
		case SalStreamSendOnly:
			dir="sendonly";
			break;
		case SalStreamInactive:
			dir="inactive";
			break;
	}
	if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) );
	
	if (rtp_port != 0) {
		different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0);
		if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) {
			if (different_rtp_and_rtcp_addr == TRUE) {
				snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr);
			} else {
				snprintf(buffer, sizeof(buffer), "%u",rtcp_port);
			}
			belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("rtcp",buffer));
		}
	}
	if (stream->ice_completed == TRUE) {
		belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("nortpproxy","yes"));
	}
	if (stream->ice_mismatch == TRUE) {
		belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL));
	} else {
		if (rtp_port != 0) {
			if (stream->ice_pwd[0] != '\0') 
				belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd));
			if (stream->ice_ufrag[0] != '\0')
				belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag));
			add_ice_candidates(media_desc,stream);
			add_ice_remote_candidates(media_desc,stream);
		}
	}
	
	return media_desc;
}

belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescription *desc ) {
	belle_sdp_session_description_t* session_desc=belle_sdp_session_description_new();
	bool_t inet6;
	belle_sdp_origin_t* origin;
	int i;
jehan's avatar
jehan committed
199

200 201 202 203
	if ( strchr ( desc->addr,':' ) !=NULL ) {
		inet6=1;
	} else inet6=0;
	belle_sdp_session_description_set_version ( session_desc,belle_sdp_version_create ( 0 ) );
jehan's avatar
jehan committed
204

205 206 207 208 209 210
	origin = belle_sdp_origin_create ( desc->username
									  ,desc->session_id
									  ,desc->session_ver
									  ,"IN"
									  , inet6 ? "IP6" :"IP4"
									  ,desc->addr );
jehan's avatar
jehan committed
211

212
	belle_sdp_session_description_set_origin ( session_desc,origin );
jehan's avatar
jehan committed
213

214
	belle_sdp_session_description_set_session_name ( session_desc,belle_sdp_session_name_create ( "Talk" ) );
jehan's avatar
jehan committed
215

Simon Morlat's avatar
Simon Morlat committed
216 217
	if ( (!sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive )) 
		|| desc->ice_ufrag[0] != '\0' ) {
218 219
		belle_sdp_session_description_set_connection ( session_desc
				,belle_sdp_connection_create ( "IN",inet6 ? "IP6" :"IP4",desc->addr ) );
jehan's avatar
jehan committed
220 221

	} else 	{
222 223 224 225
		belle_sdp_session_description_set_connection ( session_desc
				,belle_sdp_connection_create ( "IN"
								,inet6 ? "IP6" :"IP4"
								,inet6 ? "::0" :"0.0.0.0" ) );
jehan's avatar
jehan committed
226 227 228

	}

229
	belle_sdp_session_description_set_time_description ( session_desc,belle_sdp_time_description_create ( 0,0 ) );
jehan's avatar
jehan committed
230

231 232
	if ( desc->bandwidth>0 ) {
		belle_sdp_session_description_set_bandwidth ( session_desc,"AS",desc->bandwidth );
jehan's avatar
jehan committed
233
	}
234 235 236 237 238 239
	
	if (desc->ice_completed == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes"));
	if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd));
	if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag));
	
	for ( i=0; i<desc->n_total_streams; i++ ) {
240
		belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(desc,&desc->streams[i]));
jehan's avatar
jehan committed
241 242 243 244 245
	}
	return session_desc;
}


246
int sdp_to_media_description ( belle_sdp_session_description_t  *session_desc, SalMediaDescription *desc ) {
jehan's avatar
jehan committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
	/*
	typedef struct SalMediaDescription{
		int refcount;
		char addr[64];
		char username[64];
		int nstreams;
		int bandwidth;
		unsigned int session_ver;
		unsigned int session_id;
		SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
	} SalMediaDescription;
	 */
	belle_sdp_connection_t* cnx;
	belle_sip_list_t* media_desc_it;
	belle_sdp_media_description_t* media_desc;
	const char *mtype,*proto;
	SalStreamDescription *stream;
	belle_sdp_media_t* media;
265
	belle_sip_list_t* mime_params=NULL;
jehan's avatar
jehan committed
266 267 268 269
	belle_sip_list_t* mime_param_it=NULL;
	belle_sdp_mime_parameter_t* mime_param;
	PayloadType *pt;
	belle_sip_list_t* attribute_it;
270
	const belle_sdp_attribute_t* attribute;
jehan's avatar
jehan committed
271 272 273
	int valid_count = 0;
	char tmp[256], tmp2[256];
	int nb=0;
274
	SalStreamDir stream_dir=SalStreamSendRecv;
275 276
	const char* value;
	
277 278
	desc->n_active_streams = 0;
	desc->n_total_streams = 0;
jehan's avatar
jehan committed
279

280 281
	if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
		strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) );
jehan's avatar
jehan committed
282
	}
283 284
	if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) {
		desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" );
jehan's avatar
jehan committed
285
	}
286
	/*in some very rare case, session attribute may set stream dir*/
287
	if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) {
288
		stream_dir=SalStreamSendRecv;
289
	} else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) {
290
		stream_dir=SalStreamSendOnly;
291
	} else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) {
292
		stream_dir=SalStreamRecvOnly;
293
	} else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) {
294 295 296
		stream_dir=SalStreamInactive;
	}

297 298 299 300 301 302 303 304 305 306 307 308 309
	/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
	value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag");
	if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag));
	
	value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd");
	if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd));
	
	value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite");
	if (value) desc->ice_lite = TRUE;
	
	for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc )
						; media_desc_it!=NULL
			; media_desc_it=media_desc_it->next ) {
310
		int nb_ice_candidates=0;
311
		media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data );
312
		stream=&desc->streams[desc->n_total_streams];
313
		media=belle_sdp_media_description_get_media ( media_desc );
jehan's avatar
jehan committed
314

315
		memset ( stream,0,sizeof ( *stream ) );
jehan's avatar
jehan committed
316

317
		proto = belle_sdp_media_get_protocol ( media );
jehan's avatar
jehan committed
318
		stream->proto=SalProtoUnknown;
319 320
		if ( proto ) {
			if ( strcasecmp ( proto,"RTP/AVP" ) ==0 )
jehan's avatar
jehan committed
321
				stream->proto=SalProtoRtpAvp;
322
			else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) {
jehan's avatar
jehan committed
323 324 325
				stream->proto=SalProtoRtpSavp;
			}
		}
326 327
		if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
			strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) );
jehan's avatar
jehan committed
328 329
		}

330
		stream->rtp_port=belle_sdp_media_get_media_port ( media );
331

332 333
		if ( stream->rtp_port > 0 )
			desc->n_active_streams++;
jehan's avatar
jehan committed
334

335 336
		mtype = belle_sdp_media_get_media_type ( media );
		if ( strcasecmp ( "audio", mtype ) == 0 ) {
jehan's avatar
jehan committed
337
			stream->type=SalAudio;
338
		} else if ( strcasecmp ( "video", mtype ) == 0 ) {
jehan's avatar
jehan committed
339
			stream->type=SalVideo;
340
		} else {
jehan's avatar
jehan committed
341
			stream->type=SalOther;
342
			strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 );
jehan's avatar
jehan committed
343 344
		}

345 346
		if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) {
			stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" );
jehan's avatar
jehan committed
347 348 349
		}


350
		if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) {
jehan's avatar
jehan committed
351
			stream->dir=SalStreamSendRecv;
352
		} else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) {
jehan's avatar
jehan committed
353
			stream->dir=SalStreamSendOnly;
354
		} else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) {
jehan's avatar
jehan committed
355
			stream->dir=SalStreamRecvOnly;
356
		} else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) {
jehan's avatar
jehan committed
357 358
			stream->dir=SalStreamInactive;
		} else {
359
			stream->dir=stream_dir; /*takes default value if not present*/
jehan's avatar
jehan committed
360 361 362
		}

		/* for each payload type */
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
		mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc );
		for ( mime_param_it=mime_params
							; mime_param_it!=NULL
				; mime_param_it=mime_param_it->next ) {
			mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data )

					   pt=payload_type_new();
			payload_type_set_number ( pt,belle_sdp_mime_parameter_get_media_format ( mime_param ) );
			pt->clock_rate=belle_sdp_mime_parameter_get_rate ( mime_param );
			pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) );
			pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param );
			payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) );
			stream->payloads=ms_list_append ( stream->payloads,pt );
			stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param );
			ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
						 pt->send_fmtp ? pt->send_fmtp : "" );
jehan's avatar
jehan committed
379
		}
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
		if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref );
		
		
		/* Get media specific RTCP attribute */
		stream->rtcp_port = stream->rtp_port + 1;
		snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr);
		attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp");
		if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
			char tmp[256];
			int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp);
			if (nb == 1) {
				/* SDP rtcp attribute only contains the port */
			} else if (nb == 2) {
				strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr));
			} else {
				ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb);
			}
		}
		
jehan's avatar
jehan committed
399
		/* read crypto lines if any */
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
		if ( stream->proto == SalProtoRtpSavp ) {
			memset ( &stream->crypto, 0, sizeof ( stream->crypto ) );
			for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc )
							   ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL;
					attribute_it=attribute_it->next ) {
				attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data );

				if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) {
					nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s",
								  &stream->crypto[valid_count].tag,
								  tmp,
								  tmp2 );
					ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
								 stream->crypto[valid_count].tag,
								 tmp,
								 tmp2 );
					if ( nb == 3 ) {
						if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 )
jehan's avatar
jehan committed
418
							stream->crypto[valid_count].algo = AES_128_SHA1_80;
419
						else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 )
jehan's avatar
jehan committed
420 421
							stream->crypto[valid_count].algo = AES_128_SHA1_32;
						else {
422
							ms_warning ( "Failed to parse crypto-algo: '%s'", tmp );
jehan's avatar
jehan committed
423 424
							stream->crypto[valid_count].algo = 0;
						}
425 426
						if ( stream->crypto[valid_count].algo ) {
							strncpy ( stream->crypto[valid_count].master_key, tmp2, 41 );
jehan's avatar
jehan committed
427
							stream->crypto[valid_count].master_key[40] = '\0';
428 429 430 431
							ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
										 stream->crypto[valid_count].tag,
										 tmp,
										 stream->crypto[valid_count].master_key );
jehan's avatar
jehan committed
432 433 434
							valid_count++;
						}
					} else {
435
						ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb );
jehan's avatar
jehan committed
436 437 438
					}
				}
			}
439 440 441 442 443
			ms_message ( "Found: %d valid crypto lines", valid_count );
		}
		
		/* Get ICE candidate attributes if any */
		for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) {
444
			const char *att_name;
445
			attribute=(belle_sdp_attribute_t*)attribute_it->data;
446
			att_name=belle_sdp_attribute_get_name(attribute);
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
			value=belle_sdp_attribute_get_value(attribute);
			if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) {
				SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates];
				int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d",
					candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port,
					candidate->type, candidate->raddr, &candidate->rport);
				if ((nb == 6) || (nb == 8)) nb_ice_candidates++;
				else memset(candidate, 0, sizeof(*candidate));
			} else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) {
				SalIceRemoteCandidate candidate;
				unsigned int componentID;
				int offset;
				const char *ptr = value;
				while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) {
					if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) {
						SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1];
						strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr));
						remote_candidate->port = candidate.port;
					}
					ptr += offset;
					if (ptr[offset] == ' ') ptr += 1;
				}
			} else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) {
				strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag));
			} else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) {
				strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd));
			} else if (keywordcmp("ice-mismatch", att_name) == 0) {
				stream->ice_mismatch = TRUE;
			}
jehan's avatar
jehan committed
476
		}
477
		desc->n_total_streams++;
jehan's avatar
jehan committed
478 479 480 481 482 483 484
	}
	return 0;
}




485