]> sjero.net Git - linphone/blob - coreapi/misc.c
a22bbc1d9f57706c0050cbf988e28afabb051a75
[linphone] / coreapi / misc.c
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21 #include "private.h"
22 #include "lpconfig.h"
23 #include "mediastreamer2/mediastream.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #ifdef HAVE_SIGHANDLER_T
27 #include <signal.h>
28 #endif /*HAVE_SIGHANDLER_T*/
29
30 #include <string.h>
31 #if !defined(_WIN32_WCE)
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #endif /*_WIN32_WCE*/
38
39 #undef snprintf
40 #include <ortp/stun.h>
41
42 #ifdef HAVE_GETIFADDRS
43 #include <net/if.h>
44 #include <ifaddrs.h>
45 #endif
46
47
48 #if !defined(WIN32)
49
50 static char lock_name[80];
51 static char lock_set=0;
52 /* put a lock file in /tmp. this is called when linphone runs as a daemon*/
53 int set_lock_file()
54 {
55         FILE *lockfile;
56
57         snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
58         lockfile=fopen(lock_name,"w");
59         if (lockfile==NULL)
60         {
61                 printf("Failed to create lock file.\n");
62                 return(-1);
63         }
64         fprintf(lockfile,"%i",getpid());
65         fclose(lockfile);
66         lock_set=1;
67         return(0);
68 }
69
70 /* looks if there is a lock file. If presents return its content (the pid of the already running linphone), if not found, returns -1*/
71 int get_lock_file()
72 {
73         int pid;
74         FILE *lockfile;
75
76         snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
77         lockfile=fopen(lock_name,"r");
78         if (lockfile==NULL)
79                 return(-1);
80         if (fscanf(lockfile,"%i",&pid)!=1){
81                 ms_warning("Could not read pid in lock file.");
82                 fclose(lockfile);
83                 return -1;
84         }
85         fclose(lockfile);
86         return pid;
87 }
88
89 /* remove the lock file if it was set*/
90 int remove_lock_file()
91 {
92         int err=0;
93         if (lock_set)
94         {
95                 err=unlink(lock_name);
96                 lock_set=0;
97         }
98         return(err);
99 }
100
101 #endif
102
103 char *int2str(int number)
104 {
105         char *numstr=ms_malloc(10);
106         snprintf(numstr,10,"%i",number);
107         return numstr;
108 }
109
110 void check_sound_device(LinphoneCore *lc)
111 {
112 #ifdef _linux
113         int fd=0;
114         int len;
115         int a;
116         char *file=NULL;
117         char *i810_audio=NULL;
118         char *snd_pcm_oss=NULL;
119         char *snd_mixer_oss=NULL;
120         char *snd_pcm=NULL;
121         fd=open("/proc/modules",O_RDONLY);
122
123         if (fd>0){
124                 /* read the entire /proc/modules file and check if sound conf seems correct */
125                 /*a=fstat(fd,&statbuf);
126                 if (a<0) ms_warning("Can't stat /proc/modules:%s.",strerror(errno));
127                 len=statbuf.st_size;
128                 if (len==0) ms_warning("/proc/modules has zero size!");
129                 */
130                 /***** fstat does not work on /proc/modules for unknown reason *****/
131                 len=6000;
132                 file=ms_malloc(len+1);
133                 a=read(fd,file,len);
134                 if (a<len) file=ms_realloc(file,a+1);
135                 file[a]='\0';
136                 i810_audio=strstr(file,"i810_audio");
137                 if (i810_audio!=NULL){
138                         /* I'm sorry i put this warning in comments because
139                          * i don't use yet the right driver !! */
140 /*                      lc->vtable.display_warning(lc,_("You are currently using the i810_audio driver.\nThis driver is buggy and so does not work with Linphone.\nWe suggest that you replace it by its equivalent ALSA driver,\neither with packages from your distribution, or by downloading\nALSA drivers at http://www.alsa-project.org."));*/
141                         goto end;
142                 }
143                 snd_pcm=strstr(file,"snd-pcm");
144                 if (snd_pcm!=NULL){
145                         snd_pcm_oss=strstr(file,"snd-pcm-oss");
146                         snd_mixer_oss=strstr(file,"snd-mixer-oss");
147                         if (snd_pcm_oss==NULL){
148                                 lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the pcm oss emulation module\nis missing and linphone needs it. Please execute\n'modprobe snd-pcm-oss' as root to load it."));
149                         }
150                         if (snd_mixer_oss==NULL){
151                                 lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the mixer oss emulation module\nis missing and linphone needs it. Please execute\n 'modprobe snd-mixer-oss' as root to load it."));
152                         }
153                 }
154         }else {
155
156                 ms_warning("Could not open /proc/modules.");
157         }
158         /* now check general volume. Some user forget to rise it and then complain that linphone is
159         not working */
160         /* but some other users complain that linphone should not change levels...
161         if (lc->sound_conf.sndcard!=NULL){
162                 a=snd_card_get_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL);
163                 if (a<50){
164                         ms_warning("General level is quite low (%i). Linphone rises it up for you.",a);
165                         snd_card_set_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL,80);
166                 }
167         }
168         */
169         end:
170         if (file!=NULL) ms_free(file);
171         if (fd>0) close(fd);
172 #endif
173 }
174
175 #define UDP_HDR_SZ 8
176 #define RTP_HDR_SZ 12
177 #define IP4_HDR_SZ 20   /*20 is the minimum, but there may be some options*/
178
179 static void payload_type_set_enable(PayloadType *pt,int value)
180 {
181         if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \
182         else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
183 }
184
185 static bool_t payload_type_enabled(const PayloadType *pt) {
186         return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
187 }
188
189 bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt){
190         if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){
191                 return payload_type_enabled(pt);
192         }
193         ms_error("Getting enablement status of codec not in audio or video list of PayloadType !");
194         return FALSE;
195 }
196
197 int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){
198         if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
199                 payload_type_set_enable(pt,enabled);
200                 _linphone_core_codec_config_write(lc);
201                 return 0;
202         }
203         ms_error("Enabling codec not in audio or video list of PayloadType !");
204         return -1;
205 }
206
207 int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){
208        return payload_type_get_number(pt);
209 }
210
211 const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
212         if (ms_filter_codec_supported(pt->mime_type)){
213                 MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
214 #ifdef ENABLE_NLS
215                 return dgettext("mediastreamer",desc->text);
216 #else
217                 return desc->text;
218 #endif
219         }
220         return NULL;
221 }
222
223
224 /*this function makes a special case for speex/8000.
225 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
226 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
227 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
228         int upload_bw=linphone_core_get_upload_bandwidth(lc);
229         if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
230                 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
231                         return 15000;
232                 }
233         }
234         return pt->normal_bitrate;
235 }
236
237 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
238         double npacket=50;
239         double packet_size;
240         int bitrate;
241         bitrate=get_codec_bitrate(lc,pt);
242         packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
243         return packet_size*8.0*npacket;
244 }
245
246 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){
247         call->audio_bw=(int)(get_audio_payload_bandwidth(call->core,pt)/1000.0);
248         ms_message("Audio bandwidth for this call is %i",call->audio_bw);
249 }
250
251 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
252         const MSList *elem;
253         PayloadType *max=NULL;
254         for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
255                 PayloadType *pt=(PayloadType*)elem->data;
256                 if (payload_type_enabled(pt)){
257                         int pt_bitrate=get_codec_bitrate(lc,pt);
258                         if (max==NULL) max=pt;
259                         else if (max->normal_bitrate<pt_bitrate){
260                                 max=pt;
261                         }
262                 }
263         }
264         if (max) {
265                 lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0);
266         }
267 }
268
269 bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt,  int bandwidth_limit)
270 {
271         double codec_band;
272         bool_t ret=FALSE;
273         
274         switch (pt->type){
275                 case PAYLOAD_AUDIO_CONTINUOUS:
276                 case PAYLOAD_AUDIO_PACKETIZED:
277                         codec_band=get_audio_payload_bandwidth(lc,pt);
278                         ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
279                         /*hack to avoid using uwb codecs when having low bitrate and video*/
280                         if (bandwidth_is_greater(199,bandwidth_limit)){
281                                 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
282                                         ret=FALSE;
283                                 }
284                         }
285                         //ms_message("Payload %s: %g",pt->mime_type,codec_band);
286                         break;
287                 case PAYLOAD_VIDEO:
288                         if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/
289                                 ret=TRUE;
290                         }
291                         else ret=FALSE;
292                         break;
293         }
294         return ret;
295 }
296
297 /* return TRUE if codec can be used with bandwidth, FALSE else*/
298 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
299 {
300         double codec_band;
301         int allowed_bw,video_bw;
302         bool_t ret=FALSE;
303
304         linphone_core_update_allocated_audio_bandwidth(lc);
305         allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
306                                         linphone_core_get_upload_bandwidth(lc));
307         if (allowed_bw==0) {
308                 allowed_bw=-1;
309                 video_bw=1500; /*around 1.5 Mbit/s*/
310         }else
311                 video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw);
312
313         switch (pt->type){
314                 case PAYLOAD_AUDIO_CONTINUOUS:
315                 case PAYLOAD_AUDIO_PACKETIZED:
316                         codec_band=get_audio_payload_bandwidth(lc,pt);
317                         ret=bandwidth_is_greater(allowed_bw*1000,codec_band);
318                         /*hack to avoid using uwb codecs when having low bitrate and video*/
319                         if (bandwidth_is_greater(199,allowed_bw)){
320                                 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
321                                         ret=FALSE;
322                                 }
323                         }
324                         //ms_message("Payload %s: %g",pt->mime_type,codec_band);
325                         break;
326                 case PAYLOAD_VIDEO:
327                         if (video_bw>0){
328                                 pt->normal_bitrate=video_bw*1000;
329                                 ret=TRUE;
330                         }
331                         else ret=FALSE;
332                         break;
333         }
334         return ret;
335 }
336
337 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
338 #if !defined(_WIN32_WCE)
339         FILE *f=popen(command,"r");
340         if (f!=NULL){
341                 int err;
342                 *result=ms_malloc(4096);
343                 err=fread(*result,1,4096-1,f);
344                 if (err<0){
345                         ms_warning("Error reading command output:%s",strerror(errno));
346                         ms_free(result);
347                         return FALSE;
348                 }
349                 (*result)[err]=0;
350                 err=pclose(f);
351                 if (command_ret!=NULL) *command_ret=err;
352                 return TRUE;
353         }
354 #endif /*_WIN32_WCE*/
355         return FALSE;
356 }
357
358 static ortp_socket_t create_socket(int local_port){
359         struct sockaddr_in laddr;
360         ortp_socket_t sock;
361         int optval;
362         sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
363         if (sock<0) {
364                 ms_error("Fail to create socket");
365                 return -1;
366         }
367         memset (&laddr,0,sizeof(laddr));
368         laddr.sin_family=AF_INET;
369         laddr.sin_addr.s_addr=INADDR_ANY;
370         laddr.sin_port=htons(local_port);
371         if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
372                 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
373                 close_socket(sock);
374                 return -1;
375         }
376         optval=1;
377         if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
378                                 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
379                 ms_warning("Fail to set SO_REUSEADDR");
380         }
381         set_non_blocking_socket(sock);
382         return sock;
383 }
384
385 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
386         char buf[STUN_MAX_MESSAGE_SIZE];
387         int len = STUN_MAX_MESSAGE_SIZE;
388         StunAtrString username;
389         StunAtrString password;
390         StunMessage req;
391         int err;
392         memset(&req, 0, sizeof(StunMessage));
393         memset(&username,0,sizeof(username));
394         memset(&password,0,sizeof(password));
395         stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
396         len = stunEncodeMessage( &req, buf, len, &password);
397         if (len<=0){
398                 ms_error("Fail to encode stun message.");
399                 return -1;
400         }
401         err=sendto(sock,buf,len,0,server,addrlen);
402         if (err<0){
403                 ms_error("sendto failed: %s",strerror(errno));
404                 return -1;
405         }
406         return 0;
407 }
408
409 int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
410         struct addrinfo hints,*res=NULL;
411         int family = PF_INET;
412         int port_int = 3478;
413         int ret;
414         char port[6];
415         char host[NI_MAXHOST];
416         char *p1, *p2;
417         if ((sscanf(server, "[%64[^]]]:%d", host, &port_int) == 2) || (sscanf(server, "[%64[^]]]", host) == 1)) {
418                 family = PF_INET6;
419         } else {
420                 p1 = strchr(server, ':');
421                 p2 = strrchr(server, ':');
422                 if (p1 && p2 && (p1 != p2)) {
423                         family = PF_INET6;
424                         host[NI_MAXHOST-1]='\0';
425                         strncpy(host, server, sizeof(host) - 1);
426                 } else if (sscanf(server, "%[^:]:%d", host, &port_int) != 2) {
427                         host[NI_MAXHOST-1]='\0';
428                         strncpy(host, server, sizeof(host) - 1);
429                 }
430         }
431         snprintf(port, sizeof(port), "%d", port_int);
432         memset(&hints,0,sizeof(hints));
433         hints.ai_family=family;
434         hints.ai_socktype=SOCK_DGRAM;
435         hints.ai_protocol=IPPROTO_UDP;
436         ret=getaddrinfo(host,port,&hints,&res);
437         if (ret!=0){
438                 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
439                 return -1;
440         }
441         if (!res) return -1;
442         memcpy(ss,res->ai_addr,res->ai_addrlen);
443         *socklen=res->ai_addrlen;
444         freeaddrinfo(res);
445         return 0;
446 }
447
448 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
449         char buf[STUN_MAX_MESSAGE_SIZE];
450         int len = STUN_MAX_MESSAGE_SIZE;
451         StunMessage resp;
452         len=recv(sock,buf,len,0);
453         if (len>0){
454                 struct in_addr ia;
455                 stunParseMessage(buf,len, &resp );
456                 *id=resp.msgHdr.tr_id.octet[0];
457                 if (resp.hasXorMappedAddress){
458                         *port = resp.xorMappedAddress.ipv4.port;
459                         ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
460                 }else if (resp.hasMappedAddress){
461                         *port = resp.mappedAddress.ipv4.port;
462                         ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
463                 }else return -1;
464                 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
465         }
466         return len;
467 }
468
469 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
470         const char *server=linphone_core_get_stun_server(lc);
471
472         if (lc->sip_conf.ipv6_enabled){
473                 ms_warning("stun support is not implemented for ipv6");
474                 return;
475         }
476         if (server!=NULL){
477                 struct sockaddr_storage ss;
478                 socklen_t ss_len;
479                 ortp_socket_t sock1=-1, sock2=-1;
480                 int loops=0;
481                 bool_t video_enabled=linphone_core_video_enabled(lc);
482                 bool_t got_audio,got_video;
483                 bool_t cone_audio=FALSE,cone_video=FALSE;
484                 struct timeval init,cur;
485                 SalEndpointCandidate *ac,*vc;
486                 
487                 ac=&call->localdesc->streams[0].candidates[0];
488                 vc=&call->localdesc->streams[1].candidates[0];
489                 
490                 if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
491                         ms_error("Fail to parser stun server address: %s",server);
492                         return;
493                 }
494                 if (lc->vtable.display_status!=NULL)
495                         lc->vtable.display_status(lc,_("Stun lookup in progress..."));
496
497                 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
498                 sock1=create_socket(call->audio_port);
499                 if (sock1==-1) return;
500                 if (video_enabled){
501                         sock2=create_socket(call->video_port);
502                         if (sock2==-1) return ;
503                 }
504                 got_audio=FALSE;
505                 got_video=FALSE;
506                 gettimeofday(&init,NULL);
507                 do{
508                         double elapsed;
509                         int id;
510                         if (loops%20==0){
511                                 ms_message("Sending stun requests...");
512                                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
513                                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
514                                 if (sock2!=-1){
515                                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
516                                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
517                                 }
518                         }
519 #ifdef WIN32
520                         Sleep(10);
521 #else
522                         usleep(10000);
523 #endif
524
525                         if (recvStunResponse(sock1,ac->addr,
526                                                 &ac->port,&id)>0){
527                                 ms_message("STUN test result: local audio port maps to %s:%i",
528                                                 ac->addr,
529                                                 ac->port);
530                                 if (id==11)
531                                         cone_audio=TRUE;
532                                 got_audio=TRUE;
533                         }
534                         if (recvStunResponse(sock2,vc->addr,
535                                                         &vc->port,&id)>0){
536                                 ms_message("STUN test result: local video port maps to %s:%i",
537                                         vc->addr,
538                                         vc->port);
539                                 if (id==22)
540                                         cone_video=TRUE;
541                                 got_video=TRUE;
542                         }
543                         gettimeofday(&cur,NULL);
544                         elapsed=((cur.tv_sec-init.tv_sec)*1000.0) +  ((cur.tv_usec-init.tv_usec)/1000.0);
545                         if (elapsed>2000)  {
546                                 ms_message("Stun responses timeout, going ahead.");
547                                 break;
548                         }
549                         loops++;
550                 }while(!(got_audio && (got_video||sock2==-1)  ) );
551                 if (!got_audio){
552                         ms_error("No stun server response for audio port.");
553                 }else{
554                         if (!cone_audio) {
555                                 ms_message("NAT is symmetric for audio port");
556                         }
557                 }
558                 if (sock2!=-1){
559                         if (!got_video){
560                                 ms_error("No stun server response for video port.");
561                         }else{
562                                 if (!cone_video) {
563                                         ms_message("NAT is symmetric for video port.");
564                                 }
565                         }
566                 }
567                 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
568                     || sock2==-1){
569                         strcpy(call->localdesc->addr,ac->addr);
570                 }
571                 close_socket(sock1);
572                 if (sock2!=-1) close_socket(sock2);
573         }
574 }
575
576 int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
577 {
578         char local_addr[64];
579         struct sockaddr_storage ss;
580         socklen_t ss_len;
581         IceCheckList *audio_check_list;
582         IceCheckList *video_check_list;
583         const char *server = linphone_core_get_stun_server(lc);
584
585         if ((server == NULL) || (call->ice_session == NULL)) return -1;
586         audio_check_list = ice_session_check_list(call->ice_session, 0);
587         video_check_list = ice_session_check_list(call->ice_session, 1);
588         if (audio_check_list == NULL) return -1;
589
590         if (lc->sip_conf.ipv6_enabled){
591                 ms_warning("stun support is not implemented for ipv6");
592                 return -1;
593         }
594
595         if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) {
596                 ms_error("Fail to parser stun server address: %s", server);
597                 return -1;
598         }
599         if (lc->vtable.display_status != NULL)
600                 lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
601
602         /* Gather local host candidates. */
603         if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
604                 ms_error("Fail to get local ip");
605                 return -1;
606         }
607         ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
608         ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
609         if (call->params.has_video && (video_check_list != NULL)) {
610                 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
611                 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
612         }
613
614         /* Gather local srflx candidates. */
615         ice_session_gather_candidates(call->ice_session, ss, ss_len);
616         return 0;
617 }
618
619 void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
620 {
621         const char *rtp_addr, *rtcp_addr;
622         IceSessionState session_state = ice_session_state(session);
623         int nb_candidates;
624         int i, j;
625         bool_t result;
626
627         if (session_state == IS_Completed) {
628                 desc->ice_completed = TRUE;
629                 ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
630                 strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
631         }
632         else {
633                 desc->ice_completed = FALSE;
634         }
635         strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
636         strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
637         for (i = 0; i < desc->nstreams; i++) {
638                 SalStreamDescription *stream = &desc->streams[i];
639                 IceCheckList *cl = ice_session_check_list(session, i);
640                 nb_candidates = 0;
641                 if (cl == NULL) continue;
642                 if (ice_check_list_state(cl) == ICL_Completed) {
643                         stream->ice_completed = TRUE;
644                         result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
645                 } else {
646                         stream->ice_completed = FALSE;
647                         result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
648                 }
649                 if (result == TRUE) {
650                         strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr));
651                         strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr));
652                 } else {
653                         memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr));
654                         memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr));
655                 }
656                 if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd)))
657                         strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd));
658                 else
659                         memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
660                 if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag)))
661                         strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag));
662                 else
663                         memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
664                 stream->ice_mismatch = ice_check_list_is_mismatch(cl);
665                 if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) {
666                         memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates));
667                         for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) {
668                                 SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates];
669                                 IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j);
670                                 const char *default_addr = NULL;
671                                 int default_port = 0;
672                                 if (ice_candidate->componentID == 1) {
673                                         default_addr = stream->rtp_addr;
674                                         default_port = stream->rtp_port;
675                                 } else if (ice_candidate->componentID == 2) {
676                                         default_addr = stream->rtcp_addr;
677                                         default_port = stream->rtcp_port;
678                                 } else continue;
679                                 if (default_addr[0] == '\0') default_addr = desc->addr;
680                                 /* 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. */
681                                 if ((ice_check_list_state(cl) == ICL_Completed)
682                                         && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0)))
683                                         continue;
684                                 strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation));
685                                 sal_candidate->componentID = ice_candidate->componentID;
686                                 sal_candidate->priority = ice_candidate->priority;
687                                 strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type));
688                                 strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr));
689                                 sal_candidate->port = ice_candidate->taddr.port;
690                                 if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) {
691                                         strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr));
692                                         sal_candidate->rport = ice_candidate->base->taddr.port;
693                                 }
694                                 nb_candidates++;
695                         }
696                 }
697                 if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
698                         int rtp_port, rtcp_port;
699                         memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
700                         ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
701                         strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
702                         stream->ice_remote_candidates[0].port = rtp_port;
703                         strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
704                         stream->ice_remote_candidates[1].port = rtcp_port;
705                 }
706         }
707 }
708
709 static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port)
710 {
711         if (componentID == 1) {
712                 *addr = stream->rtp_addr;
713                 *port = stream->rtp_port;
714         } else if (componentID == 2) {
715                 *addr = stream->rtcp_addr;
716                 *port = stream->rtcp_port;
717         } else return;
718         if ((*addr)[0] == '\0') *addr = md->addr;
719 }
720
721 void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
722 {
723         bool_t ice_restarted = FALSE;
724
725         if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) {
726                 int i, j;
727
728                 /* Check for ICE restart and set remote credentials. */
729                 if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) {
730                         ice_session_restart(call->ice_session);
731                         ice_restarted = TRUE;
732                 } else {
733                         for (i = 0; i < md->nstreams; i++) {
734                                 const SalStreamDescription *stream = &md->streams[i];
735                                 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
736                                 if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
737                                         ice_session_restart(call->ice_session);
738                                         ice_restarted = TRUE;
739                                         break;
740                                 }
741                         }
742                 }
743                 if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) {
744                         ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
745                 } else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) {
746                         if (ice_restarted == FALSE) {
747                                 ice_session_restart(call->ice_session);
748                                 ice_restarted = TRUE;
749                         }
750                         ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
751                 }
752                 for (i = 0; i < md->nstreams; i++) {
753                         const SalStreamDescription *stream = &md->streams[i];
754                         IceCheckList *cl = ice_session_check_list(call->ice_session, i);
755                         if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
756                                 if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) {
757                                         if (ice_restarted == FALSE) {
758                                                 ice_session_restart(call->ice_session);
759                                                 ice_restarted = TRUE;
760                                         }
761                                         ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
762                                         break;
763                                 }
764                         }
765                 }
766
767                 /* Create ICE check lists if needed and parse ICE attributes. */
768                 for (i = 0; i < md->nstreams; i++) {
769                         const SalStreamDescription *stream = &md->streams[i];
770                         IceCheckList *cl = ice_session_check_list(call->ice_session, i);
771                         if (cl == NULL) {
772                                 cl = ice_check_list_new();
773                                 ice_session_add_check_list(call->ice_session, cl);
774                                 switch (stream->type) {
775                                         case SalAudio:
776                                                 if (call->audiostream != NULL) call->audiostream->ice_check_list = cl;
777                                                 break;
778                                         case SalVideo:
779                                                 if (call->videostream != NULL) call->videostream->ice_check_list = cl;
780                                                 break;
781                                         default:
782                                                 break;
783                                 }
784                         }
785                         if ((stream->ice_mismatch == TRUE) || (stream->rtp_port == 0)) {
786                                 ice_check_list_set_state(cl, ICL_Failed);
787                         } else {
788                                 if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
789                                         ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
790                                 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
791                                         const SalIceCandidate *candidate = &stream->ice_candidates[j];
792                                         bool_t default_candidate = FALSE;
793                                         const char *addr = NULL;
794                                         int port = 0;
795                                         if (candidate->addr[0] == '\0') break;
796                                         if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue;
797                                         get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port);
798                                         if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
799                                                 default_candidate = TRUE;
800                                         ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID,
801                                                 candidate->priority, candidate->foundation, default_candidate);
802                                 }
803                                 if (ice_restarted == FALSE) {
804                                         bool_t losing_pairs_added = FALSE;
805                                         for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
806                                                 const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j];
807                                                 const char *addr = NULL;
808                                                 int port = 0;
809                                                 int componentID = j + 1;
810                                                 if (candidate->addr[0] == '\0') break;
811                                                 get_default_addr_and_port(componentID, md, stream, &addr, &port);
812                                                 ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port);
813                                                 losing_pairs_added = TRUE;
814                                         }
815                                         if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl);
816                                 }
817                         }
818                 }
819                 for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) {
820                         ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
821                 }
822                 ice_session_check_mismatch(call->ice_session);
823         }
824         if (ice_session_nb_check_lists(call->ice_session) == 0) {
825                 linphone_call_delete_ice_session(call);
826         }
827 }
828
829 void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md)
830 {
831         int i;
832         for (i = 0; i < md->nstreams; i++) {
833                 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
834                 if (cl && (md->streams[i].rtp_port == 0)) {
835                         if (ice_check_list_state(cl) != ICL_Completed) ice_check_list_set_state(cl, ICL_Failed);
836                 }
837         }
838 }
839
840 LinphoneCall * is_a_linphone_call(void *user_pointer){
841         LinphoneCall *call=(LinphoneCall*)user_pointer;
842         if (call==NULL) return NULL;
843         return call->magic==linphone_call_magic ? call : NULL;
844 }
845
846 LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer){
847         LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)user_pointer;
848         if (cfg==NULL) return NULL;
849         return cfg->magic==linphone_proxy_config_magic ? cfg : NULL;
850 }
851
852 unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
853         unsigned int ret=0;
854         const char *features=lp_config_get_string(lc->config,"sound","features",NULL);
855         if (features){
856                 char tmp[256]={0};
857                 char name[256];
858                 char *p,*n;
859                 strncpy(tmp,features,sizeof(tmp)-1);
860                 for(p=tmp;*p!='\0';p++){
861                         if (*p==' ') continue;
862                         n=strchr(p,'|');
863                         if (n) *n='\0';
864                         sscanf(p,"%s",name);
865                         ms_message("Found audio feature %s",name);
866                         if (strcasecmp(name,"PLC")==0) ret|=AUDIO_STREAM_FEATURE_PLC;
867                         else if (strcasecmp(name,"EC")==0) ret|=AUDIO_STREAM_FEATURE_EC;
868                         else if (strcasecmp(name,"EQUALIZER")==0) ret|=AUDIO_STREAM_FEATURE_EQUALIZER;
869                         else if (strcasecmp(name,"VOL_SND")==0) ret|=AUDIO_STREAM_FEATURE_VOL_SND;
870                         else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV;
871                         else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF;
872                         else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO;
873                         else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL;
874                         else if (strcasecmp(name,"NONE")==0) ret=0;
875                         else ms_error("Unsupported audio feature %s requested in config file.",name);
876                         if (!n) break;
877                         p=n;
878                 }
879         }else ret=AUDIO_STREAM_FEATURE_ALL;
880         return ret;
881 }
882
883
884 #ifdef HAVE_GETIFADDRS
885
886 #include <ifaddrs.h>
887 static int get_local_ip_with_getifaddrs(int type, char *address, int size)
888 {
889         struct ifaddrs *ifp;
890         struct ifaddrs *ifpstart;
891         int ret = 0;
892
893         if (getifaddrs(&ifpstart) < 0) {
894                 return -1;
895         }
896
897         for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
898                 if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
899                         && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
900                 {
901                         getnameinfo(ifp->ifa_addr,
902                                                 (type == AF_INET6) ?
903                                                 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
904                                                 address, size, NULL, 0, NI_NUMERICHOST);
905                         if (strchr(address, '%') == NULL) {     /*avoid ipv6 link-local addresses */
906                                 /*ms_message("getifaddrs() found %s",address);*/
907                                 ret++;
908                                 break;
909                         }
910                 }
911         }
912         freeifaddrs(ifpstart);
913         return ret;
914 }
915 #endif
916
917
918 static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
919         int err,tmp;
920         struct addrinfo hints;
921         struct addrinfo *res=NULL;
922         struct sockaddr_storage addr;
923         struct sockaddr *p_addr=(struct sockaddr*)&addr;
924         ortp_socket_t sock;
925         socklen_t s;
926
927         memset(&hints,0,sizeof(hints));
928         hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
929         hints.ai_socktype=SOCK_DGRAM;
930         /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
931         err=getaddrinfo(dest,"5060",&hints,&res);
932         if (err!=0){
933                 ms_error("getaddrinfo() error: %s",gai_strerror(err));
934                 return -1;
935         }
936         if (res==NULL){
937                 ms_error("bug: getaddrinfo returned nothing.");
938                 return -1;
939         }
940         sock=socket(res->ai_family,SOCK_DGRAM,0);
941         tmp=1;
942         err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
943         if (err<0){
944                 ms_warning("Error in setsockopt: %s",strerror(errno));
945         }
946         err=connect(sock,res->ai_addr,res->ai_addrlen);
947         if (err<0) {
948                 ms_error("Error in connect: %s",strerror(errno));
949                 freeaddrinfo(res);
950                 close_socket(sock);
951                 return -1;
952         }
953         freeaddrinfo(res);
954         res=NULL;
955         s=sizeof(addr);
956         err=getsockname(sock,(struct sockaddr*)&addr,&s);
957         if (err!=0) {
958                 ms_error("Error in getsockname: %s",strerror(errno));
959                 close_socket(sock);
960                 return -1;
961         }
962         if (p_addr->sa_family==AF_INET){
963                 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
964                 if (p_sin->sin_addr.s_addr==0){
965                         close_socket(sock);
966                         return -1;
967                 }
968         }
969         err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
970         if (err!=0){
971                 ms_error("getnameinfo error: %s",strerror(errno));
972         }
973         close_socket(sock);
974         ms_message("Local interface to reach %s is %s.",dest,result);
975         return 0;
976 }
977
978 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
979         strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
980 #ifdef HAVE_GETIFADDRS
981         if (dest==NULL) {
982                 /*we use getifaddrs for lookup of default interface */
983                 int found_ifs;
984         
985                 found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
986                 if (found_ifs==1){
987                         return 0;
988                 }else if (found_ifs<=0){
989                         /*absolutely no network on this machine */
990                         return -1;
991                 }
992         }
993 #endif
994         /*else use connect to find the best local ip address */
995         if (type==AF_INET)
996                 dest="87.98.157.38"; /*a public IP address*/
997         else dest="2a00:1450:8002::68";
998         return get_local_ip_for_with_connect(type,dest,result);
999 }
1000
1001 #ifndef WIN32
1002 #include <resolv.h>
1003
1004
1005
1006 void _linphone_core_configure_resolver(){
1007 /*bionic declares _res but does not define nor export it !!*/
1008 #ifdef ANDROID
1009         /*timeout and attempts are the same as retrans and retry, but are android specific names.*/
1010         setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1);
1011 #else
1012         res_init();
1013         _res.retrans=2; /*retransmit every two seconds*/
1014         _res.retry=2; /*only two times per DNS server*/
1015 #endif
1016 }
1017
1018 #else
1019
1020 void _linphone_core_configure_resolver(){
1021 }
1022
1023 #endif