]> sjero.net Git - linphone/blob - linphone/coreapi/misc.c
remove mediastreamer2 and add it as a submodule instead.
[linphone] / 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
42 #if !defined(WIN32)
43
44 static char lock_name[80];
45 static char lock_set=0;
46 /* put a lock file in /tmp. this is called when linphone runs as a daemon*/
47 int set_lock_file()
48 {
49         FILE *lockfile;
50
51         snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
52         lockfile=fopen(lock_name,"w");
53         if (lockfile==NULL)
54         {
55                 printf("Failed to create lock file.\n");
56                 return(-1);
57         }
58         fprintf(lockfile,"%i",getpid());
59         fclose(lockfile);
60         lock_set=1;
61         return(0);
62 }
63
64 /* looks if there is a lock file. If presents return its content (the pid of the already running linphone), if not found, returns -1*/
65 int get_lock_file()
66 {
67         int pid;
68         FILE *lockfile;
69
70         snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
71         lockfile=fopen(lock_name,"r");
72         if (lockfile==NULL)
73                 return(-1);
74         if (fscanf(lockfile,"%i",&pid)!=1){
75                 ms_warning("Could not read pid in lock file.");
76                 fclose(lockfile);
77                 return -1;
78         }
79         fclose(lockfile);
80         return pid;
81 }
82
83 /* remove the lock file if it was set*/
84 int remove_lock_file()
85 {
86         int err=0;
87         if (lock_set)
88         {
89                 err=unlink(lock_name);
90                 lock_set=0;
91         }
92         return(err);
93 }
94
95 #endif
96
97 char *int2str(int number)
98 {
99         char *numstr=ms_malloc(10);
100         snprintf(numstr,10,"%i",number);
101         return numstr;
102 }
103
104 void check_sound_device(LinphoneCore *lc)
105 {
106 #ifdef _linux
107         int fd=0;
108         int len;
109         int a;
110         char *file=NULL;
111         char *i810_audio=NULL;
112         char *snd_pcm_oss=NULL;
113         char *snd_mixer_oss=NULL;
114         char *snd_pcm=NULL;
115         fd=open("/proc/modules",O_RDONLY);
116
117         if (fd>0){
118                 /* read the entire /proc/modules file and check if sound conf seems correct */
119                 /*a=fstat(fd,&statbuf);
120                 if (a<0) ms_warning("Can't stat /proc/modules:%s.",strerror(errno));
121                 len=statbuf.st_size;
122                 if (len==0) ms_warning("/proc/modules has zero size!");
123                 */
124                 /***** fstat does not work on /proc/modules for unknown reason *****/
125                 len=6000;
126                 file=ms_malloc(len+1);
127                 a=read(fd,file,len);
128                 if (a<len) file=ms_realloc(file,a+1);
129                 file[a]='\0';
130                 i810_audio=strstr(file,"i810_audio");
131                 if (i810_audio!=NULL){
132                         /* I'm sorry i put this warning in comments because
133                          * i don't use yet the right driver !! */
134 /*                      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."));*/
135                         goto end;
136                 }
137                 snd_pcm=strstr(file,"snd-pcm");
138                 if (snd_pcm!=NULL){
139                         snd_pcm_oss=strstr(file,"snd-pcm-oss");
140                         snd_mixer_oss=strstr(file,"snd-mixer-oss");
141                         if (snd_pcm_oss==NULL){
142                                 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."));
143                         }
144                         if (snd_mixer_oss==NULL){
145                                 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."));
146                         }
147                 }
148         }else {
149
150                 ms_warning("Could not open /proc/modules.");
151         }
152         /* now check general volume. Some user forget to rise it and then complain that linphone is
153         not working */
154         /* but some other users complain that linphone should not change levels...
155         if (lc->sound_conf.sndcard!=NULL){
156                 a=snd_card_get_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL);
157                 if (a<50){
158                         ms_warning("General level is quite low (%i). Linphone rises it up for you.",a);
159                         snd_card_set_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL,80);
160                 }
161         }
162         */
163         end:
164         if (file!=NULL) ms_free(file);
165         if (fd>0) close(fd);
166 #endif
167 }
168
169 #define UDP_HDR_SZ 8
170 #define RTP_HDR_SZ 12
171 #define IP4_HDR_SZ 20   /*20 is the minimum, but there may be some options*/
172
173 const char *payload_type_get_description(PayloadType *pt){
174         return _((const char *)pt->user_data);
175 }
176
177 void payload_type_set_enable(PayloadType *pt,int value)
178 {
179         if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \
180         else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
181 }
182
183
184 bool_t payload_type_enabled(PayloadType *pt) {
185         return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
186 }
187
188 int payload_type_get_bitrate(PayloadType *pt)
189 {
190         return pt->normal_bitrate;
191 }
192 const char *payload_type_get_mime(PayloadType *pt){
193         return pt->mime_type;
194 }
195
196 int payload_type_get_rate(PayloadType *pt){
197         return pt->clock_rate;
198 }
199
200 /*this function makes a special case for speex/8000.
201 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
202 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
203 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
204         int upload_bw=linphone_core_get_upload_bandwidth(lc);
205         if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
206                 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
207                         return 15000;
208                 }
209         }
210         return pt->normal_bitrate;
211 }
212
213 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
214         double npacket=50;
215         double packet_size;
216         int bitrate;
217         bitrate=get_codec_bitrate(lc,pt);
218         packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
219         return packet_size*8.0*npacket;
220 }
221
222 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCore *lc, const PayloadType *pt){
223         lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,pt)/1000.0);
224         /*update*/
225         linphone_core_set_download_bandwidth(lc,lc->net_conf.download_bw);
226         linphone_core_set_upload_bandwidth(lc,lc->net_conf.upload_bw);
227 }
228
229 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
230         const MSList *elem;
231         PayloadType *max=NULL;
232         for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
233                 PayloadType *pt=(PayloadType*)elem->data;
234                 if (payload_type_enabled(pt)){
235                         int pt_bitrate=get_codec_bitrate(lc,pt);
236                         if (max==NULL) max=pt;
237                         else if (max->normal_bitrate<pt_bitrate){
238                                 max=pt;
239                         }
240                 }
241         }
242         if (max) {
243                 linphone_core_update_allocated_audio_bandwidth_in_call(lc,max);
244         }
245 }
246
247 /* return TRUE if codec can be used with bandwidth, FALSE else*/
248 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
249 {
250         double codec_band;
251         int min_audio_bw;
252         int min_video_bw;
253         bool_t ret=FALSE;
254         /*
255           update allocated audio bandwidth to allocate the remaining to video.
256           This must be done outside calls, because after sdp negociation
257           the audio bandwidth is refined to the selected codec
258         */
259         if (!linphone_core_in_call(lc)) linphone_core_update_allocated_audio_bandwidth(lc);
260         min_audio_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
261                                         linphone_core_get_upload_bandwidth(lc));
262         if (min_audio_bw==0) min_audio_bw=-1;
263         min_video_bw=get_min_bandwidth(lc->dw_video_bw,lc->up_video_bw);
264
265         switch (pt->type){
266                 case PAYLOAD_AUDIO_CONTINUOUS:
267                 case PAYLOAD_AUDIO_PACKETIZED:
268                         codec_band=get_audio_payload_bandwidth(lc,pt);
269                         ret=bandwidth_is_greater(min_audio_bw*1000,codec_band);
270                         //ms_message("Payload %s: %g",pt->mime_type,codec_band);
271                         break;
272                 case PAYLOAD_VIDEO:
273                         if (min_video_bw!=0) {/* infinite (-1) or strictly positive*/
274                                 /*let the video use all the bandwidth minus the maximum bandwidth used by audio */
275                                 if (min_video_bw>0)
276                                         pt->normal_bitrate=min_video_bw*1000;
277                                 else
278                                         pt->normal_bitrate=1500000; /*around 1.5 Mbit/s*/
279                                 ret=TRUE;
280                         }
281                         else ret=FALSE;
282                         break;
283         }
284         /*if (!ret) ms_warning("Payload %s is not usable with your internet connection.",pt->mime_type);*/
285
286         return ret;
287 }
288
289 static PayloadType * find_payload(RtpProfile *prof, PayloadType *pt /*from config*/){
290         PayloadType *candidate=NULL;
291         int i;
292         PayloadType *it;
293         for(i=0;i<127;++i){
294                 it=rtp_profile_get_payload(prof,i);
295                 if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0
296                         && (pt->clock_rate==it->clock_rate || pt->clock_rate<=0)
297                         && payload_type_get_user_data(it)==NULL ){
298                         if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) ||
299                                 (pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){
300                                 /*exact match*/
301                                 return it;
302                         }else candidate=it;
303                 }
304         }
305         return candidate;
306 }
307
308 static bool_t check_h264_packmode(PayloadType *payload, MSFilterDesc *desc){
309         if (payload->recv_fmtp==NULL || strstr(payload->recv_fmtp,"packetization-mode")==0){
310                 /*this is packetization-mode=0 H264, we only support it with a multislicing
311                 enabled version of x264*/
312                 if (strstr(desc->text,"x264") && strstr(desc->text,"multislicing")==0){
313                         /*this is x264 without multisclicing*/
314                         ms_message("Disabling packetization-mode=0 H264 codec because "
315                         "of lack of multislicing support");
316                         return FALSE;
317                 }
318         }
319         return TRUE;
320 }
321
322 static MSList *fix_codec_list(RtpProfile *prof, MSList *conflist)
323 {
324         MSList *elem;
325         MSList *newlist=NULL;
326         PayloadType *payload,*confpayload;
327
328         for (elem=conflist;elem!=NULL;elem=ms_list_next(elem))
329         {
330                 confpayload=(PayloadType*)elem->data;
331                 payload=find_payload(prof,confpayload);
332                 if (payload!=NULL){
333                         if (ms_filter_codec_supported(confpayload->mime_type)){
334                                 MSFilterDesc *desc=ms_filter_get_encoder(confpayload->mime_type);
335                                 if (strcasecmp(confpayload->mime_type,"H264")==0){
336                                         if (!check_h264_packmode(confpayload,desc)){
337                                                 continue;
338                                         }
339                                 }
340                                 payload_type_set_user_data(payload,(void*)desc->text);
341                                 payload_type_set_enable(payload,payload_type_enabled(confpayload));
342                                 newlist=ms_list_append(newlist,payload);
343                         }
344                 }
345                 else{
346                         ms_warning("Cannot support %s/%i: does not exist.",confpayload->mime_type,
347                                                                 confpayload->clock_rate);
348                 }
349         }
350         return newlist;
351 }
352
353
354 void linphone_core_setup_local_rtp_profile(LinphoneCore *lc)
355 {
356         int i;
357         MSList *audiopt,*videopt;
358         PayloadType *payload;
359         bool_t prepend;
360         lc->local_profile=rtp_profile_clone_full(&av_profile);
361         /* first look at the list given by configuration file to see if
362         it is correct */
363         audiopt=fix_codec_list(lc->local_profile,lc->codecs_conf.audio_codecs);
364         videopt=fix_codec_list(lc->local_profile,lc->codecs_conf.video_codecs);
365         /* now find and add payloads that are not listed in the configuration
366         codec list */
367         for (i=0;i<127;i++)
368         {
369                 payload=rtp_profile_get_payload(lc->local_profile,i);
370                 if (payload!=NULL){
371                         if (payload_type_get_user_data(payload)!=NULL) continue;
372                         /* find a mediastreamer codec for this payload type */
373                         if (ms_filter_codec_supported(payload->mime_type)){
374                                 MSFilterDesc *desc=ms_filter_get_encoder(payload->mime_type);
375                                 ms_message("Adding new codec %s/%i",payload->mime_type,payload->clock_rate);
376                                 payload_type_set_enable(payload,1);
377                                 payload_type_set_user_data(payload,(void *)desc->text);
378                                 prepend=FALSE;
379                                 /* by default, put speex, mpeg4, or h264 on top of list*/
380                                 if (strcmp(payload->mime_type,"speex")==0)
381                                         prepend=TRUE;
382                                 else if (strcmp(payload->mime_type,"MP4V-ES")==0)
383                                         prepend=TRUE;
384                                 else if (strcasecmp(payload->mime_type,"H264")==0){
385                                         if (check_h264_packmode(payload,desc))
386                                                 prepend=TRUE;
387                                         else continue;
388                                 }
389                                 switch (payload->type){
390                                         case PAYLOAD_AUDIO_CONTINUOUS:
391                                         case PAYLOAD_AUDIO_PACKETIZED:
392                                                         if (prepend)
393                                                                 audiopt=ms_list_prepend(audiopt,(void *)payload);
394                                                         else
395                                                                 audiopt=ms_list_append(audiopt,(void *)payload);
396                                                 break;
397                                         case PAYLOAD_VIDEO:
398                                                         if (prepend)
399                                                                 videopt=ms_list_prepend(videopt,(void *)payload);
400                                                         else
401                                                                 videopt=ms_list_append(videopt,(void *)payload);
402                                                 break;
403                                         default:
404                                                 ms_error("Unsupported rtp media type.");
405                                 }
406                         }
407                 }
408         }
409         ms_list_for_each(lc->codecs_conf.audio_codecs,(void (*)(void*))payload_type_destroy);
410         ms_list_for_each(lc->codecs_conf.video_codecs,(void (*)(void *))payload_type_destroy);
411         ms_list_free(lc->codecs_conf.audio_codecs);
412         ms_list_free(lc->codecs_conf.video_codecs);
413         /* set the fixed lists instead:*/
414         lc->codecs_conf.audio_codecs=audiopt;
415         lc->codecs_conf.video_codecs=videopt;
416         linphone_core_update_allocated_audio_bandwidth(lc);
417 }
418
419 int from_2char_without_params(osip_from_t *from,char **str)
420 {
421         osip_from_t *tmpfrom=NULL;
422         osip_from_clone(from,&tmpfrom);
423         if (tmpfrom!=NULL){
424                 while(!osip_list_eol(&tmpfrom->gen_params,0)){
425                         osip_generic_param_t *param=(osip_generic_param_t*)osip_list_get(&tmpfrom->gen_params,0);
426                         osip_generic_param_free(param);
427                         osip_list_remove(&tmpfrom->gen_params,0);
428                 }
429         }else return -1;
430         osip_from_to_str(tmpfrom,str);
431         osip_from_free(tmpfrom);
432         return 0;
433 }
434
435 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
436 #if !defined(_WIN32_WCE)
437         FILE *f=popen(command,"r");
438         if (f!=NULL){
439                 int err;
440                 *result=ms_malloc(4096);
441                 err=fread(*result,1,4096-1,f);
442                 if (err<0){
443                         ms_warning("Error reading command output:%s",strerror(errno));
444                         ms_free(result);
445                         return FALSE;
446                 }
447                 (*result)[err]=0;
448                 err=pclose(f);
449                 if (command_ret!=NULL) *command_ret=err;
450                 return TRUE;
451         }
452 #endif /*_WIN32_WCE*/
453         return FALSE;
454 }
455
456 #if defined(HAVE_GETIFADDRS) && defined(INET6)
457 #include <sys/types.h>
458 #include <sys/socket.h>
459 #include <ifaddrs.h>
460 bool_t host_has_ipv6_network()
461 {
462         struct ifaddrs *ifp;
463         struct ifaddrs *ifpstart;
464         bool_t ipv6_present=FALSE;
465
466         if (getifaddrs (&ifpstart) < 0)
467         {
468                 return FALSE;
469         }
470
471         for (ifp=ifpstart; ifp != NULL; ifp = ifp->ifa_next)
472         {
473                 if (!ifp->ifa_addr)
474                   continue;
475
476                 switch (ifp->ifa_addr->sa_family) {
477                 case AF_INET:
478
479                         break;
480                 case AF_INET6:
481                     ipv6_present=TRUE;
482                         break;
483                 default:
484                         continue;
485                 }
486         }
487
488         freeifaddrs (ifpstart);
489
490         return ipv6_present;
491 }
492 #else
493
494 bool_t host_has_ipv6_network()
495 {
496         return FALSE;
497 }
498
499
500 #endif
501
502 static ortp_socket_t create_socket(int local_port){
503         struct sockaddr_in laddr;
504         ortp_socket_t sock;
505         int optval;
506         sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
507         if (sock<0) {
508                 ms_error("Fail to create socket");
509                 return -1;
510         }
511         memset (&laddr,0,sizeof(laddr));
512         laddr.sin_family=AF_INET;
513         laddr.sin_addr.s_addr=INADDR_ANY;
514         laddr.sin_port=htons(local_port);
515         if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
516                 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
517                 close_socket(sock);
518                 return -1;
519         }
520         optval=1;
521         if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
522                                 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
523                 ms_warning("Fail to set SO_REUSEADDR");
524         }
525         set_non_blocking_socket(sock);
526         return sock;
527 }
528
529 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
530         char buf[STUN_MAX_MESSAGE_SIZE];
531         int len = STUN_MAX_MESSAGE_SIZE;
532         StunAtrString username;
533         StunAtrString password;
534         StunMessage req;
535         int err;
536         memset(&req, 0, sizeof(StunMessage));
537         memset(&username,0,sizeof(username));
538         memset(&password,0,sizeof(password));
539         stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
540         len = stunEncodeMessage( &req, buf, len, &password);
541         if (len<=0){
542                 ms_error("Fail to encode stun message.");
543                 return -1;
544         }
545         err=sendto(sock,buf,len,0,server,addrlen);
546         if (err<0){
547                 ms_error("sendto failed: %s",strerror(errno));
548                 return -1;
549         }
550         return 0;
551 }
552
553 static int parse_stun_server_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
554         struct addrinfo hints,*res=NULL;
555         int ret;
556         const char *port;
557         char host[NI_MAXHOST];
558         char *p;
559         host[NI_MAXHOST-1]='\0';
560         strncpy(host,server,sizeof(host)-1);
561         p=strchr(host,':');
562         if (p) {
563                 *p='\0';
564                 port=p+1;
565         }else port="3478";
566         memset(&hints,0,sizeof(hints));
567         hints.ai_family=PF_INET;
568         hints.ai_socktype=SOCK_DGRAM;
569         hints.ai_protocol=IPPROTO_UDP;
570         ret=getaddrinfo(host,port,&hints,&res);
571         if (ret!=0){
572                 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
573                 return -1;
574         }
575         if (!res) return -1;
576         memcpy(ss,res->ai_addr,res->ai_addrlen);
577         *socklen=res->ai_addrlen;
578         freeaddrinfo(res);
579         return 0;
580 }
581
582 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
583         char buf[STUN_MAX_MESSAGE_SIZE];
584         int len = STUN_MAX_MESSAGE_SIZE;
585         StunMessage resp;
586         len=recv(sock,buf,len,0);
587         if (len>0){
588                 struct in_addr ia;
589                 stunParseMessage(buf,len, &resp );
590                 *id=resp.msgHdr.tr_id.octet[0];
591                 *port = resp.mappedAddress.ipv4.port;
592                 ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
593                 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
594         }
595         return len;
596 }
597
598 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
599         const char *server=linphone_core_get_stun_server(lc);
600
601         if (lc->sip_conf.ipv6_enabled){
602                 ms_warning("stun support is not implemented for ipv6");
603                 return;
604         }
605         if (server!=NULL){
606                 struct sockaddr_storage ss;
607                 socklen_t ss_len;
608                 ortp_socket_t sock1=-1, sock2=-1;
609                 bool_t video_enabled=linphone_core_video_enabled(lc);
610                 bool_t got_audio,got_video;
611                 bool_t cone_audio=FALSE,cone_video=FALSE;
612                 struct timeval init,cur;
613                 if (parse_stun_server_addr(server,&ss,&ss_len)<0){
614                         ms_error("Fail to parser stun server address: %s",server);
615                         return;
616                 }
617                 if (lc->vtable.display_status!=NULL)
618                         lc->vtable.display_status(lc,_("Stun lookup in progress..."));
619
620                 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
621                 sock1=create_socket(linphone_core_get_audio_port(lc));
622                 if (sock1<0) return;
623                 if (video_enabled){
624                         sock2=create_socket(linphone_core_get_video_port(lc));
625                         if (sock2<0) return ;
626                 }
627                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
628                 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
629                 if (sock2>=0){
630                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
631                         sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
632                 }
633                 got_audio=FALSE;
634                 got_video=FALSE;
635                 gettimeofday(&init,NULL);
636                 do{
637                         double elapsed;
638                         int id;
639 #ifdef WIN32
640                         Sleep(10);
641 #else
642                         usleep(10000);
643 #endif
644
645                         if (recvStunResponse(sock1,call->audio_params.natd_addr,
646                                                 &call->audio_params.natd_port,&id)>0){
647                                 ms_message("STUN test result: local audio port maps to %s:%i",
648                                                 call->audio_params.natd_addr,
649                                                 call->audio_params.natd_port);
650                                 if (id==11)
651                                         cone_audio=TRUE;
652                                 got_audio=TRUE;
653                         }
654                         if (recvStunResponse(sock2,call->video_params.natd_addr,
655                                                         &call->video_params.natd_port,&id)>0){
656                                 ms_message("STUN test result: local video port maps to %s:%i",
657                                         call->video_params.natd_addr,
658                                         call->video_params.natd_port);
659                                 if (id==22)
660                                         cone_video=TRUE;
661                                 got_video=TRUE;
662                         }
663                         gettimeofday(&cur,NULL);
664                         elapsed=((cur.tv_sec-init.tv_sec)*1000.0) +  ((cur.tv_usec-init.tv_usec)/1000.0);
665                         if (elapsed>2000)  break;
666                 }while(!(got_audio && (got_video||sock2<0)  ) );
667                 if (!got_audio){
668                         ms_error("No stun server response for audio port.");
669                 }else{
670                         if (!cone_audio) {
671                                 ms_warning("NAT is symmetric for audio port");
672                                 call->audio_params.natd_port=0;
673                         }
674                 }
675                 if (sock2>=0){
676                         if (!got_video){
677                                 ms_error("No stun server response for video port.");
678                         }else{
679                                 if (!cone_video) {
680                                         ms_warning("NAT is symmetric for video port.");
681                                         call->video_params.natd_port=0;
682                                 }
683                         }
684                 }
685                 close_socket(sock1);
686                 if (sock2>=0) close_socket(sock2);
687         }
688 }
689
690 static int extract_sip_port(const char *config){
691         char line[512];
692         char port[12];
693         int ret=-1;
694         FILE *f=fopen(config,"r");
695         if (f){
696                 while(fgets(line,sizeof(line),f)!=NULL){
697                         if (fmtp_get_value(line,"sip_port",port,sizeof(port))){
698                                 ret=atoi(port);
699                         }
700                 }
701                 fclose(f);
702         }
703         return ret;
704 }
705
706 int linphone_core_wake_up_possible_already_running_instance(
707     const char * config_file, const char * addr_to_call)
708 {
709         int port=extract_sip_port(config_file);
710         const char *wakeup="WAKEUP sip:127.0.0.1 SIP/2.0\r\n"
711                 "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n"
712                 "From: <sip:another_linphone@127.0.0.1>;tag=%u\r\n"
713                 "To:   <sip:you@127.0.0.1>\r\n"
714                 "CSeq: 1 WAKEUP\r\n"
715                 "Call-ID: %u@onsantape\r\n"
716                 "Content-length: 0\r\n\r\n";
717         const char * call = "REFER sip:127.0.0.1 SIP/2.0\r\n"
718                 "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n"
719                 "From: <sip:another_linphone@127.0.0.1>;tag=%u\r\n"
720                 "To:   <sip:you@127.0.0.1>\r\n"
721                 "Refer-To: %s\r\n"
722                 "CSeq: 1 WAKEUP\r\n"
723                 "Call-ID: %u@onsantape\r\n"
724                 "Content-length: 0\r\n\r\n";
725
726         /*make sure ortp is initialized (it initializes win32 socket api)*/
727         ortp_init();
728         if (port>0){
729                 struct sockaddr_storage ss;
730                 socklen_t sslen;
731                 char tmp[100];
732                 snprintf(tmp,sizeof(tmp),"127.0.0.1:%i",port);
733                 if (parse_stun_server_addr(tmp,&ss,&sslen)==0){
734                         int locport=57123;
735                         ortp_socket_t sock=create_socket(locport);
736                         if (sock<0) sock=create_socket(++locport);
737                         if (sock>=0){
738                                 char req[512];
739                                 if (addr_to_call != NULL)
740                                         snprintf(req, sizeof(req), call, locport,
741                                         random(), random(), addr_to_call, random());
742                                 else
743                                         snprintf(req, sizeof(req), wakeup, locport,
744                                         random(), random(), random());
745                                 if (connect(sock,(struct sockaddr*)&ss,sslen)<0){
746                                         fprintf(stderr,"connect failed: %s\n",getSocketError());
747                                 }else if (send(sock,req,strlen(req),0)>0){
748                                         /*wait a bit for a response*/
749                                         int i;
750                                         for(i=0;i<10;++i){
751                                                 if (recv(sock,req,sizeof(req),0)>0){
752                                                         close_socket(sock);
753                                                         return 0;
754                                                 }else if (getSocketErrorCode()!=EWOULDBLOCK){
755                                                         break;
756                                                 }
757 #ifdef WIN32
758                                                 Sleep(100);
759 #else
760                                                 usleep(100000);
761 #endif
762                                         }
763                                 }else{
764                                         ms_message("sendto() of WAKEUP request failed, nobody to wakeup.");
765                                 }
766                         }
767                         close_socket(sock);
768                 }
769         }
770         return -1;
771 }
772
773 int linphone_core_get_local_ip_for(const char *dest, char *result){
774         int err,tmp;
775         struct addrinfo hints;
776         struct addrinfo *res=NULL;
777         struct sockaddr_storage addr;
778         struct sockaddr *p_addr=(struct sockaddr*)&addr;
779         ortp_socket_t sock;
780         socklen_t s;
781
782         memset(&hints,0,sizeof(hints));
783         hints.ai_family=PF_UNSPEC;
784         hints.ai_socktype=SOCK_DGRAM;
785         /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
786         err=getaddrinfo(dest,"5060",&hints,&res);
787         if (err!=0){
788                 ms_error("getaddrinfo() error: %s",gai_strerror(err));
789                 return -1;
790         }
791         if (res==NULL){
792                 ms_error("bug: getaddrinfo returned nothing.");
793                 return -1;
794         }
795         sock=socket(res->ai_family,SOCK_DGRAM,0);
796         tmp=1;
797         err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
798         if (err<0){
799                 ms_warning("Error in setsockopt: %s",strerror(errno));
800         }
801         err=connect(sock,res->ai_addr,res->ai_addrlen);
802         if (err<0) {
803                 ms_error("Error in connect: %s",strerror(errno));
804                 freeaddrinfo(res);
805                 close_socket(sock);
806                 return -1;
807         }
808         freeaddrinfo(res);
809         res=NULL;
810         s=sizeof(addr);
811         err=getsockname(sock,(struct sockaddr*)&addr,&s);
812         if (err!=0) {
813                 ms_error("Error in getsockname: %s",strerror(errno));
814                 close_socket(sock);
815                 return -1;
816         }
817         if (p_addr->sa_family==AF_INET){
818                 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
819                 if (p_sin->sin_addr.s_addr==0){
820                         close_socket(sock);
821                         return -1;
822                 }
823         }
824         err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
825         if (err!=0){
826                 ms_error("getnameinfo error: %s",strerror(errno));
827         }
828         close_socket(sock);
829         ms_message("Local interface to reach %s is %s.",dest,result);
830         return 0;
831 }