1 /*
2 linphone
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)
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 This file contains SAL API functions that do not depend on the underlying implementation (like belle-sip).
22 **/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "sal/sal.h"
27 
28 
29 #include <ctype.h>
30 
31 
sal_multicast_role_to_string(SalMulticastRole role)32 const char *sal_multicast_role_to_string(SalMulticastRole role){
33 	switch(role){
34 		case SalMulticastInactive:
35 			return "inactive";
36 		case SalMulticastReceiver:
37 			return "receiver";
38 		case SalMulticastSender:
39 			return "sender";
40 		case SalMulticastSenderReceiver:
41 			return "sender-receiver";
42 	}
43 	return "INVALID";
44 }
45 
sal_transport_to_string(SalTransport transport)46 const char* sal_transport_to_string(SalTransport transport) {
47 	switch (transport) {
48 		case SalTransportUDP:return "udp";
49 		case SalTransportTCP: return "tcp";
50 		case SalTransportTLS:return "tls";
51 		case SalTransportDTLS:return "dtls";
52 		default: {
53 			ms_fatal("Unexpected transport [%i]",transport);
54 			return NULL;
55 		}
56 	}
57 }
58 
sal_transport_parse(const char * param)59 SalTransport sal_transport_parse(const char* param) {
60 	if (!param) return SalTransportUDP;
61 	if (strcasecmp("udp",param)==0) return SalTransportUDP;
62 	if (strcasecmp("tcp",param)==0) return SalTransportTCP;
63 	if (strcasecmp("tls",param)==0) return SalTransportTLS;
64 	if (strcasecmp("dtls",param)==0) return SalTransportDTLS;
65 	ms_error("Unknown transport type[%s], returning UDP", param);
66 	return SalTransportUDP;
67 }
68 
sal_media_description_new()69 SalMediaDescription *sal_media_description_new(){
70 	SalMediaDescription *md=ms_new0(SalMediaDescription,1);
71 	int i;
72 	md->refcount=1;
73 	for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
74 		md->streams[i].dir=SalStreamInactive;
75 		md->streams[i].rtp_port = 0;
76 		md->streams[i].rtcp_port = 0;
77 		md->streams[i].haveZrtpHash = 0;
78 	}
79 	return md;
80 }
81 
sal_media_description_destroy(SalMediaDescription * md)82 static void sal_media_description_destroy(SalMediaDescription *md){
83 	int i;
84 	for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++){
85 		bctbx_list_free_with_data(md->streams[i].payloads,(void (*)(void *))payload_type_destroy);
86 		bctbx_list_free_with_data(md->streams[i].already_assigned_payloads,(void (*)(void *))payload_type_destroy);
87 		md->streams[i].payloads=NULL;
88 		md->streams[i].already_assigned_payloads=NULL;
89 		sal_custom_sdp_attribute_free(md->streams[i].custom_sdp_attributes);
90 	}
91 	sal_custom_sdp_attribute_free(md->custom_sdp_attributes);
92 	ms_free(md);
93 }
94 
sal_media_description_ref(SalMediaDescription * md)95 SalMediaDescription * sal_media_description_ref(SalMediaDescription *md){
96 	md->refcount++;
97 	return md;
98 }
99 
sal_media_description_unref(SalMediaDescription * md)100 void sal_media_description_unref(SalMediaDescription *md){
101 	md->refcount--;
102 	if (md->refcount==0){
103 		sal_media_description_destroy (md);
104 	}
105 }
106 
sal_media_description_find_stream(SalMediaDescription * md,SalMediaProto proto,SalStreamType type)107 SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){
108 	int i;
109 	for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
110 		SalStreamDescription *ss=&md->streams[i];
111 		if (!sal_stream_description_active(ss)) continue;
112 		if (ss->proto==proto && ss->type==type) return ss;
113 	}
114 	return NULL;
115 }
116 
sal_media_description_nb_active_streams_of_type(SalMediaDescription * md,SalStreamType type)117 unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type) {
118 	unsigned int i;
119 	unsigned int nb = 0;
120 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i) {
121 		if (!sal_stream_description_active(&md->streams[i])) continue;
122 		if (md->streams[i].type == type) nb++;
123 	}
124 	return nb;
125 }
126 
sal_media_description_get_active_stream_of_type(SalMediaDescription * md,SalStreamType type,unsigned int idx)127 SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx) {
128 	unsigned int i;
129 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i) {
130 		if (!sal_stream_description_active(&md->streams[i])) continue;
131 		if (md->streams[i].type == type) {
132 			if (idx-- == 0) return &md->streams[i];
133 		}
134 	}
135 	return NULL;
136 }
137 
sal_media_description_find_secure_stream_of_type(SalMediaDescription * md,SalStreamType type)138 SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type) {
139 	SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
140 	if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type);
141 	return desc;
142 }
143 
sal_media_description_find_best_stream(SalMediaDescription * md,SalStreamType type)144 SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) {
145 	SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavpf, type);
146 	if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavp, type);
147 	if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
148 	if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type);
149 	if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type);
150 	if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type);
151 	return desc;
152 }
153 
sal_media_description_empty(const SalMediaDescription * md)154 bool_t sal_media_description_empty(const SalMediaDescription *md){
155 	if (sal_media_description_get_nb_active_streams(md) > 0) return FALSE;
156 	return TRUE;
157 }
158 
sal_media_description_set_dir(SalMediaDescription * md,SalStreamDir stream_dir)159 void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
160 	int i;
161 	for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
162 		SalStreamDescription *ss=&md->streams[i];
163 		if (!sal_stream_description_active(ss)) continue;
164 		ss->dir=stream_dir;
165 	}
166 }
167 
sal_media_description_get_nb_active_streams(const SalMediaDescription * md)168 int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) {
169 	int i;
170 	int nb = 0;
171 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
172 		if (sal_stream_description_active(&md->streams[i])) nb++;
173 	}
174 	return nb;
175 }
176 
is_null_address(const char * addr)177 static bool_t is_null_address(const char *addr){
178 	return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
179 }
180 
181 /*check for the presence of at least one stream with requested direction */
has_dir(const SalMediaDescription * md,SalStreamDir stream_dir)182 static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
183 	int i;
184 
185 	/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
186 	for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
187 		const SalStreamDescription *ss=&md->streams[i];
188 		if (!sal_stream_description_active(ss)) continue;
189 		if (ss->dir==stream_dir) {
190 			return TRUE;
191 		}
192 		/*compatibility check for phones that only used the null address and no attributes */
193 		if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))){
194 			return TRUE;
195 		}
196 	}
197 	return FALSE;
198 }
199 
sal_media_description_has_dir(const SalMediaDescription * md,SalStreamDir stream_dir)200 bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
201 	if (stream_dir==SalStreamRecvOnly){
202 		return has_dir(md, SalStreamRecvOnly) && !(has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv));
203 	}else if (stream_dir==SalStreamSendOnly){
204 		return has_dir(md, SalStreamSendOnly) && !(has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv));
205 	}else if (stream_dir==SalStreamSendRecv){
206 		return has_dir(md,SalStreamSendRecv);
207 	}else{
208 		/*SalStreamInactive*/
209 		if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)  || has_dir(md,SalStreamRecvOnly))
210 			return FALSE;
211 		else return TRUE;
212 	}
213 	return FALSE;
214 }
215 
sal_stream_description_active(const SalStreamDescription * sd)216 bool_t sal_stream_description_active(const SalStreamDescription *sd) {
217 	return (sd->rtp_port > 0);
218 }
219 
220 /*these are switch case, so that when a new proto is added we can't forget to modify this function*/
sal_stream_description_has_avpf(const SalStreamDescription * sd)221 bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) {
222 	switch (sd->proto){
223 		case SalProtoRtpAvpf:
224 		case SalProtoRtpSavpf:
225 		case SalProtoUdpTlsRtpSavpf:
226 			return TRUE;
227 		case SalProtoRtpAvp:
228 		case SalProtoRtpSavp:
229 		case SalProtoUdpTlsRtpSavp:
230 		case SalProtoOther:
231 			return FALSE;
232 	}
233 	return FALSE;
234 }
235 
sal_stream_description_has_ipv6(const SalStreamDescription * sd)236 bool_t sal_stream_description_has_ipv6(const SalStreamDescription *sd){
237 	return strchr(sd->rtp_addr,':') != NULL;
238 }
239 
sal_stream_description_has_implicit_avpf(const SalStreamDescription * sd)240 bool_t sal_stream_description_has_implicit_avpf(const SalStreamDescription *sd){
241 	return sd->implicit_rtcp_fb;
242 }
243 /*these are switch case, so that when a new proto is added we can't forget to modify this function*/
sal_stream_description_has_srtp(const SalStreamDescription * sd)244 bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) {
245 	switch (sd->proto){
246 		case SalProtoRtpSavp:
247 		case SalProtoRtpSavpf:
248 			return TRUE;
249 		case SalProtoRtpAvp:
250 		case SalProtoRtpAvpf:
251 		case SalProtoUdpTlsRtpSavpf:
252 		case SalProtoUdpTlsRtpSavp:
253 		case SalProtoOther:
254 			return FALSE;
255 	}
256 	return FALSE;
257 }
258 
sal_stream_description_has_dtls(const SalStreamDescription * sd)259 bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd) {
260 	switch (sd->proto){
261 		case SalProtoUdpTlsRtpSavpf:
262 		case SalProtoUdpTlsRtpSavp:
263 			return TRUE;
264 		case SalProtoRtpSavp:
265 		case SalProtoRtpSavpf:
266 		case SalProtoRtpAvp:
267 		case SalProtoRtpAvpf:
268 		case SalProtoOther:
269 			return FALSE;
270 	}
271 	return FALSE;
272 }
273 
sal_stream_description_has_zrtp(const SalStreamDescription * sd)274 bool_t sal_stream_description_has_zrtp(const SalStreamDescription *sd) {
275 	if (sd->haveZrtpHash==1) return TRUE;
276 	return FALSE;
277 }
278 
sal_media_description_has_avpf(const SalMediaDescription * md)279 bool_t sal_media_description_has_avpf(const SalMediaDescription *md) {
280 	int i;
281 	if (md->nb_streams == 0) return FALSE;
282 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
283 		if (!sal_stream_description_active(&md->streams[i])) continue;
284 		if (sal_stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE;
285 	}
286 	return TRUE;
287 }
288 
sal_media_description_has_implicit_avpf(const SalMediaDescription * md)289 bool_t sal_media_description_has_implicit_avpf(const SalMediaDescription *md) {
290     int i;
291     if (md->nb_streams == 0) return FALSE;
292     for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
293         if (!sal_stream_description_active(&md->streams[i])) continue;
294         if (sal_stream_description_has_implicit_avpf(&md->streams[i]) != TRUE) return FALSE;
295     }
296     return TRUE;
297 }
298 
sal_media_description_has_srtp(const SalMediaDescription * md)299 bool_t sal_media_description_has_srtp(const SalMediaDescription *md) {
300 	int i;
301 	if (md->nb_streams == 0) return FALSE;
302 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
303 		if (!sal_stream_description_active(&md->streams[i])) continue;
304 		if (sal_stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE;
305 	}
306 	return TRUE;
307 }
308 
sal_media_description_has_dtls(const SalMediaDescription * md)309 bool_t sal_media_description_has_dtls(const SalMediaDescription *md) {
310 	int i;
311 	if (md->nb_streams == 0) return FALSE;
312 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
313 		if (!sal_stream_description_active(&md->streams[i])) continue;
314 		if (sal_stream_description_has_dtls(&md->streams[i]) != TRUE) return FALSE;
315 	}
316 	return TRUE;
317 }
318 
sal_media_description_has_zrtp(const SalMediaDescription * md)319 bool_t sal_media_description_has_zrtp(const SalMediaDescription *md) {
320 	int i;
321 	if (md->nb_streams == 0) return FALSE;
322 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
323 		if (!sal_stream_description_active(&md->streams[i])) continue;
324 		if (sal_stream_description_has_zrtp(&md->streams[i]) != TRUE) return FALSE;
325 	}
326 	return TRUE;
327 }
328 
sal_media_description_has_ipv6(const SalMediaDescription * md)329 bool_t sal_media_description_has_ipv6(const SalMediaDescription *md){
330 	int i;
331 	if (md->nb_streams == 0) return FALSE;
332 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
333 		if (!sal_stream_description_active(&md->streams[i])) continue;
334 		if (md->streams[i].rtp_addr[0] != '\0'){
335 			if (!sal_stream_description_has_ipv6(&md->streams[i])) return FALSE;
336 		}else{
337 			if (strchr(md->addr,':') == NULL) return FALSE;
338 		}
339 	}
340 	return TRUE;
341 }
342 
343 /*
344 static bool_t fmtp_equals(const char *p1, const char *p2){
345 	if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
346 	if (p1==NULL && p2==NULL) return TRUE;
347 	return FALSE;
348 }
349 */
350 
payload_type_equals(const PayloadType * p1,const PayloadType * p2)351 static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
352 	if (p1->type!=p2->type) return FALSE;
353 	if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE;
354 	if (p1->clock_rate!=p2->clock_rate) return FALSE;
355 	if (p1->channels!=p2->channels) return FALSE;
356 	if (payload_type_get_number(p1) != payload_type_get_number(p2)) return FALSE;
357 	/*
358 	 Do not compare fmtp right now: they are modified internally when the call is started
359 	*/
360 	/*
361 	if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
362 		!fmtp_equals(p1->send_fmtp,p2->send_fmtp))
363 		return FALSE;
364 	*/
365 	return TRUE;
366 }
367 
is_recv_only(PayloadType * p)368 static bool_t is_recv_only(PayloadType *p){
369 	return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND);
370 }
371 
payload_list_equals(const bctbx_list_t * l1,const bctbx_list_t * l2)372 static bool_t payload_list_equals(const bctbx_list_t *l1, const bctbx_list_t *l2){
373 	const bctbx_list_t *e1,*e2;
374 	for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
375 		PayloadType *p1=(PayloadType*)e1->data;
376 		PayloadType *p2=(PayloadType*)e2->data;
377 		if (!payload_type_equals(p1,p2))
378 			return FALSE;
379 	}
380 	if (e1!=NULL){
381 		/*skip possible recv-only payloads*/
382 		for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){
383 			ms_message("Skipping recv-only payload type...");
384 		}
385 	}
386 	if (e1!=NULL || e2!=NULL){
387 		/*means one list is longer than the other*/
388 		return FALSE;
389 	}
390 	return TRUE;
391 }
392 
sal_stream_description_equals(const SalStreamDescription * sd1,const SalStreamDescription * sd2)393 int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
394 	int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
395 	int i;
396 
397 	/* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change
398 	   needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */
399 	if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
400 	for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
401 		if ((sd1->crypto[i].tag != sd2->crypto[i].tag)
402 			|| (sd1->crypto[i].algo != sd2->crypto[i].algo)){
403 			result|=SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED;
404 		}
405 		if ((strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) {
406 			result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED;
407 		}
408 	}
409 
410 	if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
411 	if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
412 	if (sd1->rtp_addr[0]!='\0' && sd2->rtp_addr[0]!='\0' && ms_is_multicast(sd1->rtp_addr) != ms_is_multicast(sd2->rtp_addr))
413 			result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED;
414 	if (sd1->rtp_port != sd2->rtp_port) {
415 		if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
416 		else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
417 	}
418 	if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
419 	if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
420 	if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
421 	if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
422 	if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
423 	if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
424 
425 	/* ICE */
426 	if (strcmp(sd1->ice_ufrag, sd2->ice_ufrag) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED;
427 	if (strcmp(sd1->ice_pwd, sd2->ice_pwd) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED;
428 
429 	/*DTLS*/
430 	if (sd1->dtls_role != sd2->dtls_role) result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED;
431 	if (strcmp(sd1->dtls_fingerprint, sd2->dtls_fingerprint) != 0) result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED;
432 
433 	return result;
434 }
435 
sal_media_description_print_differences(int result)436 char * sal_media_description_print_differences(int result){
437 	char *out = NULL;
438 	if (result & SAL_MEDIA_DESCRIPTION_CODEC_CHANGED){
439 		out = ms_strcat_printf(out, "%s ", "CODEC_CHANGED");
440 		result &= ~SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
441 	}
442 	if (result & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED){
443 		out = ms_strcat_printf(out, "%s ", "NETWORK_CHANGED");
444 		result &= ~SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
445 	}
446 	if (result & SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED){
447 		out = ms_strcat_printf(out, "%s ", "ICE_RESTART_DETECTED");
448 		result &= ~SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED;
449 	}
450 	if (result & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED){
451 		out = ms_strcat_printf(out, "%s ", "CRYPTO_KEYS_CHANGED");
452 		result &= ~SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED;
453 	}
454 	if (result & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED){
455 		out = ms_strcat_printf(out, "%s ", "NETWORK_XXXCAST_CHANGED");
456 		result &= ~SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED;
457 	}
458 	if (result & SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED){
459 		out = ms_strcat_printf(out, "%s ", "STREAMS_CHANGED");
460 		result &= ~SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED;
461 	}
462 	if (result & SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED){
463 		out = ms_strcat_printf(out, "%s ", "CRYPTO_POLICY_CHANGED");
464 		result &= ~SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED;
465 	}
466 	if (result & SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION){
467 		out = ms_strcat_printf(out, "%s ", "FORCE_STREAM_RECONSTRUCTION");
468 		result &= ~SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION;
469 	}
470 	if (result){
471 		ms_fatal("There are unhandled result bitmasks in sal_media_description_print_differences(), fix it");
472 	}
473 	if (!out) out = ms_strdup("NONE");
474 	return out;
475 }
476 
sal_media_description_equals(const SalMediaDescription * md1,const SalMediaDescription * md2)477 int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
478 	int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
479 	int i;
480 
481 	if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
482 	if (md1->addr[0]!='\0' && md2->addr[0]!='\0' && ms_is_multicast(md1->addr) != ms_is_multicast(md2->addr))
483 		result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED;
484 	if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED;
485 	if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
486 
487 	/* ICE */
488 	if (strcmp(md1->ice_ufrag, md2->ice_ufrag) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED;
489 	if (strcmp(md1->ice_pwd, md2->ice_pwd) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED;
490 
491 	for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
492 		if (!sal_stream_description_active(&md1->streams[i]) && !sal_stream_description_active(&md2->streams[i])) continue;
493 		result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]);
494 	}
495 	return result;
496 }
497 
assign_address(SalAddress ** address,const char * value)498 static void assign_address(SalAddress** address, const char *value){
499 	if (*address){
500 		sal_address_destroy(*address);
501 		*address=NULL;
502 	}
503 	if (value)
504 		*address=sal_address_new(value);
505 }
506 
assign_string(char ** str,const char * arg)507 static void assign_string(char **str, const char *arg){
508 	if (*str){
509 		ms_free(*str);
510 		*str=NULL;
511 	}
512 	if (arg)
513 		*str=ms_strdup(arg);
514 }
515 
sal_op_set_contact_address(SalOp * op,const SalAddress * address)516 void sal_op_set_contact_address(SalOp *op, const SalAddress *address){
517 	if (((SalOpBase*)op)->contact_address) sal_address_destroy(((SalOpBase*)op)->contact_address);
518 	((SalOpBase*)op)->contact_address=address?sal_address_clone(address):NULL;
519 }
sal_op_get_contact_address(const SalOp * op)520 const SalAddress* sal_op_get_contact_address(const SalOp *op) {
521 	return ((SalOpBase*)op)->contact_address;
522 }
523 
sal_op_get_remote_contact_address(const SalOp * op)524 const SalAddress*sal_op_get_remote_contact_address(const SalOp* op)
525 {
526 	return ((SalOpBase*)op)->remote_contact_address;
527 }
528 
529 #define SET_PARAM(op,name) \
530 		char* name##_string=NULL; \
531 		assign_address(&((SalOpBase*)op)->name##_address,name); \
532 		if (((SalOpBase*)op)->name##_address) { \
533 			name##_string=sal_address_as_string(((SalOpBase*)op)->name##_address); \
534 		}\
535 		assign_string(&((SalOpBase*)op)->name,name##_string); \
536 		if(name##_string) ms_free(name##_string);
537 
538 
sal_op_set_route(SalOp * op,const char * route)539 void sal_op_set_route(SalOp *op, const char *route){
540 	char* route_string=(void *)0;
541 	SalOpBase* op_base = (SalOpBase*)op;
542 	if (op_base->route_addresses) {
543 		bctbx_list_for_each(op_base->route_addresses,(void (*)(void *))sal_address_destroy);
544 		op_base->route_addresses=bctbx_list_free(op_base->route_addresses);
545 	}
546 	if (route) {
547 		op_base->route_addresses=bctbx_list_append(NULL,NULL);
548 		assign_address((SalAddress**)&(op_base->route_addresses->data),route);
549 		route_string=sal_address_as_string((SalAddress*)op_base->route_addresses->data); \
550 	}
551 	assign_string(&op_base->route,route_string); \
552 	if(route_string) ms_free(route_string);
553 }
sal_op_get_route_addresses(const SalOp * op)554 const bctbx_list_t* sal_op_get_route_addresses(const SalOp *op) {
555 	return ((SalOpBase*)op)->route_addresses;
556 }
sal_op_set_route_address(SalOp * op,const SalAddress * address)557 void sal_op_set_route_address(SalOp *op, const SalAddress *address){
558 	char* address_string=sal_address_as_string(address); /*can probably be optimized*/
559 	sal_op_set_route(op,address_string);
560 	ms_free(address_string);
561 }
sal_op_add_route_address(SalOp * op,const SalAddress * address)562 void sal_op_add_route_address(SalOp *op, const SalAddress *address){
563 	SalOpBase* op_base = (SalOpBase*)op;
564 	if (op_base->route_addresses) {
565 		op_base->route_addresses=bctbx_list_append(op_base->route_addresses,(void*)sal_address_clone(address));
566 	} else {
567 		sal_op_set_route_address(op,address);
568 	}
569 }
sal_op_set_realm(SalOp * op,const char * realm)570 void sal_op_set_realm(SalOp *op, const char *realm){
571 	SalOpBase* op_base = (SalOpBase*)op;
572 	if (op_base->realm != NULL){
573 		ms_free(op_base->realm);
574 	}
575 	op_base->realm = ms_strdup(realm);
576 }
sal_op_set_from(SalOp * op,const char * from)577 void sal_op_set_from(SalOp *op, const char *from){
578 	SET_PARAM(op,from);
579 }
sal_op_set_from_address(SalOp * op,const SalAddress * from)580 void sal_op_set_from_address(SalOp *op, const SalAddress *from){
581 	char* address_string=sal_address_as_string(from); /*can probably be optimized*/
582 	sal_op_set_from(op,address_string);
583 	ms_free(address_string);
584 }
sal_op_set_to(SalOp * op,const char * to)585 void sal_op_set_to(SalOp *op, const char *to){
586 	SET_PARAM(op,to);
587 }
sal_op_set_to_address(SalOp * op,const SalAddress * to)588 void sal_op_set_to_address(SalOp *op, const SalAddress *to){
589 	char* address_string=sal_address_as_string(to); /*can probably be optimized*/
590 	sal_op_set_to(op,address_string);
591 	ms_free(address_string);
592 }
sal_op_set_diversion_address(SalOp * op,const SalAddress * diversion)593 void sal_op_set_diversion_address(SalOp *op, const SalAddress *diversion){
594 	if (((SalOpBase*)op)->diversion_address) sal_address_destroy(((SalOpBase*)op)->diversion_address);
595 	((SalOpBase*)op)->diversion_address=diversion?sal_address_clone(diversion):NULL;
596 }
sal_op_set_user_pointer(SalOp * op,void * up)597 void sal_op_set_user_pointer(SalOp *op, void *up){
598 	((SalOpBase*)op)->user_pointer=up;
599 }
600 
sal_op_get_sal(const SalOp * op)601 Sal *sal_op_get_sal(const SalOp *op){
602 	return ((SalOpBase*)op)->root;
603 }
604 
sal_op_get_from(const SalOp * op)605 const char *sal_op_get_from(const SalOp *op){
606 	return ((SalOpBase*)op)->from;
607 }
sal_op_get_from_address(const SalOp * op)608 const SalAddress *sal_op_get_from_address(const SalOp *op){
609 	return ((SalOpBase*)op)->from_address;
610 }
611 
sal_op_get_to(const SalOp * op)612 const char *sal_op_get_to(const SalOp *op){
613 	return ((SalOpBase*)op)->to;
614 }
615 
sal_op_get_to_address(const SalOp * op)616 const SalAddress *sal_op_get_to_address(const SalOp *op){
617 	return ((SalOpBase*)op)->to_address;
618 }
619 
sal_op_get_diversion_address(const SalOp * op)620 const SalAddress *sal_op_get_diversion_address(const SalOp *op){
621 	return ((SalOpBase*)op)->diversion_address;
622 }
623 
sal_op_get_remote_ua(const SalOp * op)624 const char *sal_op_get_remote_ua(const SalOp *op){
625 	return ((SalOpBase*)op)->remote_ua;
626 }
627 
sal_op_get_user_pointer(const SalOp * op)628 void *sal_op_get_user_pointer(const SalOp *op){
629 	return ((SalOpBase*)op)->user_pointer;
630 }
631 
sal_op_get_proxy(const SalOp * op)632 const char *sal_op_get_proxy(const SalOp *op){
633 	return ((SalOpBase*)op)->route;
634 }
635 
sal_op_get_network_origin(const SalOp * op)636 const char *sal_op_get_network_origin(const SalOp *op){
637 	return ((SalOpBase*)op)->origin;
638 }
sal_op_get_call_id(const SalOp * op)639 const char* sal_op_get_call_id(const SalOp *op) {
640 	return  ((SalOpBase*)op)->call_id;
641 }
642 
__sal_op_init(SalOp * b,Sal * sal)643 void __sal_op_init(SalOp *b, Sal *sal){
644 	memset(b,0,sizeof(SalOpBase));
645 	((SalOpBase*)b)->root=sal;
646 }
647 
__sal_op_set_network_origin(SalOp * op,const char * origin)648 void __sal_op_set_network_origin(SalOp *op, const char *origin){
649 	SET_PARAM(op,origin);
650 }
651 
__sal_op_set_remote_contact(SalOp * op,const char * remote_contact)652 void __sal_op_set_remote_contact(SalOp *op, const char* remote_contact){
653 	assign_address(&((SalOpBase*)op)->remote_contact_address,remote_contact);\
654 	/*to preserve header params*/
655 	assign_string(&((SalOpBase*)op)->remote_contact,remote_contact); \
656 }
657 
__sal_op_set_network_origin_address(SalOp * op,SalAddress * origin)658 void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){
659 	char* address_string=sal_address_as_string(origin); /*can probably be optimized*/
660 	__sal_op_set_network_origin(op,address_string);
661 	ms_free(address_string);
662 }
663 
__sal_op_free(SalOp * op)664 void __sal_op_free(SalOp *op){
665 	SalOpBase *b=(SalOpBase *)op;
666 	if (b->from_address){
667 		sal_address_destroy(b->from_address);
668 		b->from_address=NULL;
669 	}
670 	if (b->to_address){
671 		sal_address_destroy(b->to_address);
672 		b->to_address=NULL;
673 	}
674 
675 	if (b->service_route){
676 		sal_address_destroy(b->service_route);
677 		b->service_route=NULL;
678 	}
679 
680 	if (b->origin_address){
681 		sal_address_destroy(b->origin_address);
682 		b->origin_address=NULL;
683 	}
684 
685 	if (b->from) {
686 		ms_free(b->from);
687 		b->from=NULL;
688 	}
689 	if (b->to) {
690 		ms_free(b->to);
691 		b->to=NULL;
692 	}
693 	if (b->route) {
694 		ms_free(b->route);
695 		b->route=NULL;
696 	}
697 	if (b->realm) {
698 		ms_free(b->realm);
699 		b->realm=NULL;
700 	}
701 	if (b->contact_address) {
702 		sal_address_destroy(b->contact_address);
703 	}
704 	if (b->origin){
705 		ms_free(b->origin);
706 		b->origin=NULL;
707 	}
708 	if (b->remote_ua){
709 		ms_free(b->remote_ua);
710 		b->remote_ua=NULL;
711 	}
712 	if (b->remote_contact){
713 		ms_free(b->remote_contact);
714 		b->remote_contact=NULL;
715 	}
716 	if (b->remote_contact_address){
717 		sal_address_destroy(b->remote_contact_address);
718 	}
719 	if (b->local_media)
720 		sal_media_description_unref(b->local_media);
721 	if (b->remote_media)
722 		sal_media_description_unref(b->remote_media);
723 	if (b->call_id)
724 		ms_free((void*)b->call_id);
725 	if (b->service_route) {
726 		sal_address_destroy(b->service_route);
727 	}
728 	if (b->route_addresses){
729 		bctbx_list_for_each(b->route_addresses,(void (*)(void*)) sal_address_destroy);
730 		b->route_addresses=bctbx_list_free(b->route_addresses);
731 	}
732 	if (b->recv_custom_headers)
733 		sal_custom_header_free(b->recv_custom_headers);
734 	if (b->sent_custom_headers)
735 		sal_custom_header_free(b->sent_custom_headers);
736 
737 	if (b->entity_tag != NULL){
738 		ms_free(b->entity_tag);
739 		b->entity_tag = NULL;
740 	}
741 	ms_free(op);
742 }
743 
sal_auth_info_new()744 SalAuthInfo* sal_auth_info_new() {
745 	return ms_new0(SalAuthInfo,1);
746 }
747 
sal_auth_info_clone(const SalAuthInfo * auth_info)748 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
749 	SalAuthInfo* new_auth_info=sal_auth_info_new();
750 	new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
751 	new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
752 	new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
753 	new_auth_info->domain=auth_info->realm?ms_strdup(auth_info->domain):NULL;
754 	new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
755 	return new_auth_info;
756 }
757 
sal_auth_info_delete(SalAuthInfo * auth_info)758 void sal_auth_info_delete(SalAuthInfo* auth_info) {
759 	if (auth_info->username) ms_free(auth_info->username);
760 	if (auth_info->userid) ms_free(auth_info->userid);
761 	if (auth_info->realm) ms_free(auth_info->realm);
762 	if (auth_info->domain) ms_free(auth_info->domain);
763 	if (auth_info->password) ms_free(auth_info->password);
764 	if (auth_info->ha1) ms_free(auth_info->ha1);
765 	if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates);
766 	if (auth_info->key) sal_signing_key_delete(auth_info->key);
767 	ms_free(auth_info);
768 }
769 
770 
771 
sal_stream_type_to_string(SalStreamType type)772 const char* sal_stream_type_to_string(SalStreamType type) {
773 	switch (type) {
774 	case SalAudio: return "audio";
775 	case SalVideo: return "video";
776 	case SalText: return "text";
777 	default: return "other";
778 	}
779 }
780 
sal_stream_description_get_type_as_string(const SalStreamDescription * desc)781 const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc){
782 	if (desc->type==SalOther) return desc->typeother;
783 	else return sal_stream_type_to_string(desc->type);
784 }
785 
sal_media_proto_to_string(SalMediaProto type)786 const char* sal_media_proto_to_string(SalMediaProto type) {
787 	switch (type) {
788 	case SalProtoRtpAvp:return "RTP/AVP";
789 	case SalProtoRtpSavp:return "RTP/SAVP";
790 	case SalProtoUdpTlsRtpSavp:return "UDP/TLS/RTP/SAVP";
791 	case SalProtoRtpAvpf:return "RTP/AVPF";
792 	case SalProtoRtpSavpf:return "RTP/SAVPF";
793 	case SalProtoUdpTlsRtpSavpf:return "UDP/TLS/RTP/SAVPF";
794 	default: return "unknown";
795 	}
796 }
797 
sal_stream_description_get_proto_as_string(const SalStreamDescription * desc)798 const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc){
799 	if (desc->proto==SalProtoOther) return desc->proto_other;
800 	else return sal_media_proto_to_string(desc->proto);
801 }
802 
803 
sal_stream_dir_to_string(SalStreamDir type)804 const char* sal_stream_dir_to_string(SalStreamDir type) {
805 	switch (type) {
806 	case SalStreamSendRecv:return "sendrecv";
807 	case SalStreamSendOnly:return "sendonly";
808 	case SalStreamRecvOnly:return "recvonly";
809 	case SalStreamInactive:return "inative";
810 	default: return "unknown";
811 	}
812 
813 }
814 
sal_reason_to_string(const SalReason reason)815 const char* sal_reason_to_string(const SalReason reason) {
816 	switch (reason) {
817 	case SalReasonDeclined : return "SalReasonDeclined";
818 	case SalReasonBusy: return "SalReasonBusy";
819 	case SalReasonRedirect: return "SalReasonRedirect";
820 	case SalReasonTemporarilyUnavailable: return "SalReasonTemporarilyUnavailable";
821 	case SalReasonNotFound: return "SalReasonNotFound";
822 	case SalReasonDoNotDisturb: return "SalReasonDoNotDisturb";
823 	case SalReasonUnsupportedContent: return "SalReasonUnsupportedContent";
824 	case SalReasonForbidden: return "SalReasonForbidden";
825 	case SalReasonUnknown: return "SalReasonUnknown";
826 	case SalReasonServiceUnavailable: return "SalReasonServiceUnavailable";
827 	case SalReasonNotAcceptable: return "SalReasonNotAcceptable";
828 	default: return "Unkown reason";
829 	}
830 }
sal_op_get_service_route(const SalOp * op)831 const SalAddress* sal_op_get_service_route(const SalOp *op) {
832 	return ((SalOpBase*)op)->service_route;
833 }
sal_op_set_service_route(SalOp * op,const SalAddress * service_route)834 void sal_op_set_service_route(SalOp *op,const SalAddress* service_route) {
835 	if (((SalOpBase*)op)->service_route)
836 		sal_address_destroy(((SalOpBase*)op)->service_route);
837 
838 	((SalOpBase*)op)->service_route=service_route?sal_address_clone(service_route):NULL;
839 }
840 
sal_presence_status_to_string(const SalPresenceStatus status)841 const char* sal_presence_status_to_string(const SalPresenceStatus status) {
842 	switch (status) {
843 	case SalPresenceOffline: return "SalPresenceOffline";
844 	case SalPresenceOnline: return "SalPresenceOnline";
845 	case SalPresenceBusy: return "SalPresenceBusy";
846 	case SalPresenceBerightback: return "SalPresenceBerightback";
847 	case SalPresenceAway: return "SalPresenceAway";
848 	case SalPresenceOnthephone: return "SalPresenceOnthephone";
849 	case SalPresenceOuttolunch: return "SalPresenceOuttolunch";
850 	case SalPresenceDonotdisturb: return "SalPresenceDonotdisturb";
851 	case SalPresenceMoved: return "SalPresenceMoved";
852 	case SalPresenceAltService: return "SalPresenceAltService";
853 	default : return "unknown";
854 	}
855 
856 }
sal_privacy_to_string(SalPrivacy privacy)857 const char* sal_privacy_to_string(SalPrivacy privacy) {
858 	switch(privacy) {
859 	case SalPrivacyUser: return "user";
860 	case SalPrivacyHeader: return "header";
861 	case SalPrivacySession: return "session";
862 	case SalPrivacyId: return "id";
863 	case SalPrivacyNone: return "none";
864 	case SalPrivacyCritical: return "critical";
865 	default: return NULL;
866 	}
867 }
868 
remove_trailing_spaces(char * line)869 static void remove_trailing_spaces(char *line) {
870 	size_t size = size = strlen(line);
871 	char *end = line + size - 1;
872 	while (end >= line && isspace(*end)) {
873 		end--;
874 	}
875     *(end + 1) = '\0';
876 }
877 
line_get_value(const char * input,const char * key,char * value,size_t value_size,size_t * read)878 static int line_get_value(const char *input, const char *key, char *value, size_t value_size, size_t *read){
879 	const char *end=strchr(input,'\n');
880 	char line[256]={0};
881 	char key_candidate[256];
882 	char *equal;
883 	size_t len;
884 	if (!end) len=strlen(input);
885 	else len=end +1 -input;
886 	*read=len;
887 	strncpy(line,input,MIN(len,sizeof(line)));
888 	equal=strchr(line,'=');
889 	if (!equal) return FALSE;
890 	*equal='\0';
891 	if (sscanf(line,"%s",key_candidate)!=1) return FALSE;
892 	if (strcasecmp(key,key_candidate)==0){
893 		equal++;
894 		remove_trailing_spaces(equal);
895 		strncpy(value,equal,value_size-1);
896 		value[value_size-1]='\0';
897 		return TRUE;
898 	}
899 	return FALSE;
900 }
901 
sal_lines_get_value(const char * data,const char * key,char * value,size_t value_size)902 int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size){
903 	size_t read=0;
904 
905 	do{
906 		if (line_get_value(data,key,value,value_size,&read))
907 			return TRUE;
908 		data+=read;
909 	}while(read!=0);
910 	return FALSE;
911 }
912 
sal_op_get_entity_tag(const SalOp * op)913 const char *sal_op_get_entity_tag(const SalOp* op) {
914 	SalOpBase* op_base = (SalOpBase*)op;
915 	return op_base->entity_tag;
916 }
917 
918 
sal_op_set_entity_tag(SalOp * op,const char * entity_tag)919 void sal_op_set_entity_tag(SalOp *op, const char* entity_tag) {
920 	SalOpBase* op_base = (SalOpBase*)op;
921 	if (op_base->entity_tag != NULL){
922 		ms_free(op_base->entity_tag);
923 	}
924 	if (entity_tag)
925 		op_base->entity_tag = ms_strdup(entity_tag);
926 	else
927 		op_base->entity_tag = NULL;
928 }
929 
930