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