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