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