source: mediastreamer2/linphone/coreapi/misc.c @ 222:b0a88ad21aa7

Last change on this file since 222:b0a88ad21aa7 was 222:b0a88ad21aa7, checked in by smorlat <smorlat@…>, 4 years ago

various things in progress.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@225 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

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