1
2 /*
3 linphone
4 Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include "private.h"
22 #include "linphone/lpconfig.h"
23 #include "linphone/wrapper_utils.h"
24 #include "mediastreamer2/mediastream.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #ifdef HAVE_SIGHANDLER_T
29 #include <signal.h>
30 #endif /*HAVE_SIGHANDLER_T*/
31
32 #include <string.h>
33 #if !defined(_WIN32_WCE)
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #if _MSC_VER
38 #include <io.h>
39 #else
40 #include <unistd.h>
41 #endif
42 #include <fcntl.h>
43 #endif /*_WIN32_WCE*/
44
45 #undef snprintf
46 #include <mediastreamer2/stun.h>
47
48 #ifdef HAVE_GETIFADDRS
49 #include <net/if.h>
50 #include <ifaddrs.h>
51 #endif
52 #include <math.h>
53 #if _MSC_VER
54 #define snprintf _snprintf
55 #define popen _popen
56 #define pclose _pclose
57 #endif
58
59
60 #define UDP_HDR_SZ 8
61 #define RTP_HDR_SZ 12
62 #define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/
63
64 static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed);
65
66
67 /*
68 *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime;
69 *ptime=1/npacket
70 */
71
get_audio_payload_bandwidth_from_codec_bitrate(const PayloadType * pt)72 static double get_audio_payload_bandwidth_from_codec_bitrate(const PayloadType *pt){
73 double npacket=50;
74 double packet_size;
75 int bitrate;
76
77 if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt))==0) {
78 /*special case of aac 44K because ptime= 10ms*/
79 npacket=100;
80 }else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt))==0) {
81 npacket=1000/30.0;
82 }
83
84 bitrate=pt->normal_bitrate;
85 packet_size= (((double)bitrate)/(npacket*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
86 return packet_size*8.0*npacket;
87 }
88
89 typedef struct vbr_codec_bitrate{
90 int max_avail_bitrate;
91 int min_rate;
92 int recomended_bitrate;
93 }vbr_codec_bitrate_t;
94
95 static vbr_codec_bitrate_t defauls_vbr[]={
96 //{ 100, 44100, 100 },
97 { 64, 44100, 50 },
98 { 64, 16000, 40 },
99 { 32, 16000, 32 },
100 { 32, 8000, 32 },
101 { 0 , 8000, 24 },
102 { 0 , 0, 0 }
103 };
104
lookup_vbr_typical_bitrate(int maxbw,int clock_rate)105 static int lookup_vbr_typical_bitrate(int maxbw, int clock_rate){
106 vbr_codec_bitrate_t *it;
107 if (maxbw<=0) maxbw=defauls_vbr[0].max_avail_bitrate;
108 for(it=defauls_vbr;it->min_rate!=0;it++){
109 if (maxbw>=it->max_avail_bitrate && clock_rate>=it->min_rate)
110 return it->recomended_bitrate;
111 }
112 ms_error("lookup_vbr_typical_bitrate(): should not happen.");
113 return 32;
114 }
115
get_audio_payload_bandwidth(const LinphoneCore * lc,const PayloadType * pt,int maxbw)116 int get_audio_payload_bandwidth(const LinphoneCore *lc, const PayloadType *pt, int maxbw) {
117 if (payload_type_is_vbr(pt)) {
118 if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){
119 ms_debug("PayloadType %s/%i has bitrate override",pt->mime_type,pt->clock_rate);
120 return pt->normal_bitrate/1000;
121 }
122 return lookup_vbr_typical_bitrate(maxbw,pt->clock_rate);
123 }else return (int)ceil(get_audio_payload_bandwidth_from_codec_bitrate(pt)/1000.0);/*rounding codec bandwidth should be avoid, specially for AMR*/
124 }
125
linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall * call,const PayloadType * pt,int maxbw)126 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw){
127 call->audio_bw=get_audio_payload_bandwidth(call->core,pt,maxbw);
128 ms_message("Audio bandwidth for this call is %i",call->audio_bw);
129 }
130
linphone_core_update_allocated_audio_bandwidth(LinphoneCore * lc)131 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
132 const bctbx_list_t *elem;
133 int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
134 linphone_core_get_upload_bandwidth(lc));
135 int max_codec_bitrate=0;
136
137 for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
138 PayloadType *pt=(PayloadType*)elem->data;
139 if (payload_type_enabled(pt)){
140 int pt_bitrate=get_audio_payload_bandwidth(lc,pt,maxbw);
141 if (max_codec_bitrate==0) {
142 max_codec_bitrate=pt_bitrate;
143 }else if (max_codec_bitrate<pt_bitrate){
144 max_codec_bitrate=pt_bitrate;
145 }
146 }
147 }
148 if (max_codec_bitrate) {
149 lc->audio_bw=max_codec_bitrate;
150 }
151 }
152
linphone_core_is_payload_type_usable_for_bandwidth(const LinphoneCore * lc,const PayloadType * pt,int bandwidth_limit)153 bool_t linphone_core_is_payload_type_usable_for_bandwidth(const LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit){
154 double codec_band;
155 const int video_enablement_limit = 99;
156 bool_t ret=FALSE;
157
158 switch (pt->type){
159 case PAYLOAD_AUDIO_CONTINUOUS:
160 case PAYLOAD_AUDIO_PACKETIZED:
161 codec_band=get_audio_payload_bandwidth(lc,pt,bandwidth_limit);
162 ret=bandwidth_is_greater(bandwidth_limit,(int)codec_band);
163 /*ms_message("Payload %s: codec_bandwidth=%g, bandwidth_limit=%i",pt->mime_type,codec_band,bandwidth_limit);*/
164 break;
165 case PAYLOAD_VIDEO:
166 if (bandwidth_limit<=0 || bandwidth_limit >= video_enablement_limit) {/* infinite or greater than video_enablement_limit*/
167 ret=TRUE;
168 }
169 else ret=FALSE;
170 break;
171 case PAYLOAD_TEXT:
172 ret=TRUE;
173 break;
174 }
175 return ret;
176 }
177
lp_spawn_command_line_sync(const char * command,char ** result,int * command_ret)178 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
179 #if !defined(_WIN32_WCE) && !defined(LINPHONE_WINDOWS_UNIVERSAL)
180 FILE *f=popen(command,"r");
181 if (f!=NULL){
182 int err;
183 *result=ms_malloc(4096);
184 err=(int)fread(*result,1,4096-1,f);
185 if (err<0){
186 ms_warning("Error reading command output:%s",strerror(errno));
187 ms_free(result);
188 return FALSE;
189 }
190 (*result)[err]=0;
191 err=pclose(f);
192 if (command_ret!=NULL) *command_ret=err;
193 return TRUE;
194 }
195 #endif /*_WIN32_WCE*/
196 return FALSE;
197 }
198
create_socket(int local_port)199 static ortp_socket_t create_socket(int local_port){
200 struct sockaddr_in laddr;
201 ortp_socket_t sock;
202 int optval;
203 sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
204 if (sock<0) {
205 ms_error("Fail to create socket");
206 return -1;
207 }
208 memset (&laddr,0,sizeof(laddr));
209 laddr.sin_family=AF_INET;
210 laddr.sin_addr.s_addr=INADDR_ANY;
211 laddr.sin_port=htons(local_port);
212 if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
213 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
214 close_socket(sock);
215 return -1;
216 }
217 optval=1;
218 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
219 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
220 ms_warning("Fail to set SO_REUSEADDR");
221 }
222 set_non_blocking_socket(sock);
223 return sock;
224 }
225
send_stun_request(int sock,const struct sockaddr * server,socklen_t addrlen,int id,bool_t change_addr)226 static int send_stun_request(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t change_addr){
227 char *buf = NULL;
228 size_t len;
229 int err = 0;
230 MSStunMessage *req = ms_stun_binding_request_create();
231 UInt96 tr_id = ms_stun_message_get_tr_id(req);
232 tr_id.octet[0] = id;
233 ms_stun_message_set_tr_id(req, tr_id);
234 ms_stun_message_enable_change_ip(req, change_addr);
235 ms_stun_message_enable_change_port(req, change_addr);
236 len = ms_stun_message_encode(req, &buf);
237 if (len <= 0) {
238 ms_error("Fail to encode stun message.");
239 err = -1;
240 } else {
241 err = bctbx_sendto(sock, buf, len, 0, server, addrlen);
242 if (err < 0) {
243 ms_error("sendto failed: %s",strerror(errno));
244 err = -1;
245 }
246 }
247 if (buf != NULL) ms_free(buf);
248 ms_free(req);
249 return err;
250 }
251
linphone_parse_host_port(const char * input,char * host,size_t hostlen,int * port)252 int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port){
253 char tmphost[NI_MAXHOST]={0};
254 char *p1, *p2;
255
256 if ((sscanf(input, "[%64[^]]]:%d", tmphost, port) == 2) || (sscanf(input, "[%64[^]]]", tmphost) == 1)) {
257
258 } else {
259 p1 = strchr(input, ':');
260 p2 = strrchr(input, ':');
261 if (p1 && p2 && (p1 != p2)) {/* an ipv6 address without port*/
262 strncpy(tmphost, input, sizeof(tmphost) - 1);
263 } else if (sscanf(input, "%[^:]:%d", tmphost, port) != 2) {
264 /*no port*/
265 strncpy(tmphost, input, sizeof(tmphost) - 1);
266 }
267 }
268 strncpy(host,tmphost,hostlen);
269 return 0;
270 }
271
parse_hostname_to_addr(const char * server,struct sockaddr_storage * ss,socklen_t * socklen,int default_port)272 int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port){
273 struct addrinfo hints,*res=NULL;
274 char port[6];
275 char host[NI_MAXHOST];
276 int port_int=default_port;
277 int ret;
278
279 linphone_parse_host_port(server,host,sizeof(host),&port_int);
280
281 snprintf(port, sizeof(port), "%d", port_int);
282 memset(&hints,0,sizeof(hints));
283 hints.ai_family=AF_UNSPEC;
284 hints.ai_socktype=SOCK_DGRAM;
285 hints.ai_protocol=IPPROTO_UDP;
286 ret=getaddrinfo(host,port,&hints,&res);
287 if (ret!=0){
288 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
289 return -1;
290 }
291 if (!res) return -1;
292 memcpy(ss,res->ai_addr,res->ai_addrlen);
293 *socklen=(socklen_t)res->ai_addrlen;
294 freeaddrinfo(res);
295 return 0;
296 }
297
recv_stun_response(ortp_socket_t sock,char * ipaddr,int * port,int * id)298 static int recv_stun_response(ortp_socket_t sock, char *ipaddr, int *port, int *id) {
299 char buf[MS_STUN_MAX_MESSAGE_SIZE];
300 int len = MS_STUN_MAX_MESSAGE_SIZE;
301 MSStunMessage *resp;
302
303 len = recv(sock, buf, len, 0);
304 if (len > 0) {
305 struct in_addr ia;
306 resp = ms_stun_message_create_from_buffer_parsing((uint8_t *)buf, (ssize_t)len);
307 if (resp != NULL) {
308 const MSStunAddress *stun_addr;
309 UInt96 tr_id = ms_stun_message_get_tr_id(resp);
310 *id = tr_id.octet[0];
311 stun_addr = ms_stun_message_get_xor_mapped_address(resp);
312 if (stun_addr != NULL) {
313 *port = stun_addr->ip.v4.port;
314 ia.s_addr = htonl(stun_addr->ip.v4.addr);
315 } else {
316 stun_addr = ms_stun_message_get_mapped_address(resp);
317 if (stun_addr != NULL) {
318 *port = stun_addr->ip.v4.port;
319 ia.s_addr = htonl(stun_addr->ip.v4.addr);
320 } else len = -1;
321 }
322 if (len > 0) strncpy(ipaddr, inet_ntoa(ia), LINPHONE_IPADDR_SIZE);
323 }
324 }
325 return len;
326 }
327
328 /* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/
linphone_core_run_stun_tests(LinphoneCore * lc,LinphoneCall * call)329 int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
330 const char *server=linphone_core_get_stun_server(lc);
331 StunCandidate *ac=&call->ac;
332 StunCandidate *vc=&call->vc;
333 StunCandidate *tc=&call->tc;
334
335 if (lc->sip_conf.ipv6_enabled){
336 ms_warning("stun support is not implemented for ipv6");
337 return -1;
338 }
339 if (call->media_ports[call->main_audio_stream_index].rtp_port==-1){
340 ms_warning("Stun-only support not available for system random port");
341 return -1;
342 }
343 if (server!=NULL){
344 const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc);
345 ortp_socket_t sock1=-1, sock2=-1, sock3=-1;
346 int loops=0;
347 bool_t video_enabled=linphone_core_video_enabled(lc);
348 bool_t got_audio,got_video,got_text;
349 bool_t cone_audio=FALSE,cone_video=FALSE,cone_text=FALSE;
350 struct timeval init,cur;
351 double elapsed;
352 int ret=0;
353
354 if (ai==NULL){
355 ms_error("Could not obtain stun server addrinfo.");
356 return -1;
357 }
358 linphone_core_notify_display_status(lc,_("Stun lookup in progress..."));
359
360 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
361 sock1=create_socket(call->media_ports[call->main_audio_stream_index].rtp_port);
362 if (sock1==-1) return -1;
363 if (video_enabled){
364 sock2=create_socket(call->media_ports[call->main_video_stream_index].rtp_port);
365 if (sock2==-1) return -1;
366 }
367 sock3=create_socket(call->media_ports[call->main_text_stream_index].rtp_port);
368 if (sock3==-1) return -1;
369
370 got_audio=FALSE;
371 got_video=FALSE;
372 got_text=FALSE;
373 ortp_gettimeofday(&init,NULL);
374 do{
375
376 int id;
377 if (loops%20==0){
378 ms_message("Sending stun requests...");
379 send_stun_request((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,11,TRUE);
380 send_stun_request((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,1,FALSE);
381 if (sock2!=-1){
382 send_stun_request((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,22,TRUE);
383 send_stun_request((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,2,FALSE);
384 }
385 if (sock3!=-1){
386 send_stun_request((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,33,TRUE);
387 send_stun_request((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,3,FALSE);
388 }
389 }
390 ms_usleep(10000);
391
392 if (recv_stun_response(sock1, ac->addr, &ac->port, &id) > 0) {
393 ms_message("STUN test result: local audio port maps to %s:%i", ac->addr, ac->port);
394 if (id==11) cone_audio=TRUE;
395 got_audio=TRUE;
396 }
397 if (recv_stun_response(sock2, vc->addr, &vc->port, &id) > 0) {
398 ms_message("STUN test result: local video port maps to %s:%i", vc->addr, vc->port);
399 if (id==22) cone_video=TRUE;
400 got_video=TRUE;
401 }
402 if (recv_stun_response(sock3, tc->addr, &tc->port, &id)>0) {
403 ms_message("STUN test result: local text port maps to %s:%i", tc->addr, tc->port);
404 if (id==33) cone_text=TRUE;
405 got_text=TRUE;
406 }
407 ortp_gettimeofday(&cur,NULL);
408 elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
409 if (elapsed>2000) {
410 ms_message("Stun responses timeout, going ahead.");
411 ret=-1;
412 break;
413 }
414 loops++;
415 }while(!(got_audio && (got_video||sock2==-1) && (got_text||sock3==-1) ) );
416 if (ret==0) ret=(int)elapsed;
417 if (!got_audio){
418 ms_error("No stun server response for audio port.");
419 }else{
420 if (!cone_audio) {
421 ms_message("NAT is symmetric for audio port");
422 }
423 }
424 if (sock2!=-1){
425 if (!got_video){
426 ms_error("No stun server response for video port.");
427 }else{
428 if (!cone_video) {
429 ms_message("NAT is symmetric for video port.");
430 }
431 }
432 }
433 if (sock3!=-1){
434 if (!got_text){
435 ms_error("No stun server response for text port.");
436 }else{
437 if (!cone_text) {
438 ms_message("NAT is symmetric for text port.");
439 }
440 }
441 }
442 close_socket(sock1);
443 if (sock2!=-1) close_socket(sock2);
444 if (sock3!=-1) close_socket(sock3);
445 return ret;
446 }
447 return -1;
448 }
449
linphone_core_get_edge_bw(LinphoneCore * lc)450 int linphone_core_get_edge_bw(LinphoneCore *lc){
451 int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20);
452 return edge_bw;
453 }
454
linphone_core_get_edge_ptime(LinphoneCore * lc)455 int linphone_core_get_edge_ptime(LinphoneCore *lc){
456 int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100);
457 return edge_ptime;
458 }
459
linphone_core_adapt_to_network(LinphoneCore * lc,int ping_time_ms,LinphoneCallParams * params)460 void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){
461 int threshold;
462 if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){
463 ms_message("Stun server ping time is %i ms",ping_time_ms);
464 threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500);
465
466 if (ping_time_ms>threshold){
467 /* we might be in a 2G network*/
468 params->low_bandwidth=TRUE;
469 }/*else use default settings */
470 }
471 if (params->low_bandwidth){
472 params->up_bw=params->down_bw=linphone_core_get_edge_bw(lc);
473 params->up_ptime=params->down_ptime=linphone_core_get_edge_ptime(lc);
474 params->has_video=FALSE;
475 }
476 }
477
478
linphone_core_resolve_stun_server(LinphoneCore * lc)479 void linphone_core_resolve_stun_server(LinphoneCore *lc){
480 if (lc->nat_policy != NULL) {
481 linphone_nat_policy_resolve_stun_server(lc->nat_policy);
482 } else {
483 ms_error("linphone_core_resolve_stun_server(): called without nat_policy, this should not happen.");
484 }
485 }
486
linphone_core_get_stun_server_addrinfo(LinphoneCore * lc)487 const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc){
488 if (lc->nat_policy != NULL) {
489 return linphone_nat_policy_get_stun_server_addrinfo(lc->nat_policy);
490 } else {
491 ms_error("linphone_core_get_stun_server_addrinfo(): called without nat_policy, this should not happen.");
492 }
493 return NULL;
494 }
495
linphone_core_enable_forced_ice_relay(LinphoneCore * lc,bool_t enable)496 void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable) {
497 lc->forced_ice_relay = enable;
498 }
499
linphone_core_enable_short_turn_refresh(LinphoneCore * lc,bool_t enable)500 void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable) {
501 lc->short_turn_refresh = enable;
502 }
503
stun_auth_requested_cb(LinphoneCall * call,const char * realm,const char * nonce,const char ** username,const char ** password,const char ** ha1)504 static void stun_auth_requested_cb(LinphoneCall *call, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) {
505 LinphoneProxyConfig *proxy = NULL;
506 const LinphoneNatPolicy *nat_policy = NULL;
507 const LinphoneAddress *addr = NULL;
508 const LinphoneAuthInfo *auth_info = NULL;
509 LinphoneCore *lc = call->core;
510 const char *user = NULL;
511
512 // Get the username from the nat policy or the proxy config
513 if (call->dest_proxy != NULL) proxy = call->dest_proxy;
514 else proxy = linphone_core_get_default_proxy_config(call->core);
515 if (proxy == NULL) return;
516 nat_policy = linphone_proxy_config_get_nat_policy(proxy);
517 if (nat_policy != NULL) {
518 user = linphone_nat_policy_get_stun_server_username(nat_policy);
519 } else {
520 nat_policy = call->nat_policy;
521 if (nat_policy != NULL) {
522 user = linphone_nat_policy_get_stun_server_username(nat_policy);
523 }
524 }
525 if (user == NULL) {
526 /* If the username has not been found in the nat_policy, take the username from the currently used proxy config. */
527 addr = linphone_proxy_config_get_identity_address(proxy);
528 if (addr == NULL) return;
529 user = linphone_address_get_username(addr);
530 }
531 if (user == NULL) return;
532
533 auth_info = linphone_core_find_auth_info(lc, realm, user, NULL);
534 if (auth_info != NULL) {
535 const char *hash = linphone_auth_info_get_ha1(auth_info);
536 if (hash != NULL) {
537 *ha1 = hash;
538 } else {
539 *password = linphone_auth_info_get_passwd(auth_info);
540 }
541 *username = user;
542 } else {
543 ms_warning("No auth info found for STUN auth request");
544 }
545 }
546
linphone_core_add_local_ice_candidates(LinphoneCall * call,int family,const char * addr,IceCheckList * audio_cl,IceCheckList * video_cl,IceCheckList * text_cl)547 static void linphone_core_add_local_ice_candidates(LinphoneCall *call, int family, const char *addr, IceCheckList *audio_cl, IceCheckList *video_cl, IceCheckList *text_cl) {
548 if ((ice_check_list_state(audio_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_cl) == FALSE)) {
549 ice_add_local_candidate(audio_cl, "host", family, addr, call->media_ports[call->main_audio_stream_index].rtp_port, 1, NULL);
550 ice_add_local_candidate(audio_cl, "host", family, addr, call->media_ports[call->main_audio_stream_index].rtcp_port, 2, NULL);
551 call->audio_stats->ice_state = LinphoneIceStateInProgress;
552 }
553 if (linphone_core_video_enabled(call->core) && (video_cl != NULL)
554 && (ice_check_list_state(video_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(video_cl) == FALSE)) {
555 ice_add_local_candidate(video_cl, "host", family, addr, call->media_ports[call->main_video_stream_index].rtp_port, 1, NULL);
556 ice_add_local_candidate(video_cl, "host", family, addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL);
557 call->video_stats->ice_state = LinphoneIceStateInProgress;
558 }
559 if (call->params->realtimetext_enabled && (text_cl != NULL)
560 && (ice_check_list_state(text_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(text_cl) == FALSE)) {
561 ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL);
562 ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL);
563 call->text_stats->ice_state = LinphoneIceStateInProgress;
564 }
565 }
566
find_nat64_addrinfo(const struct addrinfo * ai)567 static const struct addrinfo * find_nat64_addrinfo(const struct addrinfo *ai) {
568 while (ai != NULL) {
569 if (ai->ai_family == AF_INET6) {
570 struct sockaddr_storage ss;
571 socklen_t sslen = sizeof(ss);
572 bctbx_sockaddr_remove_nat64_mapping(ai->ai_addr, (struct sockaddr *)&ss, &sslen);
573 if (ss.ss_family == AF_INET) break;
574 }
575 ai = ai->ai_next;
576 }
577 return ai;
578 }
579
find_ipv4_addrinfo(const struct addrinfo * ai)580 static const struct addrinfo * find_ipv4_addrinfo(const struct addrinfo *ai) {
581 while (ai != NULL) {
582 if (ai->ai_family == AF_INET) break;
583 ai = ai->ai_next;
584 }
585 return ai;
586 }
587
find_ipv6_addrinfo(const struct addrinfo * ai)588 static const struct addrinfo * find_ipv6_addrinfo(const struct addrinfo *ai) {
589 while (ai != NULL) {
590 if (ai->ai_family == AF_INET6) break;
591 ai = ai->ai_next;
592 }
593 return ai;
594 }
595
596 /**
597 * Choose the preferred IP address to use to contact the STUN server from the list of IP addresses
598 * the DNS resolution returned. If a NAT64 address is present, use it, otherwise if an IPv4 address
599 * is present, use it, otherwise use an IPv6 address if it is present.
600 */
get_preferred_stun_server_addrinfo(const struct addrinfo * ai)601 static const struct addrinfo * get_preferred_stun_server_addrinfo(const struct addrinfo *ai) {
602 const struct addrinfo *preferred_ai = find_nat64_addrinfo(ai);
603 if (!preferred_ai) preferred_ai = find_ipv4_addrinfo(ai);
604 if (!preferred_ai) preferred_ai = find_ipv6_addrinfo(ai);
605 return preferred_ai;
606 }
607
608 /* Return values:
609 * 1 : STUN gathering is started
610 * 0 : no STUN gathering is started, but it's ok to proceed with ICE anyway (with local candidates only or because STUN gathering was already done before)
611 * -1: no gathering started and something went wrong with local candidates. There is no way to start the ICE session.
612 */
linphone_core_gather_ice_candidates(LinphoneCore * lc,LinphoneCall * call)613 int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
614 char local_addr[64];
615 const struct addrinfo *ai = NULL;
616 IceCheckList *audio_cl;
617 IceCheckList *video_cl;
618 IceCheckList *text_cl;
619 LinphoneNatPolicy *nat_policy = call->nat_policy;
620 const char *server = NULL;
621
622 if (nat_policy != NULL) server = linphone_nat_policy_get_stun_server(nat_policy);
623
624 if (call->ice_session == NULL) return -1;
625 audio_cl = ice_session_check_list(call->ice_session, call->main_audio_stream_index);
626 video_cl = ice_session_check_list(call->ice_session, call->main_video_stream_index);
627 text_cl = ice_session_check_list(call->ice_session, call->main_text_stream_index);
628 if ((audio_cl == NULL) && (video_cl == NULL) && (text_cl == NULL)) return -1;
629
630 if ((nat_policy != NULL) && (server != NULL) && (server[0] != '\0')) {
631 ai=linphone_nat_policy_get_stun_server_addrinfo(nat_policy);
632 if (ai==NULL){
633 ms_warning("Fail to resolve STUN server for ICE gathering, continuing without stun.");
634 } else {
635 ai = get_preferred_stun_server_addrinfo(ai);
636 }
637 }else{
638 ms_warning("Ice is used without stun server.");
639 }
640 linphone_core_notify_display_status(lc, _("ICE local candidates gathering in progress..."));
641
642 ice_session_enable_forced_relay(call->ice_session, lc->forced_ice_relay);
643 ice_session_enable_short_turn_refresh(call->ice_session, lc->short_turn_refresh);
644
645 /* Gather local host candidates. */
646 if (call->af == AF_INET6) {
647 if (linphone_core_get_local_ip_for(AF_INET6, NULL, local_addr) < 0) {
648 ms_error("Fail to get local IPv6");
649 return -1;
650 } else {
651 linphone_core_add_local_ice_candidates(call, AF_INET6, local_addr, audio_cl, video_cl, text_cl);
652 }
653 }
654 if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
655 if (call->af != AF_INET6) {
656 ms_error("Fail to get local IPv4");
657 return -1;
658 }
659 } else {
660 linphone_core_add_local_ice_candidates(call, AF_INET, local_addr, audio_cl, video_cl, text_cl);
661 }
662 if ((ai != NULL) && (nat_policy != NULL)
663 && (linphone_nat_policy_stun_enabled(nat_policy) || linphone_nat_policy_turn_enabled(nat_policy))) {
664 bool_t gathering_in_progress;
665 ms_message("ICE: gathering candidate from [%s] using %s", server, linphone_nat_policy_turn_enabled(nat_policy) ? "TURN" : "STUN");
666 /* Gather local srflx candidates. */
667 ice_session_enable_turn(call->ice_session, linphone_nat_policy_turn_enabled(nat_policy));
668 ice_session_set_stun_auth_requested_cb(call->ice_session, (MSStunAuthRequestedCb)stun_auth_requested_cb, call);
669 gathering_in_progress = ice_session_gather_candidates(call->ice_session, ai->ai_addr, (socklen_t)ai->ai_addrlen);
670 return (gathering_in_progress == FALSE) ? 0 : 1;
671 } else {
672 ms_message("ICE: bypass candidates gathering");
673 ice_session_compute_candidates_foundations(call->ice_session);
674 ice_session_eliminate_redundant_candidates(call->ice_session);
675 ice_session_choose_default_candidates(call->ice_session);
676 }
677 return 0;
678 }
679
linphone_ice_state_to_string(LinphoneIceState state)680 const char *linphone_ice_state_to_string(LinphoneIceState state){
681 switch(state){
682 case LinphoneIceStateFailed:
683 return "IceStateFailed";
684 case LinphoneIceStateHostConnection:
685 return "IceStateHostConnection";
686 case LinphoneIceStateInProgress:
687 return "IceStateInProgress";
688 case LinphoneIceStateNotActivated:
689 return "IceStateNotActivated";
690 case LinphoneIceStateReflexiveConnection:
691 return "IceStateReflexiveConnection";
692 case LinphoneIceStateRelayConnection:
693 return "IceStateRelayConnection";
694 }
695 return "invalid";
696 }
697
linphone_call_update_ice_state_in_call_stats(LinphoneCall * call)698 void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) {
699 IceCheckList *audio_check_list;
700 IceCheckList *video_check_list;
701 IceCheckList *text_check_list;
702 IceSessionState session_state;
703
704 if (call->ice_session == NULL) return;
705 audio_check_list = ice_session_check_list(call->ice_session, call->main_audio_stream_index);
706 video_check_list = ice_session_check_list(call->ice_session, call->main_video_stream_index);
707 text_check_list = ice_session_check_list(call->ice_session, call->main_text_stream_index);
708 if ((audio_check_list == NULL) && (video_check_list == NULL) && (text_check_list == NULL)) return;
709
710 session_state = ice_session_state(call->ice_session);
711 if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) {
712 if (call->params->has_audio && (audio_check_list != NULL)) {
713 if (ice_check_list_state(audio_check_list) == ICL_Completed) {
714 switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) {
715 case ICT_HostCandidate:
716 call->audio_stats->ice_state = LinphoneIceStateHostConnection;
717 break;
718 case ICT_ServerReflexiveCandidate:
719 case ICT_PeerReflexiveCandidate:
720 call->audio_stats->ice_state = LinphoneIceStateReflexiveConnection;
721 break;
722 case ICT_RelayedCandidate:
723 call->audio_stats->ice_state = LinphoneIceStateRelayConnection;
724 break;
725 case ICT_CandidateInvalid:
726 case ICT_CandidateTypeMax:
727 /*shall not happen*/
728 break;
729 }
730 } else {
731 call->audio_stats->ice_state = LinphoneIceStateFailed;
732 }
733 }else call->audio_stats->ice_state = LinphoneIceStateNotActivated;
734
735 if (call->params->has_video && (video_check_list != NULL)) {
736 if (ice_check_list_state(video_check_list) == ICL_Completed) {
737 switch (ice_check_list_selected_valid_candidate_type(video_check_list)) {
738 case ICT_HostCandidate:
739 call->video_stats->ice_state = LinphoneIceStateHostConnection;
740 break;
741 case ICT_ServerReflexiveCandidate:
742 case ICT_PeerReflexiveCandidate:
743 call->video_stats->ice_state = LinphoneIceStateReflexiveConnection;
744 break;
745 case ICT_RelayedCandidate:
746 call->video_stats->ice_state = LinphoneIceStateRelayConnection;
747 break;
748 case ICT_CandidateInvalid:
749 case ICT_CandidateTypeMax:
750 /*shall not happen*/
751 break;
752 }
753 } else {
754 call->video_stats->ice_state = LinphoneIceStateFailed;
755 }
756 }else call->video_stats->ice_state = LinphoneIceStateNotActivated;
757
758 if (call->params->realtimetext_enabled && (text_check_list != NULL)) {
759 if (ice_check_list_state(text_check_list) == ICL_Completed) {
760 switch (ice_check_list_selected_valid_candidate_type(text_check_list)) {
761 case ICT_HostCandidate:
762 call->text_stats->ice_state = LinphoneIceStateHostConnection;
763 break;
764 case ICT_ServerReflexiveCandidate:
765 case ICT_PeerReflexiveCandidate:
766 call->text_stats->ice_state = LinphoneIceStateReflexiveConnection;
767 break;
768 case ICT_RelayedCandidate:
769 call->text_stats->ice_state = LinphoneIceStateRelayConnection;
770 break;
771 case ICT_CandidateInvalid:
772 case ICT_CandidateTypeMax:
773 /*shall not happen*/
774 break;
775 }
776 } else {
777 call->text_stats->ice_state = LinphoneIceStateFailed;
778 }
779 }else call->text_stats->ice_state = LinphoneIceStateNotActivated;
780 } else if (session_state == IS_Running) {
781 call->audio_stats->ice_state = LinphoneIceStateInProgress;
782 if (call->params->has_video && (video_check_list != NULL)) {
783 call->video_stats->ice_state = LinphoneIceStateInProgress;
784 }
785 if (call->params->realtimetext_enabled && (text_check_list != NULL)) {
786 call->text_stats->ice_state = LinphoneIceStateInProgress;
787 }
788 } else {
789 call->audio_stats->ice_state = LinphoneIceStateFailed;
790 if (call->params->has_video && (video_check_list != NULL)) {
791 call->video_stats->ice_state = LinphoneIceStateFailed;
792 }
793 if (call->params->realtimetext_enabled && (text_check_list != NULL)) {
794 call->text_stats->ice_state = LinphoneIceStateFailed;
795 }
796 }
797 ms_message("Call [%p] New ICE state: audio: [%s] video: [%s] text: [%s]", call,
798 linphone_ice_state_to_string(call->audio_stats->ice_state), linphone_ice_state_to_string(call->video_stats->ice_state), linphone_ice_state_to_string(call->text_stats->ice_state));
799 }
800
linphone_call_stop_ice_for_inactive_streams(LinphoneCall * call,SalMediaDescription * desc)801 void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDescription *desc) {
802 int i;
803 IceSession *session = call->ice_session;
804
805 if (session == NULL) return;
806 if (ice_session_state(session) == IS_Completed) return;
807
808 for (i = 0; i < desc->nb_streams; i++) {
809 IceCheckList *cl = ice_session_check_list(session, i);
810 if (!sal_stream_description_active(&desc->streams[i]) && cl) {
811 ice_session_remove_check_list(session, cl);
812 clear_ice_check_list(call, cl);
813 }
814 }
815
816 linphone_call_update_ice_state_in_call_stats(call);
817 }
818
_update_local_media_description_from_ice(SalMediaDescription * desc,IceSession * session,bool_t use_nortpproxy)819 void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy) {
820 IceCandidate *rtp_candidate = NULL;
821 IceCandidate *rtcp_candidate = NULL;
822 IceSessionState session_state = ice_session_state(session);
823 int nb_candidates;
824 int i;
825 int j;
826 bool_t result = FALSE;
827
828 if (session_state == IS_Completed) {
829 IceCheckList *first_cl = NULL;
830 for (i = 0; i < desc->nb_streams; i++) {
831 IceCheckList *cl = ice_session_check_list(session, i);
832 if (cl != NULL) {
833 first_cl = cl;
834 break;
835 }
836 }
837 if (first_cl != NULL) {
838 result = ice_check_list_selected_valid_local_candidate(first_cl, &rtp_candidate, NULL);
839 }
840 if (result == TRUE) {
841 strncpy(desc->addr, rtp_candidate->taddr.ip, sizeof(desc->addr));
842 } else {
843 ms_warning("If ICE has completed successfully, rtp_candidate should be set!");
844 }
845 }
846
847 strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
848 strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
849 for (i = 0; i < desc->nb_streams; i++) {
850 SalStreamDescription *stream = &desc->streams[i];
851 IceCheckList *cl = ice_session_check_list(session, i);
852 nb_candidates = 0;
853 rtp_candidate = rtcp_candidate = NULL;
854 if (!sal_stream_description_active(stream) || (cl == NULL)) continue;
855 if (ice_check_list_state(cl) == ICL_Completed) {
856 if (use_nortpproxy) stream->set_nortpproxy = TRUE;
857 result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_candidate, &rtcp_candidate);
858 } else {
859 stream->set_nortpproxy = FALSE;
860 result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_candidate, &rtcp_candidate);
861 }
862 if (result == TRUE) {
863 strncpy(stream->rtp_addr, rtp_candidate->taddr.ip, sizeof(stream->rtp_addr));
864 strncpy(stream->rtcp_addr, rtcp_candidate->taddr.ip, sizeof(stream->rtcp_addr));
865 stream->rtp_port = rtp_candidate->taddr.port;
866 stream->rtcp_port = rtcp_candidate->taddr.port;
867 } else {
868 memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr));
869 memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr));
870 }
871 if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd)))
872 strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd));
873 else
874 memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
875 if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag)))
876 strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag));
877 else
878 memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
879 stream->ice_mismatch = ice_check_list_is_mismatch(cl);
880 if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) {
881 memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates));
882 for (j = 0; j < MIN((int)bctbx_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) {
883 SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates];
884 IceCandidate *ice_candidate = bctbx_list_nth_data(cl->local_candidates, j);
885 const char *default_addr = NULL;
886 int default_port = 0;
887 if (ice_candidate->componentID == 1) {
888 default_addr = stream->rtp_addr;
889 default_port = stream->rtp_port;
890 } else if (ice_candidate->componentID == 2) {
891 default_addr = stream->rtcp_addr;
892 default_port = stream->rtcp_port;
893 } else continue;
894 if (default_addr[0] == '\0') default_addr = desc->addr;
895 /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */
896 if ((ice_check_list_state(cl) == ICL_Completed)
897 && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0)))
898 continue;
899 strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation));
900 sal_candidate->componentID = ice_candidate->componentID;
901 sal_candidate->priority = ice_candidate->priority;
902 strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type));
903 strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr));
904 sal_candidate->port = ice_candidate->taddr.port;
905 if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) {
906 strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr));
907 sal_candidate->rport = ice_candidate->base->taddr.port;
908 }
909 nb_candidates++;
910 }
911 }
912 if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
913 memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
914 if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_candidate, &rtcp_candidate) == TRUE) {
915 strncpy(stream->ice_remote_candidates[0].addr, rtp_candidate->taddr.ip, sizeof(stream->ice_remote_candidates[0].addr));
916 stream->ice_remote_candidates[0].port = rtp_candidate->taddr.port;
917 strncpy(stream->ice_remote_candidates[1].addr, rtcp_candidate->taddr.ip, sizeof(stream->ice_remote_candidates[1].addr));
918 stream->ice_remote_candidates[1].port = rtcp_candidate->taddr.port;
919 } else {
920 ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state");
921 }
922 } else {
923 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
924 stream->ice_remote_candidates[j].addr[0] = '\0';
925 stream->ice_remote_candidates[j].port = 0;
926 }
927 }
928 }
929 }
930
get_default_addr_and_port(uint16_t componentID,const SalMediaDescription * md,const SalStreamDescription * stream,const char ** addr,int * port)931 static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port)
932 {
933 if (componentID == 1) {
934 *addr = stream->rtp_addr;
935 *port = stream->rtp_port;
936 } else if (componentID == 2) {
937 *addr = stream->rtcp_addr;
938 *port = stream->rtcp_port;
939 } else return;
940 if ((*addr)[0] == '\0') *addr = md->addr;
941 }
942
clear_ice_check_list(LinphoneCall * call,IceCheckList * removed)943 static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed){
944 if (call->audiostream && call->audiostream->ms.ice_check_list==removed)
945 call->audiostream->ms.ice_check_list=NULL;
946 if (call->videostream && call->videostream->ms.ice_check_list==removed)
947 call->videostream->ms.ice_check_list=NULL;
948 if (call->textstream && call->textstream->ms.ice_check_list==removed)
949 call->textstream->ms.ice_check_list=NULL;
950 }
951
linphone_call_clear_unused_ice_candidates(LinphoneCall * call,const SalMediaDescription * md)952 void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md){
953 int i;
954
955 if (!call->localdesc) return;
956 for (i = 0; i < md->nb_streams; i++) {
957 const SalStreamDescription *local_stream = &call->localdesc->streams[i];
958 const SalStreamDescription *stream = &md->streams[i];
959 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
960 if (!cl || !local_stream) continue;
961
962 if (stream->rtcp_mux && local_stream->rtcp_mux){
963 ice_check_list_remove_rtcp_candidates(cl);
964 }
965 }
966 }
967
linphone_core_media_description_contains_video_stream(const SalMediaDescription * md)968 bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){
969 int i;
970
971 for (i = 0; md && i < md->nb_streams; i++) {
972 if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0)
973 return TRUE;
974 }
975 return FALSE;
976 }
977
linphone_core_get_audio_features(LinphoneCore * lc)978 unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
979 unsigned int ret=0;
980 const char *features=lp_config_get_string(lc->config,"sound","features",NULL);
981 if (features){
982 char tmp[256]={0};
983 char name[256];
984 char *p,*n;
985 strncpy(tmp,features,sizeof(tmp)-1);
986 for(p=tmp;*p!='\0';p++){
987 if (*p==' ') continue;
988 n=strchr(p,'|');
989 if (n) *n='\0';
990 sscanf(p,"%s",name);
991 ms_message("Found audio feature %s",name);
992 if (strcasecmp(name,"PLC")==0) ret|=AUDIO_STREAM_FEATURE_PLC;
993 else if (strcasecmp(name,"EC")==0) ret|=AUDIO_STREAM_FEATURE_EC;
994 else if (strcasecmp(name,"EQUALIZER")==0) ret|=AUDIO_STREAM_FEATURE_EQUALIZER;
995 else if (strcasecmp(name,"VOL_SND")==0) ret|=AUDIO_STREAM_FEATURE_VOL_SND;
996 else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV;
997 else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF;
998 else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO;
999 else if (strcasecmp(name,"MIXED_RECORDING")==0) ret|=AUDIO_STREAM_FEATURE_MIXED_RECORDING;
1000 else if (strcasecmp(name,"LOCAL_PLAYING")==0) ret|=AUDIO_STREAM_FEATURE_LOCAL_PLAYING;
1001 else if (strcasecmp(name,"REMOTE_PLAYING")==0) ret|=AUDIO_STREAM_FEATURE_REMOTE_PLAYING;
1002 else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL;
1003 else if (strcasecmp(name,"NONE")==0) ret=0;
1004 else ms_error("Unsupported audio feature %s requested in config file.",name);
1005 if (!n) break;
1006 p=n;
1007 }
1008 }else ret=AUDIO_STREAM_FEATURE_ALL;
1009
1010 if (ret==AUDIO_STREAM_FEATURE_ALL){
1011 /*since call recording is specified before creation of the stream in linphonecore,
1012 * it will be requested on demand. It is not necessary to include it all the time*/
1013 ret&=~AUDIO_STREAM_FEATURE_MIXED_RECORDING;
1014 }
1015 return ret;
1016 }
1017
linphone_core_tone_indications_enabled(LinphoneCore * lc)1018 bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc){
1019 return lp_config_get_int(lc->config,"sound","tone_indications",1);
1020 }
1021
linphone_core_get_local_ip_for(int type,const char * dest,char * result)1022 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
1023 return bctbx_get_local_ip_for(type, dest, 5060, result, LINPHONE_IPADDR_SIZE);
1024 }
1025
linphone_core_get_local_ip(LinphoneCore * lc,int af,const char * dest,char * result)1026 void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result) {
1027 if (af == AF_UNSPEC) {
1028 if (linphone_core_ipv6_enabled(lc)) {
1029 bool_t has_ipv6 = linphone_core_get_local_ip_for(AF_INET6, dest, result) == 0;
1030 if (strcmp(result, "::1") != 0)
1031 return; /*this machine has real ipv6 connectivity*/
1032 if ((linphone_core_get_local_ip_for(AF_INET, dest, result) == 0) && (strcmp(result, "127.0.0.1") != 0))
1033 return; /*this machine has only ipv4 connectivity*/
1034 if (has_ipv6) {
1035 /*this machine has only local loopback for both ipv4 and ipv6, so prefer ipv6*/
1036 strncpy(result, "::1", LINPHONE_IPADDR_SIZE);
1037 return;
1038 }
1039 }
1040 /*in all other cases use IPv4*/
1041 af = AF_INET;
1042 }
1043 linphone_core_get_local_ip_for(af, dest, result);
1044 }
1045
linphone_reason_to_sal(LinphoneReason reason)1046 SalReason linphone_reason_to_sal(LinphoneReason reason){
1047 switch(reason){
1048 case LinphoneReasonNone:
1049 return SalReasonNone;
1050 case LinphoneReasonNoResponse:
1051 return SalReasonRequestTimeout;
1052 case LinphoneReasonForbidden:
1053 return SalReasonForbidden;
1054 case LinphoneReasonDeclined:
1055 return SalReasonDeclined;
1056 case LinphoneReasonNotFound:
1057 return SalReasonNotFound;
1058 case LinphoneReasonTemporarilyUnavailable:
1059 return SalReasonTemporarilyUnavailable;
1060 case LinphoneReasonBusy:
1061 return SalReasonBusy;
1062 case LinphoneReasonNotAcceptable:
1063 return SalReasonNotAcceptable;
1064 case LinphoneReasonIOError:
1065 return SalReasonServiceUnavailable;
1066 case LinphoneReasonDoNotDisturb:
1067 return SalReasonDoNotDisturb;
1068 case LinphoneReasonUnauthorized:
1069 return SalReasonUnauthorized;
1070 case LinphoneReasonUnsupportedContent:
1071 return SalReasonUnsupportedContent;
1072 case LinphoneReasonNoMatch:
1073 return SalReasonNoMatch;
1074 case LinphoneReasonMovedPermanently:
1075 return SalReasonMovedPermanently;
1076 case LinphoneReasonGone:
1077 return SalReasonGone;
1078 case LinphoneReasonAddressIncomplete:
1079 return SalReasonAddressIncomplete;
1080 case LinphoneReasonNotImplemented:
1081 return SalReasonNotImplemented;
1082 case LinphoneReasonBadGateway:
1083 return SalReasonBadGateway;
1084 case LinphoneReasonServerTimeout:
1085 return SalReasonServerTimeout;
1086 case LinphoneReasonNotAnswered:
1087 return SalReasonRequestTimeout;
1088 case LinphoneReasonUnknown:
1089 return SalReasonUnknown;
1090 }
1091 return SalReasonUnknown;
1092 }
1093
linphone_reason_from_sal(SalReason r)1094 LinphoneReason linphone_reason_from_sal(SalReason r){
1095 LinphoneReason ret=LinphoneReasonNone;
1096 switch(r){
1097 case SalReasonNone:
1098 ret=LinphoneReasonNone;
1099 break;
1100 case SalReasonIOError:
1101 ret=LinphoneReasonIOError;
1102 break;
1103 case SalReasonUnknown:
1104 case SalReasonInternalError:
1105 ret=LinphoneReasonUnknown;
1106 break;
1107 case SalReasonBusy:
1108 ret=LinphoneReasonBusy;
1109 break;
1110 case SalReasonDeclined:
1111 ret=LinphoneReasonDeclined;
1112 break;
1113 case SalReasonDoNotDisturb:
1114 ret=LinphoneReasonDoNotDisturb;
1115 break;
1116 case SalReasonForbidden:
1117 ret=LinphoneReasonBadCredentials;
1118 break;
1119 case SalReasonNotAcceptable:
1120 ret=LinphoneReasonNotAcceptable;
1121 break;
1122 case SalReasonNotFound:
1123 ret=LinphoneReasonNotFound;
1124 break;
1125 case SalReasonRedirect:
1126 ret=LinphoneReasonNone;
1127 break;
1128 case SalReasonTemporarilyUnavailable:
1129 ret=LinphoneReasonTemporarilyUnavailable;
1130 break;
1131 case SalReasonServiceUnavailable:
1132 ret=LinphoneReasonIOError;
1133 break;
1134 case SalReasonRequestPending:
1135 ret=LinphoneReasonTemporarilyUnavailable; /*might not be exactly the perfect matching, but better than LinphoneReasonNone*/
1136 break;
1137 case SalReasonUnauthorized:
1138 ret=LinphoneReasonUnauthorized;
1139 break;
1140 case SalReasonUnsupportedContent:
1141 ret=LinphoneReasonUnsupportedContent;
1142 break;
1143 case SalReasonNoMatch:
1144 ret=LinphoneReasonNoMatch;
1145 break;
1146 case SalReasonRequestTimeout:
1147 ret=LinphoneReasonNotAnswered;
1148 break;
1149 case SalReasonMovedPermanently:
1150 ret=LinphoneReasonMovedPermanently;
1151 break;
1152 case SalReasonGone:
1153 ret=LinphoneReasonGone;
1154 break;
1155 case SalReasonAddressIncomplete:
1156 ret=LinphoneReasonAddressIncomplete;
1157 break;
1158 case SalReasonNotImplemented:
1159 ret=LinphoneReasonNotImplemented;
1160 break;
1161 case SalReasonBadGateway:
1162 ret=LinphoneReasonBadGateway;
1163 break;
1164 case SalReasonServerTimeout:
1165 ret=LinphoneReasonServerTimeout;
1166 break;
1167 }
1168 return ret;
1169 }
1170
1171 /**
1172 * Set the name of the mediastreamer2 filter to be used for rendering video.
1173 * This is for advanced users of the library, mainly to workaround hardware/driver bugs.
1174 * @ingroup media_parameters
1175 **/
linphone_core_set_video_display_filter(LinphoneCore * lc,const char * filter_name)1176 void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filter_name){
1177 lp_config_set_string(lc->config,"video","displaytype",filter_name);
1178 }
1179
linphone_core_get_video_display_filter(LinphoneCore * lc)1180 const char *linphone_core_get_video_display_filter(LinphoneCore *lc){
1181 return lp_config_get_string(lc->config,"video","displaytype",NULL);
1182 }
1183
linphone_core_set_echo_canceller_filter_name(LinphoneCore * lc,const char * filtername)1184 void linphone_core_set_echo_canceller_filter_name(LinphoneCore *lc, const char *filtername) {
1185 lp_config_set_string(lc->config, "sound", "ec_filter", filtername);
1186 if (filtername != NULL) {
1187 ms_factory_set_echo_canceller_filter_name(lc->factory, filtername);
1188 }
1189 }
1190
linphone_core_get_echo_canceller_filter_name(const LinphoneCore * lc)1191 const char * linphone_core_get_echo_canceller_filter_name(const LinphoneCore *lc) {
1192 return lp_config_get_string(lc->config, "sound", "ec_filter", NULL);
1193 }
1194
1195 /**
1196 * Queue a task into the main loop. The data pointer must remain valid until the task is completed.
1197 * task_fun must return BELLE_SIP_STOP when job is finished.
1198 **/
linphone_core_queue_task(LinphoneCore * lc,belle_sip_source_func_t task_fun,void * data,const char * task_description)1199 void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description){
1200 belle_sip_source_t *s=sal_create_timer(lc->sal,task_fun,data, 20, task_description);
1201 belle_sip_object_unref(s);
1202 }
1203
get_unique_transport(LinphoneCore * lc,LinphoneTransportType * type,int * port)1204 static int get_unique_transport(LinphoneCore *lc, LinphoneTransportType *type, int *port){
1205 LinphoneSipTransports tp;
1206 linphone_core_get_sip_transports(lc,&tp);
1207 if (tp.tcp_port==0 && tp.tls_port==0 && tp.udp_port!=0){
1208 *type=LinphoneTransportUdp;
1209 *port=tp.udp_port;
1210 return 0;
1211 }else if (tp.tcp_port==0 && tp.udp_port==0 && tp.tls_port!=0){
1212 *type=LinphoneTransportTls;
1213 *port=tp.tls_port;
1214 return 0;
1215 }else if (tp.tcp_port!=0 && tp.udp_port==0 && tp.tls_port==0){
1216 *type=LinphoneTransportTcp;
1217 *port=tp.tcp_port;
1218 return 0;
1219 }
1220 return -1;
1221 }
1222
linphone_core_migrate_proxy_config(LinphoneCore * lc,LinphoneTransportType type)1223 static void linphone_core_migrate_proxy_config(LinphoneCore *lc, LinphoneTransportType type){
1224 const bctbx_list_t *elem;
1225 for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
1226 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1227 const char *proxy=linphone_proxy_config_get_addr(cfg);
1228 const char *route=linphone_proxy_config_get_route(cfg);
1229 LinphoneAddress *proxy_addr=linphone_address_new(proxy);
1230 LinphoneAddress *route_addr=NULL;
1231 char *tmp;
1232 if (route) route_addr=linphone_address_new(route);
1233 if (proxy_addr){
1234 linphone_address_set_transport(proxy_addr,type);
1235 tmp=linphone_address_as_string(proxy_addr);
1236 linphone_proxy_config_set_server_addr(cfg,tmp);
1237 ms_free(tmp);
1238 linphone_address_unref(proxy_addr);
1239 }
1240 if (route_addr){
1241 linphone_address_set_transport(route_addr,type);
1242 tmp=linphone_address_as_string(route_addr);
1243 linphone_proxy_config_set_route(cfg,tmp);
1244 ms_free(tmp);
1245 linphone_address_unref(route_addr);
1246 }
1247 }
1248 }
1249
linphone_core_migrate_to_multi_transport(LinphoneCore * lc)1250 LinphoneStatus linphone_core_migrate_to_multi_transport(LinphoneCore *lc){
1251 if (!lp_config_get_int(lc->config,"sip","multi_transport_migration_done",0)){
1252 LinphoneTransportType tpt;
1253 int port;
1254 if (get_unique_transport(lc,&tpt,&port)==0){
1255 LinphoneSipTransports newtp={0};
1256 if (lp_config_get_int(lc->config,"sip","sip_random_port",0))
1257 port=-1;
1258 ms_message("Core is using a single SIP transport, migrating proxy config and enabling multi-transport.");
1259 linphone_core_migrate_proxy_config(lc,tpt);
1260 newtp.udp_port=port;
1261 newtp.tcp_port=port;
1262 newtp.tls_port=LC_SIP_TRANSPORT_RANDOM;
1263 lp_config_set_string(lc->config, "sip","sip_random_port",NULL); /*remove*/
1264 linphone_core_set_sip_transports(lc,&newtp);
1265 }
1266 lp_config_set_int(lc->config,"sip","multi_transport_migration_done",1);
1267 return 1;
1268 }
1269 return 0;
1270 }
1271
linphone_tone_description_new(LinphoneReason reason,LinphoneToneID id,const char * audiofile)1272 LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile){
1273 LinphoneToneDescription *obj=ms_new0(LinphoneToneDescription,1);
1274 obj->reason=reason;
1275 obj->toneid=id;
1276 obj->audiofile=audiofile ? ms_strdup(audiofile) : NULL;
1277 return obj;
1278 }
1279
linphone_tone_description_destroy(LinphoneToneDescription * obj)1280 void linphone_tone_description_destroy(LinphoneToneDescription *obj){
1281 if (obj->audiofile) ms_free(obj->audiofile);
1282 ms_free(obj);
1283 }
1284
linphone_core_lookup_tone(const LinphoneCore * lc,LinphoneReason reason,LinphoneToneID id)1285 static LinphoneToneDescription *linphone_core_lookup_tone(const LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id){
1286 const bctbx_list_t *elem;
1287 for (elem=lc->tones;elem!=NULL;elem=elem->next){
1288 LinphoneToneDescription *tone=(LinphoneToneDescription*)elem->data;
1289 if (reason == LinphoneReasonNone){
1290 if (tone->toneid == id && tone->reason == LinphoneReasonNone) return tone;
1291 }else{
1292 if (tone->reason==reason) return tone;
1293 }
1294 }
1295 return NULL;
1296 }
1297
linphone_core_get_call_error_tone(const LinphoneCore * lc,LinphoneReason reason)1298 LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason){
1299 return linphone_core_lookup_tone(lc, reason, LinphoneToneUndefined);
1300 }
1301
linphone_core_get_tone_file(const LinphoneCore * lc,LinphoneToneID id)1302 const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id){
1303 LinphoneToneDescription *tone = linphone_core_lookup_tone(lc, LinphoneReasonNone, id);
1304 return tone ? tone->audiofile : NULL;
1305 }
1306
_linphone_core_set_tone(LinphoneCore * lc,LinphoneReason reason,LinphoneToneID id,const char * audiofile)1307 void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile){
1308 LinphoneToneDescription *tone = linphone_core_lookup_tone(lc,reason, id);
1309 if (tone){
1310 lc->tones=bctbx_list_remove(lc->tones,tone);
1311 linphone_tone_description_destroy(tone);
1312 }
1313 tone=linphone_tone_description_new(reason,id,audiofile);
1314 lc->tones=bctbx_list_append(lc->tones,tone);
1315 }
1316
linphone_core_set_call_error_tone(LinphoneCore * lc,LinphoneReason reason,const char * audiofile)1317 void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile){
1318 _linphone_core_set_tone(lc,reason,LinphoneToneUndefined, audiofile);
1319 }
1320
linphone_core_set_tone(LinphoneCore * lc,LinphoneToneID id,const char * audiofile)1321 void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *audiofile){
1322 _linphone_core_set_tone(lc, LinphoneReasonNone, id, audiofile);
1323 }
1324
linphone_core_get_srtp_crypto_suites(LinphoneCore * lc)1325 const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){
1326 const char *config= lp_config_get_string(lc->config, "sip", "srtp_crypto_suites", "AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32, AES_256_CM_HMAC_SHA1_80, AES_256_CM_HMAC_SHA1_32");
1327 char *tmp=ms_strdup(config);
1328
1329 char *sep;
1330 char *pos;
1331 char *nextpos;
1332 char *params;
1333 int found=0;
1334 MSCryptoSuite *result=NULL;
1335 pos=tmp;
1336 do{
1337 sep=strchr(pos,',');
1338 if (!sep) {
1339 sep=pos+strlen(pos);
1340 nextpos=NULL;
1341 }else {
1342 *sep='\0';
1343 nextpos=sep+1;
1344 }
1345 while(*pos==' ') ++pos; /*strip leading spaces*/
1346 params=strchr(pos,' '); /*look for params that arrive after crypto suite name*/
1347 if (params){
1348 while(*params==' ') ++params; /*strip parameters leading space*/
1349 }
1350 if (sep-pos>0){
1351 MSCryptoSuiteNameParams np;
1352 MSCryptoSuite suite;
1353 np.name=pos;
1354 np.params=params;
1355 suite=ms_crypto_suite_build_from_name_params(&np);
1356 if (suite!=MS_CRYPTO_SUITE_INVALID){
1357 result=ms_realloc(result,(found+2)*sizeof(MSCryptoSuite));
1358 result[found]=suite;
1359 result[found+1]=MS_CRYPTO_SUITE_INVALID;
1360 found++;
1361 ms_message("Configured srtp crypto suite: %s %s",np.name,np.params ? np.params : "");
1362 }
1363 }
1364 pos=nextpos;
1365 }while(pos);
1366 ms_free(tmp);
1367 if (lc->rtp_conf.srtp_suites){
1368 ms_free(lc->rtp_conf.srtp_suites);
1369 lc->rtp_conf.srtp_suites=NULL;
1370 }
1371 lc->rtp_conf.srtp_suites=result;
1372 return result;
1373 }
1374
seperate_string_list(char ** str)1375 static char * seperate_string_list(char **str) {
1376 char *ret;
1377
1378 if (str == NULL) return NULL;
1379 if (*str == NULL) return NULL;
1380 if (**str == '\0') return NULL;
1381
1382 ret = *str;
1383 for ( ; **str!='\0' && **str!=' ' && **str!=','; (*str)++);
1384 if (**str == '\0') {
1385 return ret;
1386 } else {
1387 **str = '\0';
1388 do { (*str)++; } while (**str!='\0' && (**str==' ' || **str==','));
1389 return ret;
1390 }
1391 }
1392
linphone_core_get_zrtp_key_agreement_suites(LinphoneCore * lc,MSZrtpKeyAgreement keyAgreements[MS_MAX_ZRTP_CRYPTO_TYPES])1393 MsZrtpCryptoTypesCount linphone_core_get_zrtp_key_agreement_suites(LinphoneCore *lc, MSZrtpKeyAgreement keyAgreements[MS_MAX_ZRTP_CRYPTO_TYPES]){
1394 char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_key_agreements_suites", NULL);
1395 MsZrtpCryptoTypesCount key_agreements_count = 0;
1396 char * entry, * origPtr;
1397 if (zrtpConfig == NULL) {
1398 return 0;
1399 }
1400
1401 origPtr = ms_strdup(zrtpConfig);
1402 zrtpConfig = origPtr;
1403 while ((entry = seperate_string_list(&zrtpConfig))) {
1404 const MSZrtpKeyAgreement agreement = ms_zrtp_key_agreement_from_string(entry);
1405 if (agreement != MS_ZRTP_KEY_AGREEMENT_INVALID) {
1406 ms_message("Configured zrtp key agreement: '%s'", ms_zrtp_key_agreement_to_string(agreement));
1407 keyAgreements[key_agreements_count++] = agreement;
1408 }
1409 }
1410
1411 ms_free(origPtr);
1412 return key_agreements_count;
1413 }
1414
linphone_core_get_zrtp_cipher_suites(LinphoneCore * lc,MSZrtpCipher ciphers[MS_MAX_ZRTP_CRYPTO_TYPES])1415 MsZrtpCryptoTypesCount linphone_core_get_zrtp_cipher_suites(LinphoneCore *lc, MSZrtpCipher ciphers[MS_MAX_ZRTP_CRYPTO_TYPES]){
1416 char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_cipher_suites", NULL);
1417 MsZrtpCryptoTypesCount cipher_count = 0;
1418 char * entry, * origPtr;
1419 if (zrtpConfig == NULL) {
1420 return 0;
1421 }
1422
1423 origPtr = ms_strdup(zrtpConfig);
1424 zrtpConfig = origPtr;
1425 while ((entry = seperate_string_list(&zrtpConfig))) {
1426 const MSZrtpCipher cipher = ms_zrtp_cipher_from_string(entry);
1427 if (cipher != MS_ZRTP_CIPHER_INVALID) {
1428 ms_message("Configured zrtp cipher: '%s'", ms_zrtp_cipher_to_string(cipher));
1429 ciphers[cipher_count++] = cipher;
1430 }
1431 }
1432
1433 ms_free(origPtr);
1434 return cipher_count;
1435 }
1436
linphone_core_get_zrtp_hash_suites(LinphoneCore * lc,MSZrtpHash hashes[MS_MAX_ZRTP_CRYPTO_TYPES])1437 MsZrtpCryptoTypesCount linphone_core_get_zrtp_hash_suites(LinphoneCore *lc, MSZrtpHash hashes[MS_MAX_ZRTP_CRYPTO_TYPES]){
1438 char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_hash_suites", NULL);
1439 MsZrtpCryptoTypesCount hash_count = 0;
1440 char * entry, * origPtr;
1441 if (zrtpConfig == NULL) {
1442 return 0;
1443 }
1444
1445 origPtr = ms_strdup(zrtpConfig);
1446 zrtpConfig = origPtr;
1447 while ((entry = seperate_string_list(&zrtpConfig))) {
1448 const MSZrtpHash hash = ms_zrtp_hash_from_string(entry);
1449 if (hash != MS_ZRTP_HASH_INVALID) {
1450 ms_message("Configured zrtp hash: '%s'", ms_zrtp_hash_to_string(hash));
1451 hashes[hash_count++] = hash;
1452 }
1453 }
1454
1455 ms_free(origPtr);
1456 return hash_count;
1457 }
1458
linphone_core_get_zrtp_auth_suites(LinphoneCore * lc,MSZrtpAuthTag authTags[MS_MAX_ZRTP_CRYPTO_TYPES])1459 MsZrtpCryptoTypesCount linphone_core_get_zrtp_auth_suites(LinphoneCore *lc, MSZrtpAuthTag authTags[MS_MAX_ZRTP_CRYPTO_TYPES]){
1460 char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_auth_suites", NULL);
1461 MsZrtpCryptoTypesCount auth_tag_count = 0;
1462 char * entry, * origPtr;
1463 if (zrtpConfig == NULL) {
1464 return 0;
1465 }
1466
1467 origPtr = ms_strdup(zrtpConfig);
1468 zrtpConfig = origPtr;
1469 while ((entry = seperate_string_list(&zrtpConfig))) {
1470 const MSZrtpAuthTag authTag = ms_zrtp_auth_tag_from_string(entry);
1471 if (authTag != MS_ZRTP_AUTHTAG_INVALID) {
1472 ms_message("Configured zrtp auth tag: '%s'", ms_zrtp_auth_tag_to_string(authTag));
1473 authTags[auth_tag_count++] = authTag;
1474 }
1475 }
1476
1477 ms_free(origPtr);
1478 return auth_tag_count;
1479 }
1480
linphone_core_get_zrtp_sas_suites(LinphoneCore * lc,MSZrtpSasType sasTypes[MS_MAX_ZRTP_CRYPTO_TYPES])1481 MsZrtpCryptoTypesCount linphone_core_get_zrtp_sas_suites(LinphoneCore *lc, MSZrtpSasType sasTypes[MS_MAX_ZRTP_CRYPTO_TYPES]){
1482 char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_sas_suites", NULL);
1483 MsZrtpCryptoTypesCount sas_count = 0;
1484 char * entry, * origPtr;
1485 if (zrtpConfig == NULL) {
1486 return 0;
1487 }
1488
1489 origPtr = ms_strdup(zrtpConfig);
1490 zrtpConfig = origPtr;
1491 while ((entry = seperate_string_list(&zrtpConfig))) {
1492 const MSZrtpSasType type = ms_zrtp_sas_type_from_string(entry);
1493 if (type != MS_ZRTP_SAS_INVALID) {
1494 ms_message("Configured zrtp SAS type: '%s'", ms_zrtp_sas_type_to_string(type));
1495 sasTypes[sas_count++] = type;
1496 }
1497 }
1498
1499 ms_free(origPtr);
1500 return sas_count;
1501 }
1502
linphone_core_get_supported_file_formats(LinphoneCore * core)1503 const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){
1504 static const char *mkv="mkv";
1505 static const char *wav="wav";
1506 if (core->supported_formats==NULL){
1507 core->supported_formats=ms_malloc0(3*sizeof(char*));
1508 core->supported_formats[0]=wav;
1509 if (ms_factory_lookup_filter_by_id(core->factory,MS_MKV_RECORDER_ID)){
1510 core->supported_formats[1]=mkv;
1511 }
1512 }
1513 return core->supported_formats;
1514 }
1515
linphone_core_file_format_supported(LinphoneCore * lc,const char * fmt)1516 bool_t linphone_core_file_format_supported(LinphoneCore *lc, const char *fmt){
1517 const char **formats=linphone_core_get_supported_file_formats(lc);
1518 for(;*formats!=NULL;++formats){
1519 if (strcasecmp(*formats,fmt)==0) return TRUE;
1520 }
1521 return FALSE;
1522 }
1523
linphone_core_symmetric_rtp_enabled(LinphoneCore * lc)1524 bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc){
1525 /* Clients don't really need rtp symmetric, unless they have a public IP address and want
1526 * to interoperate with natted client. This case is not frequent with client apps.
1527 */
1528 return lp_config_get_int(lc->config,"rtp","symmetric",0);
1529 }
1530
linphone_core_set_network_simulator_params(LinphoneCore * lc,const OrtpNetworkSimulatorParams * params)1531 LinphoneStatus linphone_core_set_network_simulator_params(LinphoneCore *lc, const OrtpNetworkSimulatorParams *params){
1532 if (params!=&lc->net_conf.netsim_params)
1533 lc->net_conf.netsim_params=*params;
1534 /*TODO: should we make some sanity checks on the parameters here*/
1535 return 0;
1536 }
1537
linphone_core_get_network_simulator_params(const LinphoneCore * lc)1538 const OrtpNetworkSimulatorParams *linphone_core_get_network_simulator_params(const LinphoneCore *lc){
1539 return &lc->net_conf.netsim_params;
1540 }
1541
1542 static const char *_tunnel_mode_str[3] = { "disable", "enable", "auto" };
1543
linphone_tunnel_mode_from_string(const char * string)1544 LinphoneTunnelMode linphone_tunnel_mode_from_string(const char *string) {
1545 if(string != NULL) {
1546 int i;
1547 for(i=0; i<3 && strcmp(string, _tunnel_mode_str[i]) != 0; i++);
1548 if(i<3) {
1549 return (LinphoneTunnelMode)i;
1550 } else {
1551 ms_error("Invalid tunnel mode '%s'", string);
1552 return LinphoneTunnelModeDisable;
1553 }
1554 } else {
1555 return LinphoneTunnelModeDisable;
1556 }
1557 }
1558
linphone_tunnel_mode_to_string(LinphoneTunnelMode mode)1559 const char *linphone_tunnel_mode_to_string(LinphoneTunnelMode mode) {
1560 switch(mode){
1561 case LinphoneTunnelModeAuto:
1562 return "auto";
1563 case LinphoneTunnelModeDisable:
1564 return "disable";
1565 case LinphoneTunnelModeEnable:
1566 return "enable";
1567 }
1568 return "invalid";
1569 }
1570
1571
1572 typedef struct Hook{
1573 LinphoneCoreIterateHook fun;
1574 void *data;
1575 }Hook;
1576
linphone_task_list_init(LinphoneTaskList * t)1577 void linphone_task_list_init(LinphoneTaskList *t){
1578 t->hooks = NULL;
1579 }
1580
hook_new(LinphoneCoreIterateHook hook,void * hook_data)1581 static Hook *hook_new(LinphoneCoreIterateHook hook, void *hook_data){
1582 Hook *h=ms_new0(Hook,1);
1583 h->fun=hook;
1584 h->data=hook_data;
1585 return h;
1586 }
1587
hook_invoke(Hook * h)1588 static void hook_invoke(Hook *h){
1589 h->fun(h->data);
1590 }
1591
linphone_task_list_add(LinphoneTaskList * t,LinphoneCoreIterateHook hook,void * hook_data)1592 void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){
1593 t->hooks = bctbx_list_append(t->hooks,hook_new(hook,hook_data));
1594 }
1595
linphone_task_list_remove(LinphoneTaskList * t,LinphoneCoreIterateHook hook,void * hook_data)1596 void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){
1597 bctbx_list_t *elem;
1598 for(elem=t->hooks;elem!=NULL;elem=elem->next){
1599 Hook *h=(Hook*)elem->data;
1600 if (h->fun==hook && h->data==hook_data){
1601 t->hooks = bctbx_list_erase_link(t->hooks,elem);
1602 ms_free(h);
1603 return;
1604 }
1605 }
1606 ms_error("linphone_task_list_remove(): No such hook found.");
1607 }
1608
linphone_task_list_run(LinphoneTaskList * t)1609 void linphone_task_list_run(LinphoneTaskList *t){
1610 bctbx_list_for_each(t->hooks,(void (*)(void*))hook_invoke);
1611 }
1612
linphone_task_list_free(LinphoneTaskList * t)1613 void linphone_task_list_free(LinphoneTaskList *t){
1614 t->hooks = bctbx_list_free_with_data(t->hooks, (void (*)(void*))ms_free);
1615 }
1616
_ice_params_found_in_remote_media_description(IceSession * ice_session,const SalMediaDescription * md)1617 static bool_t _ice_params_found_in_remote_media_description(IceSession *ice_session, const SalMediaDescription *md) {
1618 const SalStreamDescription *stream;
1619 IceCheckList *cl = NULL;
1620 int i;
1621 bool_t ice_params_found = FALSE;
1622 if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) {
1623 ice_params_found=TRUE;
1624 } else {
1625 for (i = 0; i < md->nb_streams; i++) {
1626 stream = &md->streams[i];
1627 cl = ice_session_check_list(ice_session, i);
1628 if (cl) {
1629 if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
1630 ice_params_found=TRUE;
1631 } else {
1632 ice_params_found=FALSE;
1633 break;
1634 }
1635 }
1636 }
1637 }
1638 return ice_params_found;
1639 }
1640
_check_for_ice_restart_and_set_remote_credentials(IceSession * ice_session,const SalMediaDescription * md,bool_t is_offer)1641 static bool_t _check_for_ice_restart_and_set_remote_credentials(IceSession *ice_session, const SalMediaDescription *md, bool_t is_offer) {
1642 const SalStreamDescription *stream;
1643 IceCheckList *cl = NULL;
1644 bool_t ice_restarted = FALSE;
1645 int i;
1646
1647 if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) {
1648 ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling);
1649 ice_restarted = TRUE;
1650 } else {
1651 for (i = 0; i < md->nb_streams; i++) {
1652 stream = &md->streams[i];
1653 cl = ice_session_check_list(ice_session, i);
1654 if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
1655 ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling);
1656 ice_restarted = TRUE;
1657 break;
1658 }
1659 }
1660 }
1661 if ((ice_session_remote_ufrag(ice_session) == NULL) && (ice_session_remote_pwd(ice_session) == NULL)) {
1662 ice_session_set_remote_credentials(ice_session, md->ice_ufrag, md->ice_pwd);
1663 } else if (ice_session_remote_credentials_changed(ice_session, md->ice_ufrag, md->ice_pwd)) {
1664 if (ice_restarted == FALSE) {
1665 ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling);
1666 ice_restarted = TRUE;
1667 }
1668 ice_session_set_remote_credentials(ice_session, md->ice_ufrag, md->ice_pwd);
1669 }
1670 for (i = 0; i < md->nb_streams; i++) {
1671 stream = &md->streams[i];
1672 cl = ice_session_check_list(ice_session, i);
1673 if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
1674 if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) {
1675 if (ice_restarted == FALSE
1676 && ice_check_list_get_remote_ufrag(cl)
1677 && ice_check_list_get_remote_pwd(cl)) {
1678 /* restart only if remote ufrag/paswd was already set*/
1679 ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling);
1680 ice_restarted = TRUE;
1681 }
1682 ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
1683 break;
1684 }
1685 }
1686 }
1687 return ice_restarted;
1688 }
1689
_create_ice_check_lists_and_parse_ice_attributes(LinphoneCall * call,const SalMediaDescription * md,bool_t ice_restarted)1690 static void _create_ice_check_lists_and_parse_ice_attributes(LinphoneCall *call, const SalMediaDescription *md, bool_t ice_restarted) {
1691 const SalStreamDescription *stream;
1692 IceCheckList *cl = NULL;
1693 bool_t default_candidate = FALSE;
1694 const char *addr = NULL;
1695 int port = 0;
1696 int componentID = 0;
1697 int remote_family;
1698 int family;
1699 int i, j;
1700
1701 for (i = 0; i < md->nb_streams; i++) {
1702 stream = &md->streams[i];
1703 cl = ice_session_check_list(call->ice_session, i);
1704
1705 if (cl==NULL) continue;
1706 if (stream->ice_mismatch == TRUE) {
1707 ice_check_list_set_state(cl, ICL_Failed);
1708 continue;
1709 }
1710 if (stream->rtp_port == 0) {
1711 ice_session_remove_check_list(call->ice_session, cl);
1712 clear_ice_check_list(call,cl);
1713 continue;
1714 }
1715
1716 if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
1717 ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
1718 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
1719 const SalIceCandidate *candidate = &stream->ice_candidates[j];
1720 default_candidate = FALSE;
1721 addr = NULL;
1722 port = 0;
1723 if (candidate->addr[0] == '\0') break;
1724 if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue;
1725 get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port);
1726 if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
1727 default_candidate = TRUE;
1728 if (strchr(candidate->addr, ':') != NULL) family = AF_INET6;
1729 else family = AF_INET;
1730 ice_add_remote_candidate(cl, candidate->type, family, candidate->addr, candidate->port, candidate->componentID,
1731 candidate->priority, candidate->foundation, default_candidate);
1732 }
1733 if (ice_restarted == FALSE) {
1734 bool_t losing_pairs_added = FALSE;
1735 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
1736 const SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[j];
1737 addr = NULL;
1738 port = 0;
1739 componentID = j + 1;
1740 if (remote_candidate->addr[0] == '\0') break;
1741 get_default_addr_and_port(componentID, md, stream, &addr, &port);
1742 if (j == 0) {
1743 /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */
1744 ice_check_list_unselect_valid_pairs(cl);
1745 }
1746 if (strchr(remote_candidate->addr, ':') != NULL) remote_family = AF_INET6;
1747 else remote_family = AF_INET;
1748 if (strchr(addr, ':') != NULL) family = AF_INET6;
1749 else family = AF_INET;
1750
1751 ice_add_losing_pair(cl, j + 1, remote_family, remote_candidate->addr, remote_candidate->port, family, addr, port);
1752 losing_pairs_added = TRUE;
1753 }
1754 if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl);
1755 }
1756 }
1757 }
1758
_update_ice_from_remote_media_description(LinphoneCall * call,const SalMediaDescription * md,bool_t is_offer)1759 static void _update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer) {
1760 const SalStreamDescription *stream;
1761 IceCheckList *cl = NULL;
1762 bool_t ice_restarted = FALSE;
1763 int i;
1764
1765 /* Check for ICE restart and set remote credentials. */
1766 ice_restarted = _check_for_ice_restart_and_set_remote_credentials(call->ice_session, md, is_offer);
1767
1768 /* Create ICE check lists if needed and parse ICE attributes. */
1769 _create_ice_check_lists_and_parse_ice_attributes(call, md, ice_restarted);
1770 for (i = 0; i < md->nb_streams; i++) {
1771 stream = &md->streams[i];
1772 cl = ice_session_check_list(call->ice_session, i);
1773 if (!cl) continue;
1774
1775 if (!sal_stream_description_active(stream)) {
1776 ice_session_remove_check_list_from_idx(call->ice_session, i);
1777 clear_ice_check_list(call, cl);
1778 }
1779 }
1780 linphone_call_clear_unused_ice_candidates(call, md);
1781 ice_session_check_mismatch(call->ice_session);
1782 }
1783
linphone_call_update_ice_from_remote_media_description(LinphoneCall * call,const SalMediaDescription * md,bool_t is_offer)1784 void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer){
1785 if (_ice_params_found_in_remote_media_description(call->ice_session, md) == TRUE) {
1786 _update_ice_from_remote_media_description(call, md, is_offer);
1787 } else {
1788 /* Response from remote does not contain mandatory ICE attributes, delete the session. */
1789 linphone_call_delete_ice_session(call);
1790 linphone_call_set_symmetric_rtp(call, linphone_core_symmetric_rtp_enabled(linphone_call_get_core(call)));
1791 return;
1792 }
1793 if (ice_session_nb_check_lists(call->ice_session) == 0) {
1794 linphone_call_delete_ice_session(call);
1795 linphone_call_set_symmetric_rtp(call, linphone_core_symmetric_rtp_enabled(linphone_call_get_core(call)));
1796 }
1797 }
1798
linphone_core_report_call_log(LinphoneCore * lc,LinphoneCallLog * call_log)1799 void linphone_core_report_call_log(LinphoneCore *lc, LinphoneCallLog *call_log){
1800 bool_t call_logs_sqlite_db_found = FALSE;
1801
1802 #ifdef SQLITE_STORAGE_ENABLED
1803 if (lc->logs_db) {
1804 call_logs_sqlite_db_found = TRUE;
1805 linphone_core_store_call_log(lc, call_log);
1806 }
1807 #endif
1808 if (!call_logs_sqlite_db_found) {
1809 lc->call_logs=bctbx_list_prepend(lc->call_logs,linphone_call_log_ref(call_log));
1810 if (bctbx_list_size(lc->call_logs)>(size_t)lc->max_call_logs){
1811 bctbx_list_t *elem,*prevelem=NULL;
1812 /*find the last element*/
1813 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
1814 prevelem = elem;
1815 }
1816 elem = prevelem;
1817 linphone_call_log_unref((LinphoneCallLog*)elem->data);
1818 lc->call_logs = bctbx_list_erase_link(lc->call_logs,elem);
1819 }
1820 call_logs_write_to_config_file(lc);
1821 }
1822
1823 linphone_core_notify_call_log_updated(lc,call_log);
1824 }
1825
linphone_core_report_early_failed_call(LinphoneCore * lc,LinphoneCallDir dir,LinphoneAddress * from,LinphoneAddress * to,LinphoneErrorInfo * ei)1826 void linphone_core_report_early_failed_call(LinphoneCore *lc, LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress *to, LinphoneErrorInfo *ei){
1827 LinphoneCallLog *l = linphone_call_log_new(dir, from, to);
1828 l->error_info = ei;
1829 l->status = LinphoneCallEarlyAborted;
1830 linphone_core_report_call_log(lc, l);
1831 linphone_call_log_unref(l);
1832 }
1833
1834 /* Functions to mainpulate the LinphoneRange structure */
1835
1836 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneRange);
1837
1838 BELLE_SIP_INSTANCIATE_VPTR(LinphoneRange, belle_sip_object_t,
1839 NULL, // destroy
1840 NULL, // clone
1841 NULL, // marshal
1842 FALSE
1843 );
1844
linphone_range_new()1845 LinphoneRange *linphone_range_new() {
1846 LinphoneRange *range = belle_sip_object_new(LinphoneRange);
1847 range->min = 0;
1848 range->max = 0;
1849 return range;
1850 }
1851
linphone_range_ref(LinphoneRange * range)1852 LinphoneRange* linphone_range_ref(LinphoneRange* range) {
1853 return (LinphoneRange*) belle_sip_object_ref(range);
1854 }
1855
linphone_range_unref(LinphoneRange * range)1856 void linphone_range_unref(LinphoneRange* range) {
1857 belle_sip_object_unref(range);
1858 }
1859
linphone_range_get_user_data(const LinphoneRange * range)1860 void *linphone_range_get_user_data(const LinphoneRange *range) {
1861 return range->user_data;
1862 }
1863
linphone_range_set_user_data(LinphoneRange * range,void * data)1864 void linphone_range_set_user_data(LinphoneRange *range, void *data) {
1865 range->user_data = data;
1866 }
1867
linphone_range_get_min(const LinphoneRange * range)1868 int linphone_range_get_min(const LinphoneRange *range) {
1869 return range->min;
1870 }
1871
linphone_range_get_max(const LinphoneRange * range)1872 int linphone_range_get_max(const LinphoneRange *range) {
1873 return range->max;
1874 }
1875
linphone_range_set_min(LinphoneRange * range,int min)1876 void linphone_range_set_min(LinphoneRange *range, int min) {
1877 range->min = min;
1878 }
1879
linphone_range_set_max(LinphoneRange * range,int max)1880 void linphone_range_set_max(LinphoneRange *range, int max) {
1881 range->max = max;
1882 }
1883
1884
1885
linphone_headers_ref(LinphoneHeaders * obj)1886 LinphoneHeaders * linphone_headers_ref(LinphoneHeaders *obj){
1887 sal_custom_header_ref((SalCustomHeader*)obj);
1888 return obj;
1889 }
1890
1891
linphone_headers_unref(LinphoneHeaders * obj)1892 void linphone_headers_unref(LinphoneHeaders *obj){
1893 sal_custom_header_unref((SalCustomHeader*)obj);
1894 }
1895
1896
linphone_headers_get_value(LinphoneHeaders * obj,const char * header_name)1897 const char* linphone_headers_get_value(LinphoneHeaders *obj, const char *header_name){
1898 return sal_custom_header_find((SalCustomHeader*)obj, header_name);
1899 }
1900
linphone_headers_add(LinphoneHeaders * obj,const char * name,const char * value)1901 void linphone_headers_add(LinphoneHeaders *obj, const char *name, const char *value){
1902 sal_custom_header_append((SalCustomHeader*)obj, name, value);
1903 }
1904
linphone_headers_remove(LinphoneHeaders * obj,const char * name)1905 void linphone_headers_remove(LinphoneHeaders *obj, const char *name){
1906 sal_custom_header_remove((SalCustomHeader*)obj, name);
1907 }
1908