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>
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*/
51 snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
52 lockfile=fopen(lock_name,"w");
55 printf("Failed to create lock file.\n");
58 fprintf(lockfile,"%i",getpid());
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*/
70 snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
71 lockfile=fopen(lock_name,"r");
74 if (fscanf(lockfile,"%i",&pid)!=1){
75 ms_warning("Could not read pid in lock file.");
83 /* remove the lock file if it was set*/
84 int remove_lock_file()
89 err=unlink(lock_name);
97 char *int2str(int number)
99 char *numstr=ms_malloc(10);
100 snprintf(numstr,10,"%i",number);
104 void check_sound_device(LinphoneCore *lc)
111 char *i810_audio=NULL;
112 char *snd_pcm_oss=NULL;
113 char *snd_mixer_oss=NULL;
115 fd=open("/proc/modules",O_RDONLY);
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));
122 if (len==0) ms_warning("/proc/modules has zero size!");
124 /***** fstat does not work on /proc/modules for unknown reason *****/
126 file=ms_malloc(len+1);
128 if (a<len) file=ms_realloc(file,a+1);
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."));*/
137 snd_pcm=strstr(file,"snd-pcm");
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."));
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."));
150 ms_warning("Could not open /proc/modules.");
152 /* now check general volume. Some user forget to rise it and then complain that linphone is
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);
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);
164 if (file!=NULL) ms_free(file);
170 #define RTP_HDR_SZ 12
171 #define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/
173 static void payload_type_set_enable(PayloadType *pt,int value)
175 if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \
176 else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
179 static bool_t payload_type_enabled(PayloadType *pt) {
180 return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
183 bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt){
184 if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
185 return payload_type_enabled(pt);
187 ms_error("Getting enablement status of codec not in audio or video list of PayloadType !");
191 int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){
192 if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
193 payload_type_set_enable(pt,enabled);
196 ms_error("Enabling codec not in audio or video list of PayloadType !");
200 const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
201 if (ms_filter_codec_supported(pt->mime_type)){
202 MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
203 return _(desc->text);
209 /*this function makes a special case for speex/8000.
210 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
211 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
212 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
213 int upload_bw=linphone_core_get_upload_bandwidth(lc);
214 if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
215 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
219 return pt->normal_bitrate;
222 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
226 bitrate=get_codec_bitrate(lc,pt);
227 packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
228 return packet_size*8.0*npacket;
231 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCore *lc, const PayloadType *pt){
232 lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,pt)/1000.0);
234 linphone_core_set_download_bandwidth(lc,lc->net_conf.download_bw);
235 linphone_core_set_upload_bandwidth(lc,lc->net_conf.upload_bw);
238 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
240 PayloadType *max=NULL;
241 for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
242 PayloadType *pt=(PayloadType*)elem->data;
243 if (payload_type_enabled(pt)){
244 int pt_bitrate=get_codec_bitrate(lc,pt);
245 if (max==NULL) max=pt;
246 else if (max->normal_bitrate<pt_bitrate){
252 linphone_core_update_allocated_audio_bandwidth_in_call(lc,max);
256 /* return TRUE if codec can be used with bandwidth, FALSE else*/
257 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
264 update allocated audio bandwidth to allocate the remaining to video.
265 This must be done outside calls, because after sdp negociation
266 the audio bandwidth is refined to the selected codec
268 if (!linphone_core_in_call(lc)) linphone_core_update_allocated_audio_bandwidth(lc);
269 min_audio_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
270 linphone_core_get_upload_bandwidth(lc));
271 if (min_audio_bw==0) min_audio_bw=-1;
272 min_video_bw=get_min_bandwidth(lc->dw_video_bw,lc->up_video_bw);
275 case PAYLOAD_AUDIO_CONTINUOUS:
276 case PAYLOAD_AUDIO_PACKETIZED:
277 codec_band=get_audio_payload_bandwidth(lc,pt);
278 ret=bandwidth_is_greater(min_audio_bw*1000,codec_band);
279 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
282 if (min_video_bw!=0) {/* infinite (-1) or strictly positive*/
283 /*let the video use all the bandwidth minus the maximum bandwidth used by audio */
285 pt->normal_bitrate=min_video_bw*1000;
287 pt->normal_bitrate=1500000; /*around 1.5 Mbit/s*/
293 /*if (!ret) ms_warning("Payload %s is not usable with your internet connection.",pt->mime_type);*/
298 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
299 #if !defined(_WIN32_WCE)
300 FILE *f=popen(command,"r");
303 *result=ms_malloc(4096);
304 err=fread(*result,1,4096-1,f);
306 ms_warning("Error reading command output:%s",strerror(errno));
312 if (command_ret!=NULL) *command_ret=err;
315 #endif /*_WIN32_WCE*/
319 #if defined(HAVE_GETIFADDRS) && defined(INET6)
320 #include <sys/types.h>
321 #include <sys/socket.h>
323 bool_t host_has_ipv6_network()
326 struct ifaddrs *ifpstart;
327 bool_t ipv6_present=FALSE;
329 if (getifaddrs (&ifpstart) < 0)
334 for (ifp=ifpstart; ifp != NULL; ifp = ifp->ifa_next)
339 switch (ifp->ifa_addr->sa_family) {
351 freeifaddrs (ifpstart);
357 bool_t host_has_ipv6_network()
365 static ortp_socket_t create_socket(int local_port){
366 struct sockaddr_in laddr;
369 sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
371 ms_error("Fail to create socket");
374 memset (&laddr,0,sizeof(laddr));
375 laddr.sin_family=AF_INET;
376 laddr.sin_addr.s_addr=INADDR_ANY;
377 laddr.sin_port=htons(local_port);
378 if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
379 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
384 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
385 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
386 ms_warning("Fail to set SO_REUSEADDR");
388 set_non_blocking_socket(sock);
392 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
393 char buf[STUN_MAX_MESSAGE_SIZE];
394 int len = STUN_MAX_MESSAGE_SIZE;
395 StunAtrString username;
396 StunAtrString password;
399 memset(&req, 0, sizeof(StunMessage));
400 memset(&username,0,sizeof(username));
401 memset(&password,0,sizeof(password));
402 stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
403 len = stunEncodeMessage( &req, buf, len, &password);
405 ms_error("Fail to encode stun message.");
408 err=sendto(sock,buf,len,0,server,addrlen);
410 ms_error("sendto failed: %s",strerror(errno));
416 static int parse_stun_server_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
417 struct addrinfo hints,*res=NULL;
420 char host[NI_MAXHOST];
422 host[NI_MAXHOST-1]='\0';
423 strncpy(host,server,sizeof(host)-1);
429 memset(&hints,0,sizeof(hints));
430 hints.ai_family=PF_INET;
431 hints.ai_socktype=SOCK_DGRAM;
432 hints.ai_protocol=IPPROTO_UDP;
433 ret=getaddrinfo(host,port,&hints,&res);
435 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
439 memcpy(ss,res->ai_addr,res->ai_addrlen);
440 *socklen=res->ai_addrlen;
445 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
446 char buf[STUN_MAX_MESSAGE_SIZE];
447 int len = STUN_MAX_MESSAGE_SIZE;
449 len=recv(sock,buf,len,0);
452 stunParseMessage(buf,len, &resp );
453 *id=resp.msgHdr.tr_id.octet[0];
454 *port = resp.mappedAddress.ipv4.port;
455 ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
456 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
461 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
462 const char *server=linphone_core_get_stun_server(lc);
464 if (lc->sip_conf.ipv6_enabled){
465 ms_warning("stun support is not implemented for ipv6");
469 struct sockaddr_storage ss;
471 ortp_socket_t sock1=-1, sock2=-1;
472 bool_t video_enabled=linphone_core_video_enabled(lc);
473 bool_t got_audio,got_video;
474 bool_t cone_audio=FALSE,cone_video=FALSE;
475 struct timeval init,cur;
476 SalEndpointCandidate *ac,*vc;
478 ac=&call->localdesc->streams[0].candidates[0];
479 vc=&call->localdesc->streams[1].candidates[0];
481 if (parse_stun_server_addr(server,&ss,&ss_len)<0){
482 ms_error("Fail to parser stun server address: %s",server);
485 if (lc->vtable.display_status!=NULL)
486 lc->vtable.display_status(lc,_("Stun lookup in progress..."));
488 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
489 sock1=create_socket(linphone_core_get_audio_port(lc));
492 sock2=create_socket(linphone_core_get_video_port(lc));
493 if (sock2<0) return ;
495 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
496 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
498 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
499 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
503 gettimeofday(&init,NULL);
513 if (recvStunResponse(sock1,ac->addr,
515 ms_message("STUN test result: local audio port maps to %s:%i",
522 if (recvStunResponse(sock2,vc->addr,
524 ms_message("STUN test result: local video port maps to %s:%i",
531 gettimeofday(&cur,NULL);
532 elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
533 if (elapsed>2000) break;
534 }while(!(got_audio && (got_video||sock2<0) ) );
536 ms_error("No stun server response for audio port.");
539 ms_warning("NAT is symmetric for audio port");
546 ms_error("No stun server response for video port.");
549 ms_warning("NAT is symmetric for video port.");
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_stun_server_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 int linphone_core_get_local_ip_for(const char *dest, char *result){
645 struct addrinfo hints;
646 struct addrinfo *res=NULL;
647 struct sockaddr_storage addr;
648 struct sockaddr *p_addr=(struct sockaddr*)&addr;
652 memset(&hints,0,sizeof(hints));
653 hints.ai_family=PF_UNSPEC;
654 hints.ai_socktype=SOCK_DGRAM;
655 /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
656 err=getaddrinfo(dest,"5060",&hints,&res);
658 ms_error("getaddrinfo() error: %s",gai_strerror(err));
662 ms_error("bug: getaddrinfo returned nothing.");
665 sock=socket(res->ai_family,SOCK_DGRAM,0);
667 err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
669 ms_warning("Error in setsockopt: %s",strerror(errno));
671 err=connect(sock,res->ai_addr,res->ai_addrlen);
673 ms_error("Error in connect: %s",strerror(errno));
681 err=getsockname(sock,(struct sockaddr*)&addr,&s);
683 ms_error("Error in getsockname: %s",strerror(errno));
687 if (p_addr->sa_family==AF_INET){
688 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
689 if (p_sin->sin_addr.s_addr==0){
694 err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
696 ms_error("getnameinfo error: %s",strerror(errno));
699 ms_message("Local interface to reach %s is %s.",dest,result);