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);
208 return _(desc->text);
214 /*this function makes a special case for speex/8000.
215 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
216 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
217 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
218 int upload_bw=linphone_core_get_upload_bandwidth(lc);
219 if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
220 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
224 return pt->normal_bitrate;
227 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
231 bitrate=get_codec_bitrate(lc,pt);
232 packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
233 return packet_size*8.0*npacket;
236 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCore *lc, const PayloadType *pt){
237 lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,pt)/1000.0);
239 linphone_core_set_download_bandwidth(lc,lc->net_conf.download_bw);
240 linphone_core_set_upload_bandwidth(lc,lc->net_conf.upload_bw);
243 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
245 PayloadType *max=NULL;
246 for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
247 PayloadType *pt=(PayloadType*)elem->data;
248 if (payload_type_enabled(pt)){
249 int pt_bitrate=get_codec_bitrate(lc,pt);
250 if (max==NULL) max=pt;
251 else if (max->normal_bitrate<pt_bitrate){
257 linphone_core_update_allocated_audio_bandwidth_in_call(lc,max);
261 bool_t linphone_core_is_payload_type_usable(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit)
267 case PAYLOAD_AUDIO_CONTINUOUS:
268 case PAYLOAD_AUDIO_PACKETIZED:
269 codec_band=get_audio_payload_bandwidth(lc,pt);
270 ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
271 /*hack to avoid using uwb codecs when having low bitrate and video*/
272 if (bandwidth_is_greater(199,bandwidth_limit)){
273 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
277 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
280 if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/
281 /*let the video use all the bandwidth minus the maximum bandwidth used by audio */
282 if (bandwidth_limit>0)
283 pt->normal_bitrate=bandwidth_limit*1000;
285 pt->normal_bitrate=1500000; /*around 1.5 Mbit/s*/
291 /*if (!ret) ms_warning("Payload %s is not usable with your internet connection.",pt->mime_type);*/
296 /* return TRUE if codec can be used with bandwidth, FALSE else*/
297 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
304 update allocated audio bandwidth to allocate the remaining to video.
305 This must be done outside calls, because after sdp negociation
306 the audio bandwidth is refined to the selected codec
308 if (!linphone_core_in_call(lc)) linphone_core_update_allocated_audio_bandwidth(lc);
309 min_audio_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
310 linphone_core_get_upload_bandwidth(lc));
311 if (min_audio_bw==0) min_audio_bw=-1;
312 min_video_bw=get_min_bandwidth(lc->dw_video_bw,lc->up_video_bw);
315 case PAYLOAD_AUDIO_CONTINUOUS:
316 case PAYLOAD_AUDIO_PACKETIZED:
317 codec_band=get_audio_payload_bandwidth(lc,pt);
318 ret=bandwidth_is_greater(min_audio_bw*1000,codec_band);
319 /*hack to avoid using uwb codecs when having low bitrate and video*/
320 if (bandwidth_is_greater(199,min_audio_bw)){
321 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
325 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
328 if (min_video_bw!=0) {/* infinite (-1) or strictly positive*/
329 /*let the video use all the bandwidth minus the maximum bandwidth used by audio */
331 pt->normal_bitrate=min_video_bw*1000;
333 pt->normal_bitrate=1500000; /*around 1.5 Mbit/s*/
339 /*if (!ret) ms_warning("Payload %s is not usable with your internet connection.",pt->mime_type);*/
344 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
345 #if !defined(_WIN32_WCE)
346 FILE *f=popen(command,"r");
349 *result=ms_malloc(4096);
350 err=fread(*result,1,4096-1,f);
352 ms_warning("Error reading command output:%s",strerror(errno));
358 if (command_ret!=NULL) *command_ret=err;
361 #endif /*_WIN32_WCE*/
365 #if defined(HAVE_GETIFADDRS) && defined(INET6)
366 #include <sys/types.h>
367 #include <sys/socket.h>
369 bool_t host_has_ipv6_network()
372 struct ifaddrs *ifpstart;
373 bool_t ipv6_present=FALSE;
375 if (getifaddrs (&ifpstart) < 0)
380 for (ifp=ifpstart; ifp != NULL; ifp = ifp->ifa_next)
385 switch (ifp->ifa_addr->sa_family) {
397 freeifaddrs (ifpstart);
403 bool_t host_has_ipv6_network()
411 static ortp_socket_t create_socket(int local_port){
412 struct sockaddr_in laddr;
415 sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
417 ms_error("Fail to create socket");
420 memset (&laddr,0,sizeof(laddr));
421 laddr.sin_family=AF_INET;
422 laddr.sin_addr.s_addr=INADDR_ANY;
423 laddr.sin_port=htons(local_port);
424 if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
425 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
430 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
431 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
432 ms_warning("Fail to set SO_REUSEADDR");
434 set_non_blocking_socket(sock);
438 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
439 char buf[STUN_MAX_MESSAGE_SIZE];
440 int len = STUN_MAX_MESSAGE_SIZE;
441 StunAtrString username;
442 StunAtrString password;
445 memset(&req, 0, sizeof(StunMessage));
446 memset(&username,0,sizeof(username));
447 memset(&password,0,sizeof(password));
448 stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
449 len = stunEncodeMessage( &req, buf, len, &password);
451 ms_error("Fail to encode stun message.");
454 err=sendto(sock,buf,len,0,server,addrlen);
456 ms_error("sendto failed: %s",strerror(errno));
462 static int parse_stun_server_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
463 struct addrinfo hints,*res=NULL;
466 char host[NI_MAXHOST];
468 host[NI_MAXHOST-1]='\0';
469 strncpy(host,server,sizeof(host)-1);
475 memset(&hints,0,sizeof(hints));
476 hints.ai_family=PF_INET;
477 hints.ai_socktype=SOCK_DGRAM;
478 hints.ai_protocol=IPPROTO_UDP;
479 ret=getaddrinfo(host,port,&hints,&res);
481 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
485 memcpy(ss,res->ai_addr,res->ai_addrlen);
486 *socklen=res->ai_addrlen;
491 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
492 char buf[STUN_MAX_MESSAGE_SIZE];
493 int len = STUN_MAX_MESSAGE_SIZE;
495 len=recv(sock,buf,len,0);
498 stunParseMessage(buf,len, &resp );
499 *id=resp.msgHdr.tr_id.octet[0];
500 if (resp.hasXorMappedAddress){
501 *port = resp.xorMappedAddress.ipv4.port;
502 ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
503 }else if (resp.hasMappedAddress){
504 *port = resp.mappedAddress.ipv4.port;
505 ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
507 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
512 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
513 const char *server=linphone_core_get_stun_server(lc);
515 if (lc->sip_conf.ipv6_enabled){
516 ms_warning("stun support is not implemented for ipv6");
520 struct sockaddr_storage ss;
522 ortp_socket_t sock1=-1, sock2=-1;
523 bool_t video_enabled=linphone_core_video_enabled(lc);
524 bool_t got_audio,got_video;
525 bool_t cone_audio=FALSE,cone_video=FALSE;
526 struct timeval init,cur;
527 SalEndpointCandidate *ac,*vc;
529 ac=&call->localdesc->streams[0].candidates[0];
530 vc=&call->localdesc->streams[1].candidates[0];
532 if (parse_stun_server_addr(server,&ss,&ss_len)<0){
533 ms_error("Fail to parser stun server address: %s",server);
536 if (lc->vtable.display_status!=NULL)
537 lc->vtable.display_status(lc,_("Stun lookup in progress..."));
539 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
540 sock1=create_socket(call->audio_port);
543 sock2=create_socket(call->video_port);
544 if (sock2<0) return ;
546 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
547 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
549 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
550 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
554 gettimeofday(&init,NULL);
564 if (recvStunResponse(sock1,ac->addr,
566 ms_message("STUN test result: local audio port maps to %s:%i",
573 if (recvStunResponse(sock2,vc->addr,
575 ms_message("STUN test result: local video port maps to %s:%i",
582 gettimeofday(&cur,NULL);
583 elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
584 if (elapsed>2000) break;
585 }while(!(got_audio && (got_video||sock2<0) ) );
587 ms_error("No stun server response for audio port.");
590 ms_warning("NAT is symmetric for audio port");
599 ms_error("No stun server response for video port.");
602 ms_warning("NAT is symmetric for video port.");
610 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
612 strcpy(call->localdesc->addr,ac->addr);
615 if (sock2>=0) close_socket(sock2);
619 static int extract_sip_port(const char *config){
623 FILE *f=fopen(config,"r");
625 while(fgets(line,sizeof(line),f)!=NULL){
626 if (fmtp_get_value(line,"sip_port",port,sizeof(port))){
635 int linphone_core_wake_up_possible_already_running_instance(
636 const char * config_file, const char * addr_to_call)
638 int port=extract_sip_port(config_file);
639 const char *wakeup="WAKEUP sip:127.0.0.1 SIP/2.0\r\n"
640 "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n"
641 "From: <sip:another_linphone@127.0.0.1>;tag=%u\r\n"
642 "To: <sip:you@127.0.0.1>\r\n"
644 "Call-ID: %u@onsantape\r\n"
645 "Content-length: 0\r\n\r\n";
646 const char * call = "REFER sip:127.0.0.1 SIP/2.0\r\n"
647 "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n"
648 "From: <sip:another_linphone@127.0.0.1>;tag=%u\r\n"
649 "To: <sip:you@127.0.0.1>\r\n"
652 "Call-ID: %u@onsantape\r\n"
653 "Content-length: 0\r\n\r\n";
655 /*make sure ortp is initialized (it initializes win32 socket api)*/
658 struct sockaddr_storage ss;
661 snprintf(tmp,sizeof(tmp),"127.0.0.1:%i",port);
662 if (parse_stun_server_addr(tmp,&ss,&sslen)==0){
664 ortp_socket_t sock=create_socket(locport);
665 if (sock<0) sock=create_socket(++locport);
668 if (addr_to_call != NULL)
669 snprintf(req, sizeof(req), call, locport,
670 random(), random(), addr_to_call, random());
672 snprintf(req, sizeof(req), wakeup, locport,
673 random(), random(), random());
674 if (connect(sock,(struct sockaddr*)&ss,sslen)<0){
675 fprintf(stderr,"connect failed: %s\n",getSocketError());
676 }else if (send(sock,req,strlen(req),0)>0){
677 /*wait a bit for a response*/
680 if (recv(sock,req,sizeof(req),0)>0){
683 }else if (getSocketErrorCode()!=EWOULDBLOCK){
693 ms_message("sendto() of WAKEUP request failed, nobody to wakeup.");
702 #ifdef HAVE_GETIFADDRS
705 static int get_local_ip_with_getifaddrs(int type, char *address, int size)
708 struct ifaddrs *ifpstart;
711 if (getifaddrs(&ifpstart) < 0) {
715 for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
716 if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
717 && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
719 getnameinfo(ifp->ifa_addr,
721 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
722 address, size, NULL, 0, NI_NUMERICHOST);
723 if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */
724 /*ms_message("getifaddrs() found %s",address);*/
730 freeifaddrs(ifpstart);
736 static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
738 struct addrinfo hints;
739 struct addrinfo *res=NULL;
740 struct sockaddr_storage addr;
741 struct sockaddr *p_addr=(struct sockaddr*)&addr;
745 memset(&hints,0,sizeof(hints));
746 hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
747 hints.ai_socktype=SOCK_DGRAM;
748 /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
749 err=getaddrinfo(dest,"5060",&hints,&res);
751 ms_error("getaddrinfo() error: %s",gai_strerror(err));
755 ms_error("bug: getaddrinfo returned nothing.");
758 sock=socket(res->ai_family,SOCK_DGRAM,0);
760 err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
762 ms_warning("Error in setsockopt: %s",strerror(errno));
764 err=connect(sock,res->ai_addr,res->ai_addrlen);
766 ms_error("Error in connect: %s",strerror(errno));
774 err=getsockname(sock,(struct sockaddr*)&addr,&s);
776 ms_error("Error in getsockname: %s",strerror(errno));
780 if (p_addr->sa_family==AF_INET){
781 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
782 if (p_sin->sin_addr.s_addr==0){
787 err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
789 ms_error("getnameinfo error: %s",strerror(errno));
792 ms_message("Local interface to reach %s is %s.",dest,result);
796 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
797 strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
798 #ifdef HAVE_GETIFADDRS
800 /*we use getifaddrs for lookup of default interface */
803 found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
806 }else if (found_ifs<=0){
807 /*absolutely no network on this machine */
812 /*else use connect to find the best local ip address */
814 dest="87.98.157.38"; /*a public IP address*/
815 else dest="2a00:1450:8002::68";
816 return get_local_ip_for_with_connect(type,dest,result);
825 void _linphone_core_configure_resolver(){
826 /*bionic declares _res but does not define nor export it !!*/
828 /*timeout and attempts are the same as retrans and retry, but are android specific names.*/
829 setenv("RES_OPTIONS","timeout:1 attempts:2 retrans:1 retry:2",1);
832 _res.retrans=1; /*retransmit every second*/
833 _res.retry=2; /*only two times per DNS server*/
839 void _linphone_core_configure_resolver(){