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(const PayloadType *pt) {
185 return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
188 bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt){
189 if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)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);
199 _linphone_core_codec_config_write(lc);
202 ms_error("Enabling codec not in audio or video list of PayloadType !");
206 int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){
207 return payload_type_get_number(pt);
210 const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
211 if (ms_filter_codec_supported(pt->mime_type)){
212 MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
214 return dgettext("mediastreamer",desc->text);
223 /*this function makes a special case for speex/8000.
224 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
225 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
226 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
227 int upload_bw=linphone_core_get_upload_bandwidth(lc);
228 if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
229 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
233 return pt->normal_bitrate;
236 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
240 bitrate=get_codec_bitrate(lc,pt);
241 packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
242 return packet_size*8.0*npacket;
245 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){
246 call->audio_bw=(int)(get_audio_payload_bandwidth(call->core,pt)/1000.0);
247 ms_message("Audio bandwidth for this call is %i",call->audio_bw);
250 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
252 PayloadType *max=NULL;
253 for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
254 PayloadType *pt=(PayloadType*)elem->data;
255 if (payload_type_enabled(pt)){
256 int pt_bitrate=get_codec_bitrate(lc,pt);
257 if (max==NULL) max=pt;
258 else if (max->normal_bitrate<pt_bitrate){
264 lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0);
268 bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit)
274 case PAYLOAD_AUDIO_CONTINUOUS:
275 case PAYLOAD_AUDIO_PACKETIZED:
276 codec_band=get_audio_payload_bandwidth(lc,pt);
277 ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
278 /*hack to avoid using uwb codecs when having low bitrate and video*/
279 if (bandwidth_is_greater(199,bandwidth_limit)){
280 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
284 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
287 if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/
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)
300 int allowed_bw,video_bw;
303 linphone_core_update_allocated_audio_bandwidth(lc);
304 allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
305 linphone_core_get_upload_bandwidth(lc));
308 video_bw=1500; /*around 1.5 Mbit/s*/
310 video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw);
313 case PAYLOAD_AUDIO_CONTINUOUS:
314 case PAYLOAD_AUDIO_PACKETIZED:
315 codec_band=get_audio_payload_bandwidth(lc,pt);
316 ret=bandwidth_is_greater(allowed_bw*1000,codec_band);
317 /*hack to avoid using uwb codecs when having low bitrate and video*/
318 if (bandwidth_is_greater(199,allowed_bw)){
319 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
323 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
327 pt->normal_bitrate=video_bw*1000;
336 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
337 #if !defined(_WIN32_WCE)
338 FILE *f=popen(command,"r");
341 *result=ms_malloc(4096);
342 err=fread(*result,1,4096-1,f);
344 ms_warning("Error reading command output:%s",strerror(errno));
350 if (command_ret!=NULL) *command_ret=err;
353 #endif /*_WIN32_WCE*/
357 static ortp_socket_t create_socket(int local_port){
358 struct sockaddr_in laddr;
361 sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
363 ms_error("Fail to create socket");
366 memset (&laddr,0,sizeof(laddr));
367 laddr.sin_family=AF_INET;
368 laddr.sin_addr.s_addr=INADDR_ANY;
369 laddr.sin_port=htons(local_port);
370 if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
371 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
376 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
377 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
378 ms_warning("Fail to set SO_REUSEADDR");
380 set_non_blocking_socket(sock);
384 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
385 char buf[STUN_MAX_MESSAGE_SIZE];
386 int len = STUN_MAX_MESSAGE_SIZE;
387 StunAtrString username;
388 StunAtrString password;
391 memset(&req, 0, sizeof(StunMessage));
392 memset(&username,0,sizeof(username));
393 memset(&password,0,sizeof(password));
394 stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
395 len = stunEncodeMessage( &req, buf, len, &password);
397 ms_error("Fail to encode stun message.");
400 err=sendto(sock,buf,len,0,server,addrlen);
402 ms_error("sendto failed: %s",strerror(errno));
408 int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
409 struct addrinfo hints,*res=NULL;
412 char host[NI_MAXHOST];
414 host[NI_MAXHOST-1]='\0';
415 strncpy(host,server,sizeof(host)-1);
421 memset(&hints,0,sizeof(hints));
422 hints.ai_family=PF_INET;
423 hints.ai_socktype=SOCK_DGRAM;
424 hints.ai_protocol=IPPROTO_UDP;
425 ret=getaddrinfo(host,port,&hints,&res);
427 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
431 memcpy(ss,res->ai_addr,res->ai_addrlen);
432 *socklen=res->ai_addrlen;
437 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
438 char buf[STUN_MAX_MESSAGE_SIZE];
439 int len = STUN_MAX_MESSAGE_SIZE;
441 len=recv(sock,buf,len,0);
444 stunParseMessage(buf,len, &resp );
445 *id=resp.msgHdr.tr_id.octet[0];
446 if (resp.hasXorMappedAddress){
447 *port = resp.xorMappedAddress.ipv4.port;
448 ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
449 }else if (resp.hasMappedAddress){
450 *port = resp.mappedAddress.ipv4.port;
451 ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
453 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
458 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
459 const char *server=linphone_core_get_stun_server(lc);
461 if (lc->sip_conf.ipv6_enabled){
462 ms_warning("stun support is not implemented for ipv6");
466 struct sockaddr_storage ss;
468 ortp_socket_t sock1=-1, sock2=-1;
470 bool_t video_enabled=linphone_core_video_enabled(lc);
471 bool_t got_audio,got_video;
472 bool_t cone_audio=FALSE,cone_video=FALSE;
473 struct timeval init,cur;
474 SalEndpointCandidate *ac,*vc;
476 ac=&call->localdesc->streams[0].candidates[0];
477 vc=&call->localdesc->streams[1].candidates[0];
479 if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
480 ms_error("Fail to parser stun server address: %s",server);
483 if (lc->vtable.display_status!=NULL)
484 lc->vtable.display_status(lc,_("Stun lookup in progress..."));
486 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
487 sock1=create_socket(call->audio_port);
488 if (sock1==-1) return;
490 sock2=create_socket(call->video_port);
491 if (sock2==-1) return ;
495 gettimeofday(&init,NULL);
500 ms_message("Sending stun requests...");
501 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
502 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
504 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
505 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
514 if (recvStunResponse(sock1,ac->addr,
516 ms_message("STUN test result: local audio port maps to %s:%i",
523 if (recvStunResponse(sock2,vc->addr,
525 ms_message("STUN test result: local video port maps to %s:%i",
532 gettimeofday(&cur,NULL);
533 elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
535 ms_message("Stun responses timeout, going ahead.");
539 }while(!(got_audio && (got_video||sock2==-1) ) );
541 ms_error("No stun server response for audio port.");
544 ms_message("NAT is symmetric for audio port");
549 ms_error("No stun server response for video port.");
552 ms_message("NAT is symmetric for video port.");
556 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
558 strcpy(call->localdesc->addr,ac->addr);
561 if (sock2!=-1) close_socket(sock2);
565 int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
568 struct sockaddr_storage ss;
570 IceCheckList *audio_check_list;
571 IceCheckList *video_check_list;
572 const char *server = linphone_core_get_stun_server(lc);
574 if ((server == NULL) || (call->ice_session == NULL)) return -1;
575 audio_check_list = ice_session_check_list(call->ice_session, 0);
576 video_check_list = ice_session_check_list(call->ice_session, 1);
577 if (audio_check_list == NULL) return -1;
579 if (lc->sip_conf.ipv6_enabled){
580 ms_warning("stun support is not implemented for ipv6");
584 if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) {
585 ms_error("Fail to parser stun server address: %s", server);
588 if (lc->vtable.display_status != NULL)
589 lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
591 /* Gather local host candidates. */
592 if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
593 ms_error("Fail to get local ip");
596 ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
597 ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
598 if (call->params.has_video && (video_check_list != NULL)) {
599 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
600 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
603 /* Gather local srflx candidates. */
604 ice_session_gather_candidates(call->ice_session, ss, ss_len);
608 void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
610 const char *rtp_addr, *rtcp_addr;
611 IceSessionState session_state = ice_session_state(session);
615 if (session_state == IS_Completed) {
616 desc->ice_completed = TRUE;
617 ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
618 strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
621 desc->ice_completed = FALSE;
623 strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
624 strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
625 for (i = 0; i < desc->nstreams; i++) {
626 SalStreamDescription *stream = &desc->streams[i];
627 IceCheckList *cl = ice_session_check_list(session, i);
629 if (cl == NULL) continue;
630 if (cl->state == ICL_Completed) {
631 stream->ice_completed = TRUE;
632 ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
633 strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr));
634 strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr));
636 stream->ice_completed = FALSE;
638 if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd)))
639 strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd));
641 memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
642 if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag)))
643 strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag));
645 memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
646 if ((cl->state == ICL_Running) || (cl->state == ICL_Completed)) {
647 memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates));
648 for (j = 0; j < ms_list_size(cl->local_candidates); j++) {
649 SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates];
650 IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j);
651 const char *default_addr = NULL;
652 int default_port = 0;
653 if (ice_candidate->componentID == 1) {
654 default_addr = stream->rtp_addr;
655 default_port = stream->rtp_port;
656 } else if (ice_candidate->componentID == 2) {
657 default_addr = stream->rtcp_addr;
658 default_port = stream->rtcp_port;
660 if (default_addr[0] == '\0') default_addr = desc->addr;
661 /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */
662 if ((cl->state == ICL_Completed)
663 && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0)))
665 strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation));
666 sal_candidate->componentID = ice_candidate->componentID;
667 sal_candidate->priority = ice_candidate->priority;
668 strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type));
669 strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr));
670 sal_candidate->port = ice_candidate->taddr.port;
671 if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) {
672 strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr));
673 sal_candidate->rport = ice_candidate->base->taddr.port;
678 if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
679 int rtp_port, rtcp_port;
680 memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
681 ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
682 strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
683 stream->ice_remote_candidates[0].port = rtp_port;
684 strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
685 stream->ice_remote_candidates[1].port = rtcp_port;
690 void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
692 if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) {
694 ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
695 for (i = 0; i < md->nstreams; i++) {
696 const SalStreamDescription *stream = &md->streams[i];
697 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
699 cl = ice_check_list_new();
700 ice_session_add_check_list(call->ice_session, cl);
701 switch (stream->type) {
703 if (call->audiostream != NULL) call->audiostream->ice_check_list = cl;
706 if (call->videostream != NULL) call->videostream->ice_check_list = cl;
712 if (stream->ice_mismatch == TRUE) {
713 ice_check_list_set_state(cl, ICL_Failed);
715 if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
716 ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
717 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
718 const SalIceCandidate *candidate = &stream->ice_candidates[j];
719 bool_t default_candidate = FALSE;
720 const char *addr = NULL;
722 if (candidate->addr[0] == '\0') break;
723 if (candidate->componentID == 1) {
724 addr = stream->rtp_addr;
725 port = stream->rtp_port;
726 } else if (candidate->componentID == 2) {
727 addr = stream->rtcp_addr;
728 port = stream->rtcp_port;
730 if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
731 default_candidate = TRUE;
732 ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID,
733 candidate->priority, candidate->foundation, default_candidate);
735 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
736 const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j];
737 const char *addr = NULL;
739 int componentID = j + 1;
740 if (candidate->addr[0] == '\0') break;
741 ms_error("handle remote-candidates attribute");
742 if (componentID == 1) {
743 addr = stream->rtp_addr;
744 port = stream->rtp_port;
745 } else if (componentID == 2) {
746 addr = stream->rtcp_addr;
747 port = stream->rtcp_port;
749 if (addr[0] == '\0') addr = md->addr;
750 ice_add_losing_pair(ice_session_check_list(call->ice_session, i), j + 1, candidate->addr, candidate->port, addr, port);
754 for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) {
755 ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
758 if ((ice_session_state(call->ice_session) == IS_Failed) || (ice_session_nb_check_lists(call->ice_session) == 0)) {
759 linphone_call_delete_ice_session(call);
763 LinphoneCall * is_a_linphone_call(void *user_pointer){
764 LinphoneCall *call=(LinphoneCall*)user_pointer;
765 if (call==NULL) return NULL;
766 return call->magic==linphone_call_magic ? call : NULL;
769 LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer){
770 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)user_pointer;
771 if (cfg==NULL) return NULL;
772 return cfg->magic==linphone_proxy_config_magic ? cfg : NULL;
776 #ifdef HAVE_GETIFADDRS
779 static int get_local_ip_with_getifaddrs(int type, char *address, int size)
782 struct ifaddrs *ifpstart;
785 if (getifaddrs(&ifpstart) < 0) {
789 for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
790 if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
791 && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
793 getnameinfo(ifp->ifa_addr,
795 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
796 address, size, NULL, 0, NI_NUMERICHOST);
797 if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */
798 /*ms_message("getifaddrs() found %s",address);*/
804 freeifaddrs(ifpstart);
810 static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
812 struct addrinfo hints;
813 struct addrinfo *res=NULL;
814 struct sockaddr_storage addr;
815 struct sockaddr *p_addr=(struct sockaddr*)&addr;
819 memset(&hints,0,sizeof(hints));
820 hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
821 hints.ai_socktype=SOCK_DGRAM;
822 /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
823 err=getaddrinfo(dest,"5060",&hints,&res);
825 ms_error("getaddrinfo() error: %s",gai_strerror(err));
829 ms_error("bug: getaddrinfo returned nothing.");
832 sock=socket(res->ai_family,SOCK_DGRAM,0);
834 err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
836 ms_warning("Error in setsockopt: %s",strerror(errno));
838 err=connect(sock,res->ai_addr,res->ai_addrlen);
840 ms_error("Error in connect: %s",strerror(errno));
848 err=getsockname(sock,(struct sockaddr*)&addr,&s);
850 ms_error("Error in getsockname: %s",strerror(errno));
854 if (p_addr->sa_family==AF_INET){
855 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
856 if (p_sin->sin_addr.s_addr==0){
861 err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
863 ms_error("getnameinfo error: %s",strerror(errno));
866 ms_message("Local interface to reach %s is %s.",dest,result);
870 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
871 strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
872 #ifdef HAVE_GETIFADDRS
874 /*we use getifaddrs for lookup of default interface */
877 found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
880 }else if (found_ifs<=0){
881 /*absolutely no network on this machine */
886 /*else use connect to find the best local ip address */
888 dest="87.98.157.38"; /*a public IP address*/
889 else dest="2a00:1450:8002::68";
890 return get_local_ip_for_with_connect(type,dest,result);
899 void _linphone_core_configure_resolver(){
900 /*bionic declares _res but does not define nor export it !!*/
902 /*timeout and attempts are the same as retrans and retry, but are android specific names.*/
903 setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1);
906 _res.retrans=2; /*retransmit every two seconds*/
907 _res.retry=2; /*only two times per DNS server*/
913 void _linphone_core_configure_resolver(){