]> sjero.net Git - linphone/blob - coreapi/misc.c
Use accessor function to get ICE check list state.
[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 ret;
412         const char *port;
413         char host[NI_MAXHOST];
414         char *p;
415         host[NI_MAXHOST-1]='\0';
416         strncpy(host,server,sizeof(host)-1);
417         p=strchr(host,':');
418         if (p) {
419                 *p='\0';
420                 port=p+1;
421         }else port="3478";
422         memset(&hints,0,sizeof(hints));
423         hints.ai_family=PF_INET;
424         hints.ai_socktype=SOCK_DGRAM;
425         hints.ai_protocol=IPPROTO_UDP;
426         ret=getaddrinfo(host,port,&hints,&res);
427         if (ret!=0){
428                 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
429                 return -1;
430         }
431         if (!res) return -1;
432         memcpy(ss,res->ai_addr,res->ai_addrlen);
433         *socklen=res->ai_addrlen;
434         freeaddrinfo(res);
435         return 0;
436 }
437
438 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
439         char buf[STUN_MAX_MESSAGE_SIZE];
440         int len = STUN_MAX_MESSAGE_SIZE;
441         StunMessage resp;
442         len=recv(sock,buf,len,0);
443         if (len>0){
444                 struct in_addr ia;
445                 stunParseMessage(buf,len, &resp );
446                 *id=resp.msgHdr.tr_id.octet[0];
447                 if (resp.hasXorMappedAddress){
448                         *port = resp.xorMappedAddress.ipv4.port;
449                         ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
450                 }else if (resp.hasMappedAddress){
451                         *port = resp.mappedAddress.ipv4.port;
452                         ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
453                 }else return -1;
454                 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
455         }
456         return len;
457 }
458
459 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
460         const char *server=linphone_core_get_stun_server(lc);
461
462         if (lc->sip_conf.ipv6_enabled){
463                 ms_warning("stun support is not implemented for ipv6");
464                 return;
465         }
466         if (server!=NULL){
467                 struct sockaddr_storage ss;
468                 socklen_t ss_len;
469                 ortp_socket_t sock1=-1, sock2=-1;
470                 int loops=0;
471                 bool_t video_enabled=linphone_core_video_enabled(lc);
472                 bool_t got_audio,got_video;
473                 bool_t cone_audio=FALSE,cone_video=FALSE;
474                 struct timeval init,cur;
475                 SalEndpointCandidate *ac,*vc;
476                 
477                 ac=&call->localdesc->streams[0].candidates[0];
478                 vc=&call->localdesc->streams[1].candidates[0];
479                 
480                 if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
481                         ms_error("Fail to parser stun server address: %s",server);
482                         return;
483                 }
484                 if (lc->vtable.display_status!=NULL)
485                         lc->vtable.display_status(lc,_("Stun lookup in progress..."));
486
487                 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
488                 sock1=create_socket(call->audio_port);
489                 if (sock1==-1) return;
490                 if (video_enabled){
491                         sock2=create_socket(call->video_port);
492                         if (sock2==-1) return ;
493                 }
494                 got_audio=FALSE;
495                 got_video=FALSE;
496                 gettimeofday(&init,NULL);
497                 do{
498                         double elapsed;
499                         int id;
500                         if (loops%20==0){
501                                 ms_message("Sending stun requests...");
502                                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
503                                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
504                                 if (sock2!=-1){
505                                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
506                                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
507                                 }
508                         }
509 #ifdef WIN32
510                         Sleep(10);
511 #else
512                         usleep(10000);
513 #endif
514
515                         if (recvStunResponse(sock1,ac->addr,
516                                                 &ac->port,&id)>0){
517                                 ms_message("STUN test result: local audio port maps to %s:%i",
518                                                 ac->addr,
519                                                 ac->port);
520                                 if (id==11)
521                                         cone_audio=TRUE;
522                                 got_audio=TRUE;
523                         }
524                         if (recvStunResponse(sock2,vc->addr,
525                                                         &vc->port,&id)>0){
526                                 ms_message("STUN test result: local video port maps to %s:%i",
527                                         vc->addr,
528                                         vc->port);
529                                 if (id==22)
530                                         cone_video=TRUE;
531                                 got_video=TRUE;
532                         }
533                         gettimeofday(&cur,NULL);
534                         elapsed=((cur.tv_sec-init.tv_sec)*1000.0) +  ((cur.tv_usec-init.tv_usec)/1000.0);
535                         if (elapsed>2000)  {
536                                 ms_message("Stun responses timeout, going ahead.");
537                                 break;
538                         }
539                         loops++;
540                 }while(!(got_audio && (got_video||sock2==-1)  ) );
541                 if (!got_audio){
542                         ms_error("No stun server response for audio port.");
543                 }else{
544                         if (!cone_audio) {
545                                 ms_message("NAT is symmetric for audio port");
546                         }
547                 }
548                 if (sock2!=-1){
549                         if (!got_video){
550                                 ms_error("No stun server response for video port.");
551                         }else{
552                                 if (!cone_video) {
553                                         ms_message("NAT is symmetric for video port.");
554                                 }
555                         }
556                 }
557                 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
558                     || sock2==-1){
559                         strcpy(call->localdesc->addr,ac->addr);
560                 }
561                 close_socket(sock1);
562                 if (sock2!=-1) close_socket(sock2);
563         }
564 }
565
566 int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
567 {
568         char local_addr[64];
569         struct sockaddr_storage ss;
570         socklen_t ss_len;
571         IceCheckList *audio_check_list;
572         IceCheckList *video_check_list;
573         const char *server = linphone_core_get_stun_server(lc);
574
575         if ((server == NULL) || (call->ice_session == NULL)) return -1;
576         audio_check_list = ice_session_check_list(call->ice_session, 0);
577         video_check_list = ice_session_check_list(call->ice_session, 1);
578         if (audio_check_list == NULL) return -1;
579
580         if (lc->sip_conf.ipv6_enabled){
581                 ms_warning("stun support is not implemented for ipv6");
582                 return -1;
583         }
584
585         if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) {
586                 ms_error("Fail to parser stun server address: %s", server);
587                 return -1;
588         }
589         if (lc->vtable.display_status != NULL)
590                 lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
591
592         /* Gather local host candidates. */
593         if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
594                 ms_error("Fail to get local ip");
595                 return -1;
596         }
597         ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
598         ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
599         if (call->params.has_video && (video_check_list != NULL)) {
600                 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
601                 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
602         }
603
604         /* Gather local srflx candidates. */
605         ice_session_gather_candidates(call->ice_session, ss, ss_len);
606         return 0;
607 }
608
609 void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
610 {
611         const char *rtp_addr, *rtcp_addr;
612         IceSessionState session_state = ice_session_state(session);
613         int nb_candidates;
614         int i, j;
615         bool_t result;
616
617         if (session_state == IS_Completed) {
618                 desc->ice_completed = TRUE;
619                 ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
620                 strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
621         }
622         else {
623                 desc->ice_completed = FALSE;
624         }
625         strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
626         strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
627         for (i = 0; i < desc->nstreams; i++) {
628                 SalStreamDescription *stream = &desc->streams[i];
629                 IceCheckList *cl = ice_session_check_list(session, i);
630                 nb_candidates = 0;
631                 if (cl == NULL) continue;
632                 if (ice_check_list_state(cl) == ICL_Completed) {
633                         stream->ice_completed = TRUE;
634                         result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
635                 } else {
636                         stream->ice_completed = FALSE;
637                         result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
638                 }
639                 if (result == TRUE) {
640                         strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr));
641                         strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr));
642                 } else {
643                         memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr));
644                         memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr));
645                 }
646                 if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd)))
647                         strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd));
648                 else
649                         memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
650                 if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag)))
651                         strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag));
652                 else
653                         memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
654                 stream->ice_mismatch = ice_check_list_is_mismatch(cl);
655                 if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) {
656                         memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates));
657                         for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) {
658                                 SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates];
659                                 IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j);
660                                 const char *default_addr = NULL;
661                                 int default_port = 0;
662                                 if (ice_candidate->componentID == 1) {
663                                         default_addr = stream->rtp_addr;
664                                         default_port = stream->rtp_port;
665                                 } else if (ice_candidate->componentID == 2) {
666                                         default_addr = stream->rtcp_addr;
667                                         default_port = stream->rtcp_port;
668                                 } else continue;
669                                 if (default_addr[0] == '\0') default_addr = desc->addr;
670                                 /* 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. */
671                                 if ((ice_check_list_state(cl) == ICL_Completed)
672                                         && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0)))
673                                         continue;
674                                 strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation));
675                                 sal_candidate->componentID = ice_candidate->componentID;
676                                 sal_candidate->priority = ice_candidate->priority;
677                                 strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type));
678                                 strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr));
679                                 sal_candidate->port = ice_candidate->taddr.port;
680                                 if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) {
681                                         strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr));
682                                         sal_candidate->rport = ice_candidate->base->taddr.port;
683                                 }
684                                 nb_candidates++;
685                         }
686                 }
687                 if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
688                         int rtp_port, rtcp_port;
689                         memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
690                         ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
691                         strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
692                         stream->ice_remote_candidates[0].port = rtp_port;
693                         strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
694                         stream->ice_remote_candidates[1].port = rtcp_port;
695                 }
696         }
697 }
698
699 static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port)
700 {
701         if (componentID == 1) {
702                 *addr = stream->rtp_addr;
703                 *port = stream->rtp_port;
704         } else if (componentID == 2) {
705                 *addr = stream->rtcp_addr;
706                 *port = stream->rtcp_port;
707         } else return;
708         if ((*addr)[0] == '\0') *addr = md->addr;
709 }
710
711 void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
712 {
713         bool_t ice_restarted = FALSE;
714
715         if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) {
716                 int i, j;
717
718                 /* Check for ICE restart and set remote credentials. */
719                 if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) {
720                         ice_session_restart(call->ice_session);
721                         ice_restarted = TRUE;
722                 } else {
723                         for (i = 0; i < md->nstreams; i++) {
724                                 const SalStreamDescription *stream = &md->streams[i];
725                                 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
726                                 if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
727                                         ice_session_restart(call->ice_session);
728                                         ice_restarted = TRUE;
729                                         break;
730                                 }
731                         }
732                 }
733                 if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) {
734                         ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
735                 } else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) {
736                         if (ice_restarted == FALSE) {
737                                 ice_session_restart(call->ice_session);
738                                 ice_restarted = TRUE;
739                         }
740                         ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
741                 }
742                 for (i = 0; i < md->nstreams; i++) {
743                         const SalStreamDescription *stream = &md->streams[i];
744                         IceCheckList *cl = ice_session_check_list(call->ice_session, i);
745                         if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
746                                 if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) {
747                                         if (ice_restarted == FALSE) {
748                                                 ice_session_restart(call->ice_session);
749                                                 ice_restarted = TRUE;
750                                         }
751                                         ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
752                                         break;
753                                 }
754                         }
755                 }
756
757                 /* Create ICE check lists if needed and parse ICE attributes. */
758                 for (i = 0; i < md->nstreams; i++) {
759                         const SalStreamDescription *stream = &md->streams[i];
760                         IceCheckList *cl = ice_session_check_list(call->ice_session, i);
761                         if (cl == NULL) {
762                                 cl = ice_check_list_new();
763                                 ice_session_add_check_list(call->ice_session, cl);
764                                 switch (stream->type) {
765                                         case SalAudio:
766                                                 if (call->audiostream != NULL) call->audiostream->ice_check_list = cl;
767                                                 break;
768                                         case SalVideo:
769                                                 if (call->videostream != NULL) call->videostream->ice_check_list = cl;
770                                                 break;
771                                         default:
772                                                 break;
773                                 }
774                         }
775                         if ((stream->ice_mismatch == TRUE) || (stream->rtp_port == 0)) {
776                                 ice_check_list_set_state(cl, ICL_Failed);
777                         } else {
778                                 if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
779                                         ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
780                                 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
781                                         const SalIceCandidate *candidate = &stream->ice_candidates[j];
782                                         bool_t default_candidate = FALSE;
783                                         const char *addr = NULL;
784                                         int port = 0;
785                                         if (candidate->addr[0] == '\0') break;
786                                         if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue;
787                                         get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port);
788                                         if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
789                                                 default_candidate = TRUE;
790                                         ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID,
791                                                 candidate->priority, candidate->foundation, default_candidate);
792                                 }
793                                 if (ice_restarted == FALSE) {
794                                         bool_t losing_pairs_added = FALSE;
795                                         for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
796                                                 const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j];
797                                                 const char *addr = NULL;
798                                                 int port = 0;
799                                                 int componentID = j + 1;
800                                                 if (candidate->addr[0] == '\0') break;
801                                                 get_default_addr_and_port(componentID, md, stream, &addr, &port);
802                                                 ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port);
803                                                 losing_pairs_added = TRUE;
804                                         }
805                                         if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl);
806                                 }
807                         }
808                 }
809                 for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) {
810                         ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
811                 }
812                 ice_session_check_mismatch(call->ice_session);
813         }
814         if (ice_session_nb_check_lists(call->ice_session) == 0) {
815                 linphone_call_delete_ice_session(call);
816         }
817 }
818
819 void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md)
820 {
821         int i;
822         for (i = 0; i < md->nstreams; i++) {
823                 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
824                 if (cl && (md->streams[i].rtp_port == 0)) {
825                         if (ice_check_list_state(cl) != ICL_Completed) ice_check_list_set_state(cl, ICL_Failed);
826                 }
827         }
828 }
829
830 LinphoneCall * is_a_linphone_call(void *user_pointer){
831         LinphoneCall *call=(LinphoneCall*)user_pointer;
832         if (call==NULL) return NULL;
833         return call->magic==linphone_call_magic ? call : NULL;
834 }
835
836 LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer){
837         LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)user_pointer;
838         if (cfg==NULL) return NULL;
839         return cfg->magic==linphone_proxy_config_magic ? cfg : NULL;
840 }
841
842 unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
843         unsigned int ret=0;
844         const char *features=lp_config_get_string(lc->config,"sound","features",NULL);
845         if (features){
846                 char tmp[256]={0};
847                 char name[256];
848                 char *p,*n;
849                 strncpy(tmp,features,sizeof(tmp)-1);
850                 for(p=tmp;*p!='\0';p++){
851                         if (*p==' ') continue;
852                         n=strchr(p,'|');
853                         if (n) *n='\0';
854                         sscanf(p,"%s",name);
855                         ms_message("Found audio feature %s",name);
856                         if (strcasecmp(name,"PLC")==0) ret|=AUDIO_STREAM_FEATURE_PLC;
857                         else if (strcasecmp(name,"EC")==0) ret|=AUDIO_STREAM_FEATURE_EC;
858                         else if (strcasecmp(name,"EQUALIZER")==0) ret|=AUDIO_STREAM_FEATURE_EQUALIZER;
859                         else if (strcasecmp(name,"VOL_SND")==0) ret|=AUDIO_STREAM_FEATURE_VOL_SND;
860                         else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV;
861                         else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF;
862                         else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO;
863                         else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL;
864                         else if (strcasecmp(name,"NONE")==0) ret=0;
865                         else ms_error("Unsupported audio feature %s requested in config file.",name);
866                         if (!n) break;
867                         p=n;
868                 }
869         }else ret=AUDIO_STREAM_FEATURE_ALL;
870         return ret;
871 }
872
873
874 #ifdef HAVE_GETIFADDRS
875
876 #include <ifaddrs.h>
877 static int get_local_ip_with_getifaddrs(int type, char *address, int size)
878 {
879         struct ifaddrs *ifp;
880         struct ifaddrs *ifpstart;
881         int ret = 0;
882
883         if (getifaddrs(&ifpstart) < 0) {
884                 return -1;
885         }
886
887         for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
888                 if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
889                         && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
890                 {
891                         getnameinfo(ifp->ifa_addr,
892                                                 (type == AF_INET6) ?
893                                                 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
894                                                 address, size, NULL, 0, NI_NUMERICHOST);
895                         if (strchr(address, '%') == NULL) {     /*avoid ipv6 link-local addresses */
896                                 /*ms_message("getifaddrs() found %s",address);*/
897                                 ret++;
898                                 break;
899                         }
900                 }
901         }
902         freeifaddrs(ifpstart);
903         return ret;
904 }
905 #endif
906
907
908 static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
909         int err,tmp;
910         struct addrinfo hints;
911         struct addrinfo *res=NULL;
912         struct sockaddr_storage addr;
913         struct sockaddr *p_addr=(struct sockaddr*)&addr;
914         ortp_socket_t sock;
915         socklen_t s;
916
917         memset(&hints,0,sizeof(hints));
918         hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
919         hints.ai_socktype=SOCK_DGRAM;
920         /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
921         err=getaddrinfo(dest,"5060",&hints,&res);
922         if (err!=0){
923                 ms_error("getaddrinfo() error: %s",gai_strerror(err));
924                 return -1;
925         }
926         if (res==NULL){
927                 ms_error("bug: getaddrinfo returned nothing.");
928                 return -1;
929         }
930         sock=socket(res->ai_family,SOCK_DGRAM,0);
931         tmp=1;
932         err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
933         if (err<0){
934                 ms_warning("Error in setsockopt: %s",strerror(errno));
935         }
936         err=connect(sock,res->ai_addr,res->ai_addrlen);
937         if (err<0) {
938                 ms_error("Error in connect: %s",strerror(errno));
939                 freeaddrinfo(res);
940                 close_socket(sock);
941                 return -1;
942         }
943         freeaddrinfo(res);
944         res=NULL;
945         s=sizeof(addr);
946         err=getsockname(sock,(struct sockaddr*)&addr,&s);
947         if (err!=0) {
948                 ms_error("Error in getsockname: %s",strerror(errno));
949                 close_socket(sock);
950                 return -1;
951         }
952         if (p_addr->sa_family==AF_INET){
953                 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
954                 if (p_sin->sin_addr.s_addr==0){
955                         close_socket(sock);
956                         return -1;
957                 }
958         }
959         err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
960         if (err!=0){
961                 ms_error("getnameinfo error: %s",strerror(errno));
962         }
963         close_socket(sock);
964         ms_message("Local interface to reach %s is %s.",dest,result);
965         return 0;
966 }
967
968 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
969         strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
970 #ifdef HAVE_GETIFADDRS
971         if (dest==NULL) {
972                 /*we use getifaddrs for lookup of default interface */
973                 int found_ifs;
974         
975                 found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
976                 if (found_ifs==1){
977                         return 0;
978                 }else if (found_ifs<=0){
979                         /*absolutely no network on this machine */
980                         return -1;
981                 }
982         }
983 #endif
984         /*else use connect to find the best local ip address */
985         if (type==AF_INET)
986                 dest="87.98.157.38"; /*a public IP address*/
987         else dest="2a00:1450:8002::68";
988         return get_local_ip_for_with_connect(type,dest,result);
989 }
990
991 #ifndef WIN32
992 #include <resolv.h>
993
994
995
996 void _linphone_core_configure_resolver(){
997 /*bionic declares _res but does not define nor export it !!*/
998 #ifdef ANDROID
999         /*timeout and attempts are the same as retrans and retry, but are android specific names.*/
1000         setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1);
1001 #else
1002         res_init();
1003         _res.retrans=2; /*retransmit every two seconds*/
1004         _res.retry=2; /*only two times per DNS server*/
1005 #endif
1006 }
1007
1008 #else
1009
1010 void _linphone_core_configure_resolver(){
1011 }
1012
1013 #endif