4 Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
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.
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.
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.
22 #include "mediastreamer2/mediastream.h"
25 #ifdef HAVE_SIGHANDLER_T
27 #endif /*HAVE_SIGHANDLER_T*/
30 #if !defined(_WIN32_WCE)
32 #include <sys/types.h>
39 #include <ortp/stun.h>
41 #ifdef HAVE_GETIFADDRS
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*/
56 snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
57 lockfile=fopen(lock_name,"w");
60 printf("Failed to create lock file.\n");
63 fprintf(lockfile,"%i",getpid());
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*/
75 snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
76 lockfile=fopen(lock_name,"r");
79 if (fscanf(lockfile,"%i",&pid)!=1){
80 ms_warning("Could not read pid in lock file.");
88 /* remove the lock file if it was set*/
89 int remove_lock_file()
94 err=unlink(lock_name);
102 char *int2str(int number)
104 char *numstr=ms_malloc(10);
105 snprintf(numstr,10,"%i",number);
109 void check_sound_device(LinphoneCore *lc)
116 char *i810_audio=NULL;
117 char *snd_pcm_oss=NULL;
118 char *snd_mixer_oss=NULL;
120 fd=open("/proc/modules",O_RDONLY);
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));
127 if (len==0) ms_warning("/proc/modules has zero size!");
129 /***** fstat does not work on /proc/modules for unknown reason *****/
131 file=ms_malloc(len+1);
133 if (a<len) file=ms_realloc(file,a+1);
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."));*/
142 snd_pcm=strstr(file,"snd-pcm");
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."));
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."));
155 ms_warning("Could not open /proc/modules.");
157 /* now check general volume. Some user forget to rise it and then complain that linphone is
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);
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);
169 if (file!=NULL) ms_free(file);
175 #define RTP_HDR_SZ 12
176 #define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/
178 static void payload_type_set_enable(PayloadType *pt,int value)
180 if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \
181 else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
184 static bool_t payload_type_enabled(PayloadType *pt) {
185 return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
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);
192 ms_error("Getting enablement status of codec not in audio or video list of PayloadType !");
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);
201 ms_error("Enabling codec not in audio or video list of PayloadType !");
205 const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
206 if (ms_filter_codec_supported(pt->mime_type)){
207 MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
209 return dgettext("mediastreamer",desc->text);
218 /*this function makes a special case for speex/8000.
219 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
220 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
221 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
222 int upload_bw=linphone_core_get_upload_bandwidth(lc);
223 if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
224 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
228 return pt->normal_bitrate;
231 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
235 bitrate=get_codec_bitrate(lc,pt);
236 packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
237 return packet_size*8.0*npacket;
240 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){
241 call->audio_bw=(int)(get_audio_payload_bandwidth(call->core,pt)/1000.0);
242 ms_message("Audio bandwidth for this call is %i",call->audio_bw);
245 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
247 PayloadType *max=NULL;
248 for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
249 PayloadType *pt=(PayloadType*)elem->data;
250 if (payload_type_enabled(pt)){
251 int pt_bitrate=get_codec_bitrate(lc,pt);
252 if (max==NULL) max=pt;
253 else if (max->normal_bitrate<pt_bitrate){
259 lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0);
263 bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit)
269 case PAYLOAD_AUDIO_CONTINUOUS:
270 case PAYLOAD_AUDIO_PACKETIZED:
271 codec_band=get_audio_payload_bandwidth(lc,pt);
272 ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
273 /*hack to avoid using uwb codecs when having low bitrate and video*/
274 if (bandwidth_is_greater(199,bandwidth_limit)){
275 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
279 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
282 if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/
291 /* return TRUE if codec can be used with bandwidth, FALSE else*/
292 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
295 int allowed_bw,video_bw;
298 linphone_core_update_allocated_audio_bandwidth(lc);
299 allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
300 linphone_core_get_upload_bandwidth(lc));
303 video_bw=1500; /*around 1.5 Mbit/s*/
305 video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw);
308 case PAYLOAD_AUDIO_CONTINUOUS:
309 case PAYLOAD_AUDIO_PACKETIZED:
310 codec_band=get_audio_payload_bandwidth(lc,pt);
311 ret=bandwidth_is_greater(allowed_bw*1000,codec_band);
312 /*hack to avoid using uwb codecs when having low bitrate and video*/
313 if (bandwidth_is_greater(199,allowed_bw)){
314 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
318 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
322 pt->normal_bitrate=video_bw*1000;
331 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
332 #if !defined(_WIN32_WCE)
333 FILE *f=popen(command,"r");
336 *result=ms_malloc(4096);
337 err=fread(*result,1,4096-1,f);
339 ms_warning("Error reading command output:%s",strerror(errno));
345 if (command_ret!=NULL) *command_ret=err;
348 #endif /*_WIN32_WCE*/
352 static ortp_socket_t create_socket(int local_port){
353 struct sockaddr_in laddr;
356 sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
358 ms_error("Fail to create socket");
361 memset (&laddr,0,sizeof(laddr));
362 laddr.sin_family=AF_INET;
363 laddr.sin_addr.s_addr=INADDR_ANY;
364 laddr.sin_port=htons(local_port);
365 if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
366 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
371 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
372 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
373 ms_warning("Fail to set SO_REUSEADDR");
375 set_non_blocking_socket(sock);
379 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
380 char buf[STUN_MAX_MESSAGE_SIZE];
381 int len = STUN_MAX_MESSAGE_SIZE;
382 StunAtrString username;
383 StunAtrString password;
386 memset(&req, 0, sizeof(StunMessage));
387 memset(&username,0,sizeof(username));
388 memset(&password,0,sizeof(password));
389 stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
390 len = stunEncodeMessage( &req, buf, len, &password);
392 ms_error("Fail to encode stun message.");
395 err=sendto(sock,buf,len,0,server,addrlen);
397 ms_error("sendto failed: %s",strerror(errno));
403 int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
404 struct addrinfo hints,*res=NULL;
407 char host[NI_MAXHOST];
409 host[NI_MAXHOST-1]='\0';
410 strncpy(host,server,sizeof(host)-1);
416 memset(&hints,0,sizeof(hints));
417 hints.ai_family=PF_INET;
418 hints.ai_socktype=SOCK_DGRAM;
419 hints.ai_protocol=IPPROTO_UDP;
420 ret=getaddrinfo(host,port,&hints,&res);
422 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
426 memcpy(ss,res->ai_addr,res->ai_addrlen);
427 *socklen=res->ai_addrlen;
432 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
433 char buf[STUN_MAX_MESSAGE_SIZE];
434 int len = STUN_MAX_MESSAGE_SIZE;
436 len=recv(sock,buf,len,0);
439 stunParseMessage(buf,len, &resp );
440 *id=resp.msgHdr.tr_id.octet[0];
441 if (resp.hasXorMappedAddress){
442 *port = resp.xorMappedAddress.ipv4.port;
443 ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
444 }else if (resp.hasMappedAddress){
445 *port = resp.mappedAddress.ipv4.port;
446 ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
448 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
453 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
454 const char *server=linphone_core_get_stun_server(lc);
456 if (lc->sip_conf.ipv6_enabled){
457 ms_warning("stun support is not implemented for ipv6");
461 struct sockaddr_storage ss;
463 ortp_socket_t sock1=-1, sock2=-1;
464 bool_t video_enabled=linphone_core_video_enabled(lc);
465 bool_t got_audio,got_video;
466 bool_t cone_audio=FALSE,cone_video=FALSE;
467 struct timeval init,cur;
468 SalEndpointCandidate *ac,*vc;
470 ac=&call->localdesc->streams[0].candidates[0];
471 vc=&call->localdesc->streams[1].candidates[0];
473 if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
474 ms_error("Fail to parser stun server address: %s",server);
477 if (lc->vtable.display_status!=NULL)
478 lc->vtable.display_status(lc,_("Stun lookup in progress..."));
480 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
481 sock1=create_socket(call->audio_port);
484 sock2=create_socket(call->video_port);
485 if (sock2<0) return ;
487 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
488 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
490 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
491 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
495 gettimeofday(&init,NULL);
505 if (recvStunResponse(sock1,ac->addr,
507 ms_message("STUN test result: local audio port maps to %s:%i",
514 if (recvStunResponse(sock2,vc->addr,
516 ms_message("STUN test result: local video port maps to %s:%i",
523 gettimeofday(&cur,NULL);
524 elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
525 if (elapsed>2000) break;
526 }while(!(got_audio && (got_video||sock2<0) ) );
528 ms_error("No stun server response for audio port.");
531 ms_warning("NAT is symmetric for audio port");
540 ms_error("No stun server response for video port.");
543 ms_warning("NAT is symmetric for video port.");
551 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
553 strcpy(call->localdesc->addr,ac->addr);
556 if (sock2>=0) close_socket(sock2);
560 static int extract_sip_port(const char *config){
564 FILE *f=fopen(config,"r");
566 while(fgets(line,sizeof(line),f)!=NULL){
567 if (fmtp_get_value(line,"sip_port",port,sizeof(port))){
576 int linphone_core_wake_up_possible_already_running_instance(
577 const char * config_file, const char * addr_to_call)
579 int port=extract_sip_port(config_file);
580 const char *wakeup="WAKEUP sip:127.0.0.1 SIP/2.0\r\n"
581 "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n"
582 "From: <sip:another_linphone@127.0.0.1>;tag=%u\r\n"
583 "To: <sip:you@127.0.0.1>\r\n"
585 "Call-ID: %u@onsantape\r\n"
586 "Content-length: 0\r\n\r\n";
587 const char * call = "REFER sip:127.0.0.1 SIP/2.0\r\n"
588 "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n"
589 "From: <sip:another_linphone@127.0.0.1>;tag=%u\r\n"
590 "To: <sip:you@127.0.0.1>\r\n"
593 "Call-ID: %u@onsantape\r\n"
594 "Content-length: 0\r\n\r\n";
596 /*make sure ortp is initialized (it initializes win32 socket api)*/
599 struct sockaddr_storage ss;
602 snprintf(tmp,sizeof(tmp),"127.0.0.1:%i",port);
603 if (parse_hostname_to_addr(tmp,&ss,&sslen)==0){
605 ortp_socket_t sock=create_socket(locport);
606 if (sock<0) sock=create_socket(++locport);
609 if (addr_to_call != NULL)
610 snprintf(req, sizeof(req), call, locport,
611 random(), random(), addr_to_call, random());
613 snprintf(req, sizeof(req), wakeup, locport,
614 random(), random(), random());
615 if (connect(sock,(struct sockaddr*)&ss,sslen)<0){
616 fprintf(stderr,"connect failed: %s\n",getSocketError());
617 }else if (send(sock,req,strlen(req),0)>0){
618 /*wait a bit for a response*/
621 if (recv(sock,req,sizeof(req),0)>0){
624 }else if (getSocketErrorCode()!=EWOULDBLOCK){
634 ms_message("sendto() of WAKEUP request failed, nobody to wakeup.");
643 #ifdef HAVE_GETIFADDRS
646 static int get_local_ip_with_getifaddrs(int type, char *address, int size)
649 struct ifaddrs *ifpstart;
652 if (getifaddrs(&ifpstart) < 0) {
656 for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
657 if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
658 && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
660 getnameinfo(ifp->ifa_addr,
662 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
663 address, size, NULL, 0, NI_NUMERICHOST);
664 if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */
665 /*ms_message("getifaddrs() found %s",address);*/
671 freeifaddrs(ifpstart);
677 static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
679 struct addrinfo hints;
680 struct addrinfo *res=NULL;
681 struct sockaddr_storage addr;
682 struct sockaddr *p_addr=(struct sockaddr*)&addr;
686 memset(&hints,0,sizeof(hints));
687 hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
688 hints.ai_socktype=SOCK_DGRAM;
689 /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
690 err=getaddrinfo(dest,"5060",&hints,&res);
692 ms_error("getaddrinfo() error: %s",gai_strerror(err));
696 ms_error("bug: getaddrinfo returned nothing.");
699 sock=socket(res->ai_family,SOCK_DGRAM,0);
701 err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
703 ms_warning("Error in setsockopt: %s",strerror(errno));
705 err=connect(sock,res->ai_addr,res->ai_addrlen);
707 ms_error("Error in connect: %s",strerror(errno));
715 err=getsockname(sock,(struct sockaddr*)&addr,&s);
717 ms_error("Error in getsockname: %s",strerror(errno));
721 if (p_addr->sa_family==AF_INET){
722 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
723 if (p_sin->sin_addr.s_addr==0){
728 err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
730 ms_error("getnameinfo error: %s",strerror(errno));
733 ms_message("Local interface to reach %s is %s.",dest,result);
737 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
738 strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
739 #ifdef HAVE_GETIFADDRS
741 /*we use getifaddrs for lookup of default interface */
744 found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
747 }else if (found_ifs<=0){
748 /*absolutely no network on this machine */
753 /*else use connect to find the best local ip address */
755 dest="87.98.157.38"; /*a public IP address*/
756 else dest="2a00:1450:8002::68";
757 return get_local_ip_for_with_connect(type,dest,result);
766 void _linphone_core_configure_resolver(){
767 /*bionic declares _res but does not define nor export it !!*/
769 /*timeout and attempts are the same as retrans and retry, but are android specific names.*/
770 setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1);
773 _res.retrans=2; /*retransmit every two seconds*/
774 _res.retry=2; /*only two times per DNS server*/
780 void _linphone_core_configure_resolver(){