]> sjero.net Git - linphone/blob - coreapi/misc.c
avoid prompting password for ping (OPTIONS) requests
[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(PayloadType *pt) {
185         return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
186 }
187
188 bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt){
189         if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,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                 return 0;
200         }
201         ms_error("Enabling codec not in audio or video list of PayloadType !");
202         return -1;
203 }
204
205 const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
206         if (ms_filter_codec_supported(pt->mime_type)){
207                 MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
208 #ifdef ENABLE_NLS
209                 return dgettext("mediastreamer",desc->text);
210 #else
211                 return desc->text;
212 #endif
213         }
214         return NULL;
215 }
216
217
218 /*this function makes a special case for speex/8000.
219 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
220 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
221 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
222         int upload_bw=linphone_core_get_upload_bandwidth(lc);
223         if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
224                 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
225                         return 15000;
226                 }
227         }
228         return pt->normal_bitrate;
229 }
230
231 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
232         double npacket=50;
233         double packet_size;
234         int bitrate;
235         bitrate=get_codec_bitrate(lc,pt);
236         packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
237         return packet_size*8.0*npacket;
238 }
239
240 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){
241         call->audio_bw=(int)(get_audio_payload_bandwidth(call->core,pt)/1000.0);
242         ms_message("Audio bandwidth for this call is %i",call->audio_bw);
243 }
244
245 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
246         const MSList *elem;
247         PayloadType *max=NULL;
248         for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
249                 PayloadType *pt=(PayloadType*)elem->data;
250                 if (payload_type_enabled(pt)){
251                         int pt_bitrate=get_codec_bitrate(lc,pt);
252                         if (max==NULL) max=pt;
253                         else if (max->normal_bitrate<pt_bitrate){
254                                 max=pt;
255                         }
256                 }
257         }
258         if (max) {
259                 lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0);
260         }
261 }
262
263 bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt,  int bandwidth_limit)
264 {
265         double codec_band;
266         bool_t ret=FALSE;
267         
268         switch (pt->type){
269                 case PAYLOAD_AUDIO_CONTINUOUS:
270                 case PAYLOAD_AUDIO_PACKETIZED:
271                         codec_band=get_audio_payload_bandwidth(lc,pt);
272                         ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
273                         /*hack to avoid using uwb codecs when having low bitrate and video*/
274                         if (bandwidth_is_greater(199,bandwidth_limit)){
275                                 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
276                                         ret=FALSE;
277                                 }
278                         }
279                         //ms_message("Payload %s: %g",pt->mime_type,codec_band);
280                         break;
281                 case PAYLOAD_VIDEO:
282                         if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/
283                                 ret=TRUE;
284                         }
285                         else ret=FALSE;
286                         break;
287         }
288         return ret;
289 }
290
291 /* return TRUE if codec can be used with bandwidth, FALSE else*/
292 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
293 {
294         double codec_band;
295         int allowed_bw,video_bw;
296         bool_t ret=FALSE;
297
298         linphone_core_update_allocated_audio_bandwidth(lc);
299         allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
300                                         linphone_core_get_upload_bandwidth(lc));
301         if (allowed_bw==0) {
302                 allowed_bw=-1;
303                 video_bw=1500; /*around 1.5 Mbit/s*/
304         }else
305                 video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw);
306
307         switch (pt->type){
308                 case PAYLOAD_AUDIO_CONTINUOUS:
309                 case PAYLOAD_AUDIO_PACKETIZED:
310                         codec_band=get_audio_payload_bandwidth(lc,pt);
311                         ret=bandwidth_is_greater(allowed_bw*1000,codec_band);
312                         /*hack to avoid using uwb codecs when having low bitrate and video*/
313                         if (bandwidth_is_greater(199,allowed_bw)){
314                                 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
315                                         ret=FALSE;
316                                 }
317                         }
318                         //ms_message("Payload %s: %g",pt->mime_type,codec_band);
319                         break;
320                 case PAYLOAD_VIDEO:
321                         if (video_bw>0){
322                                 pt->normal_bitrate=video_bw*1000;
323                                 ret=TRUE;
324                         }
325                         else ret=FALSE;
326                         break;
327         }
328         return ret;
329 }
330
331 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
332 #if !defined(_WIN32_WCE)
333         FILE *f=popen(command,"r");
334         if (f!=NULL){
335                 int err;
336                 *result=ms_malloc(4096);
337                 err=fread(*result,1,4096-1,f);
338                 if (err<0){
339                         ms_warning("Error reading command output:%s",strerror(errno));
340                         ms_free(result);
341                         return FALSE;
342                 }
343                 (*result)[err]=0;
344                 err=pclose(f);
345                 if (command_ret!=NULL) *command_ret=err;
346                 return TRUE;
347         }
348 #endif /*_WIN32_WCE*/
349         return FALSE;
350 }
351
352 static ortp_socket_t create_socket(int local_port){
353         struct sockaddr_in laddr;
354         ortp_socket_t sock;
355         int optval;
356         sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
357         if (sock<0) {
358                 ms_error("Fail to create socket");
359                 return -1;
360         }
361         memset (&laddr,0,sizeof(laddr));
362         laddr.sin_family=AF_INET;
363         laddr.sin_addr.s_addr=INADDR_ANY;
364         laddr.sin_port=htons(local_port);
365         if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
366                 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
367                 close_socket(sock);
368                 return -1;
369         }
370         optval=1;
371         if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
372                                 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
373                 ms_warning("Fail to set SO_REUSEADDR");
374         }
375         set_non_blocking_socket(sock);
376         return sock;
377 }
378
379 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
380         char buf[STUN_MAX_MESSAGE_SIZE];
381         int len = STUN_MAX_MESSAGE_SIZE;
382         StunAtrString username;
383         StunAtrString password;
384         StunMessage req;
385         int err;
386         memset(&req, 0, sizeof(StunMessage));
387         memset(&username,0,sizeof(username));
388         memset(&password,0,sizeof(password));
389         stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
390         len = stunEncodeMessage( &req, buf, len, &password);
391         if (len<=0){
392                 ms_error("Fail to encode stun message.");
393                 return -1;
394         }
395         err=sendto(sock,buf,len,0,server,addrlen);
396         if (err<0){
397                 ms_error("sendto failed: %s",strerror(errno));
398                 return -1;
399         }
400         return 0;
401 }
402
403 int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
404         struct addrinfo hints,*res=NULL;
405         int ret;
406         const char *port;
407         char host[NI_MAXHOST];
408         char *p;
409         host[NI_MAXHOST-1]='\0';
410         strncpy(host,server,sizeof(host)-1);
411         p=strchr(host,':');
412         if (p) {
413                 *p='\0';
414                 port=p+1;
415         }else port="3478";
416         memset(&hints,0,sizeof(hints));
417         hints.ai_family=PF_INET;
418         hints.ai_socktype=SOCK_DGRAM;
419         hints.ai_protocol=IPPROTO_UDP;
420         ret=getaddrinfo(host,port,&hints,&res);
421         if (ret!=0){
422                 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
423                 return -1;
424         }
425         if (!res) return -1;
426         memcpy(ss,res->ai_addr,res->ai_addrlen);
427         *socklen=res->ai_addrlen;
428         freeaddrinfo(res);
429         return 0;
430 }
431
432 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
433         char buf[STUN_MAX_MESSAGE_SIZE];
434         int len = STUN_MAX_MESSAGE_SIZE;
435         StunMessage resp;
436         len=recv(sock,buf,len,0);
437         if (len>0){
438                 struct in_addr ia;
439                 stunParseMessage(buf,len, &resp );
440                 *id=resp.msgHdr.tr_id.octet[0];
441                 if (resp.hasXorMappedAddress){
442                         *port = resp.xorMappedAddress.ipv4.port;
443                         ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
444                 }else if (resp.hasMappedAddress){
445                         *port = resp.mappedAddress.ipv4.port;
446                         ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
447                 }else return -1;
448                 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
449         }
450         return len;
451 }
452
453 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
454         const char *server=linphone_core_get_stun_server(lc);
455
456         if (lc->sip_conf.ipv6_enabled){
457                 ms_warning("stun support is not implemented for ipv6");
458                 return;
459         }
460         if (server!=NULL){
461                 struct sockaddr_storage ss;
462                 socklen_t ss_len;
463                 ortp_socket_t sock1=-1, sock2=-1;
464                 int loops=0;
465                 bool_t video_enabled=linphone_core_video_enabled(lc);
466                 bool_t got_audio,got_video;
467                 bool_t cone_audio=FALSE,cone_video=FALSE;
468                 struct timeval init,cur;
469                 SalEndpointCandidate *ac,*vc;
470                 
471                 ac=&call->localdesc->streams[0].candidates[0];
472                 vc=&call->localdesc->streams[1].candidates[0];
473                 
474                 if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
475                         ms_error("Fail to parser stun server address: %s",server);
476                         return;
477                 }
478                 if (lc->vtable.display_status!=NULL)
479                         lc->vtable.display_status(lc,_("Stun lookup in progress..."));
480
481                 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
482                 sock1=create_socket(call->audio_port);
483                 if (sock1==-1) return;
484                 if (video_enabled){
485                         sock2=create_socket(call->video_port);
486                         if (sock2==-1) return ;
487                 }
488                 got_audio=FALSE;
489                 got_video=FALSE;
490                 gettimeofday(&init,NULL);
491                 do{
492                         double elapsed;
493                         int id;
494                         if (loops%20==0){
495                                 ms_message("Sending stun requests...");
496                                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
497                                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
498                                 if (sock2!=-1){
499                                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
500                                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
501                                 }
502                         }
503 #ifdef WIN32
504                         Sleep(10);
505 #else
506                         usleep(10000);
507 #endif
508
509                         if (recvStunResponse(sock1,ac->addr,
510                                                 &ac->port,&id)>0){
511                                 ms_message("STUN test result: local audio port maps to %s:%i",
512                                                 ac->addr,
513                                                 ac->port);
514                                 if (id==11)
515                                         cone_audio=TRUE;
516                                 got_audio=TRUE;
517                         }
518                         if (recvStunResponse(sock2,vc->addr,
519                                                         &vc->port,&id)>0){
520                                 ms_message("STUN test result: local video port maps to %s:%i",
521                                         vc->addr,
522                                         vc->port);
523                                 if (id==22)
524                                         cone_video=TRUE;
525                                 got_video=TRUE;
526                         }
527                         gettimeofday(&cur,NULL);
528                         elapsed=((cur.tv_sec-init.tv_sec)*1000.0) +  ((cur.tv_usec-init.tv_usec)/1000.0);
529                         if (elapsed>2000)  {
530                                 ms_message("Stun responses timeout, going ahead.");
531                                 break;
532                         }
533                         loops++;
534                 }while(!(got_audio && (got_video||sock2==-1)  ) );
535                 if (!got_audio){
536                         ms_error("No stun server response for audio port.");
537                 }else{
538                         if (!cone_audio) {
539                                 ms_message("NAT is symmetric for audio port");
540                         }
541                 }
542                 if (sock2!=-1){
543                         if (!got_video){
544                                 ms_error("No stun server response for video port.");
545                         }else{
546                                 if (!cone_video) {
547                                         ms_message("NAT is symmetric for video port.");
548                                 }
549                         }
550                 }
551                 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
552                     || sock2==-1){
553                         strcpy(call->localdesc->addr,ac->addr);
554                 }
555                 close_socket(sock1);
556                 if (sock2!=-1) close_socket(sock2);
557         }
558 }
559
560 LinphoneCall * is_a_linphone_call(void *user_pointer){
561         LinphoneCall *call=(LinphoneCall*)user_pointer;
562         if (call==NULL) return NULL;
563         return call->magic==linphone_call_magic ? call : NULL;
564 }
565
566 LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer){
567         LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)user_pointer;
568         if (cfg==NULL) return NULL;
569         return cfg->magic==linphone_proxy_config_magic ? cfg : NULL;
570 }
571
572
573 #ifdef HAVE_GETIFADDRS
574
575 #include <ifaddrs.h>
576 static int get_local_ip_with_getifaddrs(int type, char *address, int size)
577 {
578         struct ifaddrs *ifp;
579         struct ifaddrs *ifpstart;
580         int ret = 0;
581
582         if (getifaddrs(&ifpstart) < 0) {
583                 return -1;
584         }
585
586         for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
587                 if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
588                         && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
589                 {
590                         getnameinfo(ifp->ifa_addr,
591                                                 (type == AF_INET6) ?
592                                                 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
593                                                 address, size, NULL, 0, NI_NUMERICHOST);
594                         if (strchr(address, '%') == NULL) {     /*avoid ipv6 link-local addresses */
595                                 /*ms_message("getifaddrs() found %s",address);*/
596                                 ret++;
597                                 break;
598                         }
599                 }
600         }
601         freeifaddrs(ifpstart);
602         return ret;
603 }
604 #endif
605
606
607 static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
608         int err,tmp;
609         struct addrinfo hints;
610         struct addrinfo *res=NULL;
611         struct sockaddr_storage addr;
612         struct sockaddr *p_addr=(struct sockaddr*)&addr;
613         ortp_socket_t sock;
614         socklen_t s;
615
616         memset(&hints,0,sizeof(hints));
617         hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
618         hints.ai_socktype=SOCK_DGRAM;
619         /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
620         err=getaddrinfo(dest,"5060",&hints,&res);
621         if (err!=0){
622                 ms_error("getaddrinfo() error: %s",gai_strerror(err));
623                 return -1;
624         }
625         if (res==NULL){
626                 ms_error("bug: getaddrinfo returned nothing.");
627                 return -1;
628         }
629         sock=socket(res->ai_family,SOCK_DGRAM,0);
630         tmp=1;
631         err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
632         if (err<0){
633                 ms_warning("Error in setsockopt: %s",strerror(errno));
634         }
635         err=connect(sock,res->ai_addr,res->ai_addrlen);
636         if (err<0) {
637                 ms_error("Error in connect: %s",strerror(errno));
638                 freeaddrinfo(res);
639                 close_socket(sock);
640                 return -1;
641         }
642         freeaddrinfo(res);
643         res=NULL;
644         s=sizeof(addr);
645         err=getsockname(sock,(struct sockaddr*)&addr,&s);
646         if (err!=0) {
647                 ms_error("Error in getsockname: %s",strerror(errno));
648                 close_socket(sock);
649                 return -1;
650         }
651         if (p_addr->sa_family==AF_INET){
652                 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
653                 if (p_sin->sin_addr.s_addr==0){
654                         close_socket(sock);
655                         return -1;
656                 }
657         }
658         err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
659         if (err!=0){
660                 ms_error("getnameinfo error: %s",strerror(errno));
661         }
662         close_socket(sock);
663         ms_message("Local interface to reach %s is %s.",dest,result);
664         return 0;
665 }
666
667 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
668         strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
669 #ifdef HAVE_GETIFADDRS
670         if (dest==NULL) {
671                 /*we use getifaddrs for lookup of default interface */
672                 int found_ifs;
673         
674                 found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
675                 if (found_ifs==1){
676                         return 0;
677                 }else if (found_ifs<=0){
678                         /*absolutely no network on this machine */
679                         return -1;
680                 }
681         }
682 #endif
683         /*else use connect to find the best local ip address */
684         if (type==AF_INET)
685                 dest="87.98.157.38"; /*a public IP address*/
686         else dest="2a00:1450:8002::68";
687         return get_local_ip_for_with_connect(type,dest,result);
688 }
689
690 #ifndef WIN32
691 #include <resolv.h>
692
693
694
695
696 void _linphone_core_configure_resolver(){
697 /*bionic declares _res but does not define nor export it !!*/
698 #ifdef ANDROID
699         /*timeout and attempts are the same as retrans and retry, but are android specific names.*/
700         setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1);
701 #else
702         res_init();
703         _res.retrans=2; /*retransmit every two seconds*/
704         _res.retry=2; /*only two times per DNS server*/
705 #endif
706 }
707
708 #else
709
710 void _linphone_core_configure_resolver(){
711 }
712
713 #endif