From 63181848bfde18ee18a454d2dc7a798bd498c22d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 3 Sep 2009 13:07:34 +0200 Subject: [PATCH 1/2] intermediate commit, not tested. --- linphone/coreapi/linphonecore.c | 46 +++++++++++++++++++++++++++------ linphone/coreapi/linphonecore.h | 5 +++- linphone/coreapi/private.h | 2 ++ linphone/coreapi/proxy.c | 21 +++++++++++++++ 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/linphone/coreapi/linphonecore.c b/linphone/coreapi/linphonecore.c index a06e57c64..4a1073db0 100644 --- a/linphone/coreapi/linphonecore.c +++ b/linphone/coreapi/linphonecore.c @@ -108,19 +108,18 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const osip_from_t *from, const osip_to_t *to) { LinphoneCall *call=ms_new0(LinphoneCall,1); - char localip[LINPHONE_IPADDR_SIZE]; char *fromstr=NULL,*tostr=NULL; call->dir=LinphoneCallOutgoing; call->cid=-1; call->did=-1; call->tid=-1; call->core=lc; - linphone_core_get_local_ip(lc,to->url->host,localip); + linphone_core_get_local_ip(lc,to->url->host,call->localip); osip_from_to_str(from,&fromstr); osip_to_to_str(to,&tostr); linphone_call_init_common(call,fromstr,tostr); call->sdpctx=sdp_handler_create_context(&linphone_sdphandler, - call->audio_params.natd_port>0 ? call->audio_params.natd_addr : localip, + call->audio_params.natd_port>0 ? call->audio_params.natd_addr : call->localip, from->url->username,NULL); sdp_context_set_user_pointer(call->sdpctx,(void*)call); discover_mtu(lc,to->url->host); @@ -128,9 +127,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const osip_f } -LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const char *from, const char *to, int cid, int did, int tid) -{ - char localip[LINPHONE_IPADDR_SIZE]; +LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const char *from, const char *to, int cid, int did, int tid){ LinphoneCall *call=ms_new0(LinphoneCall,1); osip_from_t *me= linphone_core_get_primary_contact_parsed(lc); osip_from_t *from_url=NULL; @@ -141,10 +138,10 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const char *from, co call->core=lc; osip_from_init(&from_url); osip_from_parse(from_url, from); - linphone_core_get_local_ip(lc,from_url->url->host,localip); + linphone_core_get_local_ip(lc,from_url->url->host,call->localip); linphone_call_init_common(call, osip_strdup(from), osip_strdup(to)); call->sdpctx=sdp_handler_create_context(&linphone_sdphandler, - call->audio_params.natd_port>0 ? call->audio_params.natd_addr : localip, + call->audio_params.natd_port>0 ? call->audio_params.natd_addr : call->localip, me->url->username,NULL); sdp_context_set_user_pointer(call->sdpctx,(void*)call); discover_mtu(lc,from_url->url->host); @@ -1277,6 +1274,34 @@ void linphone_set_sdp(osip_message_t *sip, const char *sdpmesg){ osip_message_set_content_length(sip,clen); } +LinphoneProxyConfig * linphone_core_goes_through_known_proxy(LinphoneCore *lc, const char *uri){ + const MSList *elem; + LinphoneProxyConfig *found_cfg=NULL; + osip_from_t *parsed_uri; + osip_from_init(&parsed_uri); + osip_from_parse(parsed_uri,uri); + for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; + const char *domain=linphone_proxy_config_get_domain(cfg); + if (domain!=NULL && strcmp(domain,parsed_uri->url->host)==0){ + found_cfg=cfg; + break; + } + } + osip_from_free(parsed_uri); + return found_cfg; +} + +static void fix_contact(osip_message_t *msg, const char *localip){ + osip_contact_t *ctt=NULL; + + osip_message_get_contact(msg,0,&ctt); + if (ctt!=NULL){ + osip_free(ctt->url->host); + ctt->url->host=osip_strdup(localip); + } +} + int linphone_core_invite(LinphoneCore *lc, const char *url) { char *barmsg; @@ -1324,6 +1349,11 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) osip_from_parse(parsed_url2,from); lc->call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); + /*try to be best-effort in giving real local or routable contact address, + except when the user choosed to override the ipaddress */ + if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) + fix_contact(invite,lc->call->localip); + barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); lc->vtable.display_status(lc,barmsg); ms_free(barmsg); diff --git a/linphone/coreapi/linphonecore.h b/linphone/coreapi/linphonecore.h index cb8fbbd64..bf0be2383 100644 --- a/linphone/coreapi/linphonecore.h +++ b/linphone/coreapi/linphonecore.h @@ -185,11 +185,12 @@ typedef struct _LinphoneCall int cid; /*call id */ int did; /*dialog id */ int tid; /*last transaction id*/ + char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ struct _sdp_context *sdpctx; time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ LCState state; - bool_t auth_pending; + bool_t auth_pending; } LinphoneCall; LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const osip_from_t *from, const osip_to_t *to); @@ -298,6 +299,8 @@ typedef struct _LinphoneProxyConfig char *type; struct _SipSetupContext *ssctx; int auth_failures; + char *contact_addr; /* our IP address as seen by the proxy, read from via 's received= parameter*/ + int contact_port; /*our IP port as seen by the proxy, read from via's rport= parameter */ bool_t commit; bool_t reg_sendregister; bool_t registered; diff --git a/linphone/coreapi/private.h b/linphone/coreapi/private.h index dd349750d..88067899b 100644 --- a/linphone/coreapi/private.h +++ b/linphone/coreapi/private.h @@ -133,5 +133,7 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); void linphone_core_write_friends_config(LinphoneCore* lc); void linphone_proxy_config_update(LinphoneProxyConfig *cfg); +void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port); + #endif /* _PRIVATE_H */ diff --git a/linphone/coreapi/proxy.c b/linphone/coreapi/proxy.c index eef862f19..eea60409e 100644 --- a/linphone/coreapi/proxy.c +++ b/linphone/coreapi/proxy.c @@ -54,12 +54,32 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx); if (obj->realm!=NULL) ms_free(obj->realm); if (obj->type!=NULL) ms_free(obj->type); + if (obj->contact_addr!=NULL) ms_free(obj->contact_addr); } bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ return obj->registered; } +void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port){ + if (cfg->registered){ + *ip=cfg->contact_addr; + *port=cfg->contact_port; + }else{ + *ip=NULL; + *port=0; + } +} + +static void update_contact(LinphoneProxyConfig *cfg, const char *ip, const char *port){ + if (cfg->contact_addr){ + ms_free(cfg->contact_addr); + } + cfg->contact_addr=ms_strdup(ip); + cfg->contact_port=atoi(port); + if (cfg->contact_port==0) cfg->contact_port=5060; +} + bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyConfig *obj, osip_message_t *orig_request, osip_message_t *last_answer){ osip_message_t *msg; const char *rport,*received; @@ -108,6 +128,7 @@ bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyCo ctt->url->port=osip_strdup(rport); eXosip_register_send_register(obj->rid,msg); eXosip_unlock(); + update_contact(obj,received,rport); ms_message("Resending new register with updated contact %s:%s",received,rport); return TRUE; } From b202a6e9cf5b6668a77300e87a96b309ab9a5449 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 3 Sep 2009 15:53:04 +0200 Subject: [PATCH 2/2] arrange to set correct local interface in SDP and contact. Use proxy received/rport if possible in INVITEs. --- linphone/coreapi/linphonecore.c | 79 ++++++++++++++++++++------------- linphone/coreapi/misc.c | 55 +++++++++++++++++++++++ linphone/coreapi/private.h | 3 +- 3 files changed, 105 insertions(+), 32 deletions(-) diff --git a/linphone/coreapi/linphonecore.c b/linphone/coreapi/linphonecore.c index 4a1073db0..782d9afed 100644 --- a/linphone/coreapi/linphonecore.c +++ b/linphone/coreapi/linphonecore.c @@ -776,32 +776,14 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE); return; } - if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN) { - if (lc->sip_conf.ipv6_enabled){ - ms_warning("stun support is not implemented for ipv6"); - }else{ - /* we no more use stun for sip socket*/ -#if 0 - int mport=0; - ms_message("doing stun lookup for local address..."); - if (stun_get_localip(lc,sock,linphone_core_get_sip_port(lc),result,&mport)){ - if (!lc->net_conf.nat_sdp_only) - eXosip_masquerade_contact(result,mport); - return; - } - ms_warning("stun lookup failed, falling back to a local interface..."); -#endif - } - - } + if (linphone_core_get_local_ip_for(dest,result)==0) + return; + /*else fallback to exosip routine that will attempt to find the most realistic interface */ if (eXosip_guess_localip(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE)<0){ /*default to something */ strncpy(result,lc->sip_conf.ipv6_enabled ? "::1" : "127.0.0.1",LINPHONE_IPADDR_SIZE); ms_error("Could not find default routable ip address !"); - } - /* - eXosip_masquerade_contact(NULL,0); - */ + } } const char *linphone_core_get_primary_contact(LinphoneCore *lc) @@ -1274,7 +1256,7 @@ void linphone_set_sdp(osip_message_t *sip, const char *sdpmesg){ osip_message_set_content_length(sip,clen); } -LinphoneProxyConfig * linphone_core_goes_through_known_proxy(LinphoneCore *lc, const char *uri){ +LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const char *uri){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; osip_from_t *parsed_uri; @@ -1292,13 +1274,36 @@ LinphoneProxyConfig * linphone_core_goes_through_known_proxy(LinphoneCore *lc, c return found_cfg; } -static void fix_contact(osip_message_t *msg, const char *localip){ +static void fix_contact(osip_message_t *msg, const char *localip, LinphoneProxyConfig *dest_proxy){ osip_contact_t *ctt=NULL; + const char *ip=NULL; + int port=5060; osip_message_get_contact(msg,0,&ctt); if (ctt!=NULL){ - osip_free(ctt->url->host); - ctt->url->host=osip_strdup(localip); + if (dest_proxy!=NULL){ + /* if we know the request will go to a known proxy for which we are registered, + we can use the same contact address as in the register */ + linphone_proxy_config_get_contact(dest_proxy,&ip,&port); + }else{ + ip=localip; + port=linphone_core_get_sip_port(dest_proxy->lc); + } + if (ip!=NULL){ + osip_free(ctt->url->host); + ctt->url->host=osip_strdup(ip); + } + if (port!=0){ + char tmp[10]={0}; + char *str; + snprintf(tmp,sizeof(tmp)-1,"%i",port); + if (ctt->url->port!=NULL) + osip_free(ctt->url->port); + ctt->url->port=osip_strdup(tmp); + osip_contact_to_str(ctt,&str); + ms_message("Contact has been fixed to %s",str); + osip_free(str); + } } } @@ -1315,6 +1320,7 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) osip_from_t *parsed_url2=NULL; osip_to_t *real_parsed_url=NULL; char *real_url=NULL; + LinphoneProxyConfig *dest_proxy=NULL; if (lc->call!=NULL){ lc->vtable.display_warning(lc,_("Sorry, having multiple simultaneous calls is not supported yet !")); @@ -1328,16 +1334,23 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); return -1; } - if (proxy!=NULL) { - from=linphone_proxy_config_get_identity(proxy); - + dest_proxy=linphone_core_lookup_known_proxy(lc,real_url); + + if (proxy!=dest_proxy && dest_proxy!=NULL) { + ms_message("Overriding default proxy setting for this call:"); + ms_message("The used identity will be %s",linphone_proxy_config_get_identity(dest_proxy)); } + + if (dest_proxy!=NULL) + from=linphone_proxy_config_get_identity(dest_proxy); + else if (proxy!=NULL) + from=linphone_proxy_config_get_identity(proxy); + /* if no proxy or no identity defined for this proxy, default to primary contact*/ if (from==NULL) from=linphone_core_get_primary_contact(lc); err=eXosip_call_build_initial_invite(&invite,real_url,from, route,"Phone call"); - if (err<0){ ms_warning("Could not build initial invite"); goto end; @@ -1352,7 +1365,7 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) /*try to be best-effort in giving real local or routable contact address, except when the user choosed to override the ipaddress */ if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) - fix_contact(invite,lc->call->localip); + fix_contact(invite,lc->call->localip,dest_proxy); barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); lc->vtable.display_status(lc,barmsg); @@ -1731,6 +1744,10 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) ms_error("Fail to build answer for call: err=%i",err); return -1; } + /*try to be best-effort in giving real local or routable contact address, + except when the user choosed to override the ipaddress */ + if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) + fix_contact(msg,call->localip,NULL); /*if a sdp answer is computed, send it, else send an offer */ sdpmesg=call->sdpctx->answerstr; if (sdpmesg==NULL){ diff --git a/linphone/coreapi/misc.c b/linphone/coreapi/misc.c index d58910d30..3b781185e 100644 --- a/linphone/coreapi/misc.c +++ b/linphone/coreapi/misc.c @@ -745,3 +745,58 @@ int linphone_core_wake_up_possible_already_running_instance( } return -1; } + +int linphone_core_get_local_ip_for(const char *dest, char *result){ + int err,tmp; + struct addrinfo hints; + struct addrinfo *res=NULL; + struct sockaddr_storage addr; + ortp_socket_t sock; +#ifdef __APPLE_CC__ + int s; +#else + socklen_t s; +#endif + memset(&hints,0,sizeof(hints)); + hints.ai_family=PF_UNSPEC; + hints.ai_socktype=SOCK_DGRAM; + /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/ + err=getaddrinfo(dest,"5060",&hints,&res); + if (err!=0){ + ms_error("getaddrinfo() error: %s",gai_strerror(err)); + return -1; + } + if (res==NULL){ + ms_error("bug: getaddrinfo returned nothing."); + return -1; + } + sock=socket(res->ai_family,SOCK_DGRAM,0); + tmp=1; + err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&tmp,sizeof(int)); + if (err<0){ + ms_warning("Error in setsockopt: %s",strerror(errno)); + } + err=connect(sock,res->ai_addr,res->ai_addrlen); + if (err<0) { + ms_error("Error in connect: %s",strerror(errno)); + freeaddrinfo(res); + close(sock); + return -1; + } + freeaddrinfo(res); + res=NULL; + s=sizeof(addr); + err=getsockname(sock,(struct sockaddr*)&addr,&s); + if (err!=0) { + ms_error("Error in getsockname: %s",strerror(errno)); + close(sock); + return -1; + } + err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST); + if (err!=0){ + ms_error("getnameinfo error: %s",strerror(errno)); + } + close(sock); + ms_message("Local interface to reach %s is %s.",dest,result); + return 0; +} diff --git a/linphone/coreapi/private.h b/linphone/coreapi/private.h index 88067899b..7e1b76c74 100644 --- a/linphone/coreapi/private.h +++ b/linphone/coreapi/private.h @@ -134,6 +134,7 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); void linphone_core_write_friends_config(LinphoneCore* lc); void linphone_proxy_config_update(LinphoneProxyConfig *cfg); void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port); - +LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const char *uri); +int linphone_core_get_local_ip_for(const char *dest, char *result); #endif /* _PRIVATE_H */