Commit 573f5305 authored by Simon Morlat's avatar Simon Morlat

remove all getaddrinfo() blocking calls from coreapi.

Stun server is resolved asynchronously.
parent f8bc426a
......@@ -840,3 +840,11 @@ void sal_enable_test_features(Sal*ctx, bool_t enabled){
ctx->enable_test_features=enabled;
}
unsigned long sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data){
return belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data);
}
void sal_resolve_cancel(Sal *sal, unsigned long id){
belle_sip_stack_resolve_cancel(sal->stack,id);
}
......@@ -4396,6 +4396,17 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){
if (server)
lc->net_conf.stun_server=ms_strdup(server);
else lc->net_conf.stun_server=NULL;
/* each time the stun server is changed, we must clean the resolved cached addrinfo*/
if (lc->net_conf.stun_addrinfo){
freeaddrinfo(lc->net_conf.stun_addrinfo);
lc->net_conf.stun_addrinfo=NULL;
}
/*if a stun server is set, we must request asynchronous resolution immediately to be ready for call*/
if (lc->net_conf.stun_server){
linphone_core_resolve_stun_server(lc);
}
if (linphone_core_ready(lc))
lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server);
}
......@@ -4404,6 +4415,7 @@ const char * linphone_core_get_stun_server(const LinphoneCore *lc){
return lc->net_conf.stun_server;
}
bool_t linphone_core_upnp_available(){
#ifdef BUILD_UPNP
return TRUE;
......@@ -4467,7 +4479,7 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc)
if (lc->net_conf.nat_address==NULL) return NULL;
if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len)<0) {
if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len, 5060)<0) {
return lc->net_conf.nat_address;
}
......@@ -5399,7 +5411,11 @@ void net_config_uninit(LinphoneCore *lc)
net_config_t *config=&lc->net_conf;
if (config->stun_server!=NULL){
ms_free(lc->net_conf.stun_server);
ms_free(config->stun_server);
}
if (config->stun_addrinfo){
freeaddrinfo(config->stun_addrinfo);
config->stun_addrinfo=NULL;
}
if (config->nat_address!=NULL){
lp_config_set_string(lc->config,"net","nat_address",config->nat_address);
......@@ -5677,6 +5693,8 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
if (!lc->network_reachable){
linphone_core_invalidate_friend_subscriptions(lc);
sal_reset_transports(lc->sal);
}else{
linphone_core_resolve_stun_server(lc);
}
#ifdef BUILD_UPNP
if(lc->upnp == NULL) {
......
......@@ -424,31 +424,38 @@ static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t ad
return 0;
}
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
struct addrinfo hints,*res=NULL;
int family = PF_INET;
int port_int = 3478;
int ret;
char port[6];
char host[NI_MAXHOST];
int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port){
char tmphost[NI_MAXHOST]={0};
char *p1, *p2;
if ((sscanf(server, "[%64[^]]]:%d", host, &port_int) == 2) || (sscanf(server, "[%64[^]]]", host) == 1)) {
family = PF_INET6;
if ((sscanf(input, "[%64[^]]]:%d", tmphost, port) == 2) || (sscanf(input, "[%64[^]]]", tmphost) == 1)) {
} else {
p1 = strchr(server, ':');
p2 = strrchr(server, ':');
if (p1 && p2 && (p1 != p2)) {
family = PF_INET6;
host[NI_MAXHOST-1]='\0';
strncpy(host, server, sizeof(host) - 1);
} else if (sscanf(server, "%[^:]:%d", host, &port_int) != 2) {
host[NI_MAXHOST-1]='\0';
strncpy(host, server, sizeof(host) - 1);
p1 = strchr(input, ':');
p2 = strrchr(input, ':');
if (p1 && p2 && (p1 != p2)) {/* an ipv6 address without port*/
strncpy(tmphost, input, sizeof(tmphost) - 1);
} else if (sscanf(input, "%[^:]:%d", tmphost, port) != 2) {
/*no port*/
strncpy(tmphost, input, sizeof(tmphost) - 1);
}
}
strncpy(host,tmphost,hostlen);
return 0;
}
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port){
struct addrinfo hints,*res=NULL;
char port[6];
char host[NI_MAXHOST];
int port_int=default_port;
int ret;
linphone_parse_host_port(server,host,sizeof(host),&port_int);
snprintf(port, sizeof(port), "%d", port_int);
memset(&hints,0,sizeof(hints));
hints.ai_family=family;
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_DGRAM;
hints.ai_protocol=IPPROTO_UDP;
ret=getaddrinfo(host,port,&hints,&res);
......@@ -495,8 +502,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
return -1;
}
if (server!=NULL){
struct sockaddr_storage ss;
socklen_t ss_len;
const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc);
ortp_socket_t sock1=-1, sock2=-1;
int loops=0;
bool_t video_enabled=linphone_core_video_enabled(lc);
......@@ -506,8 +512,8 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
double elapsed;
int ret=0;
if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
ms_error("Fail to parser stun server address: %s",server);
if (ai==NULL){
ms_error("Could not obtain stun server addrinfo.");
return -1;
}
if (lc->vtable.display_status!=NULL)
......@@ -528,11 +534,11 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
int id;
if (loops%20==0){
ms_message("Sending stun requests...");
sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,11,TRUE);
sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,1,FALSE);
if (sock2!=-1){
sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,22,TRUE);
sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,2,FALSE);
}
}
ms_usleep(10000);
......@@ -616,13 +622,60 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone
}
}
static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addrinfo *addrinfo){
if (lc->net_conf.stun_addrinfo){
freeaddrinfo(lc->net_conf.stun_addrinfo);
lc->net_conf.stun_addrinfo=NULL;
}
if (addrinfo){
ms_message("Stun server resolution successful.");
}else{
ms_warning("Stun server resolution failed.");
}
lc->net_conf.stun_addrinfo=addrinfo;
lc->net_conf.stun_res_id=0;
}
void linphone_core_resolve_stun_server(LinphoneCore *lc){
const char *server=lc->net_conf.stun_server;
if (lc->sal && server){
char host[NI_MAXHOST];
int port=3478;
linphone_parse_host_port(server,host,sizeof(host),&port);
lc->net_conf.stun_res_id=sal_resolve_a(lc->sal,host,port,AF_UNSPEC,(SalResolverCallback)stun_server_resolved,lc);
}
}
/*
* This function returns the addrinfo representation of the stun server address.
* It is critical not to block for a long time if it can't be resolved, otherwise this stucks the main thread when making a call.
* On the contrary, a fully asynchronous call initiation is complex to develop.
* The compromise is then:
* - have a cache of the stun server addrinfo
* - this cached value is returned when it is non-null
* - an asynchronous resolution is asked each time this function is called to ensure frequent refreshes of the cached value.
* - if no cached value exists, block for a short time; this case must be unprobable because the resolution will be asked each time the stun server value is
* changed.
**/
const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc){
const char *server=linphone_core_get_stun_server(lc);
if (server){
int wait_ms=0;
int wait_limit=1000;
linphone_core_resolve_stun_server(lc);
while (!lc->net_conf.stun_addrinfo && lc->net_conf.stun_res_id!=0 && wait_ms<wait_limit){
sal_iterate(lc->sal);
ms_usleep(50000);
wait_ms+=50;
}
}
return lc->net_conf.stun_addrinfo;
}
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
{
char local_addr[64];
struct sockaddr_storage ss;
socklen_t ss_len;
const struct addrinfo *ai;
IceCheckList *audio_check_list;
IceCheckList *video_check_list;
const char *server = linphone_core_get_stun_server(lc);
......@@ -636,16 +689,16 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
ms_warning("stun support is not implemented for ipv6");
return -1;
}
if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) {
ms_error("Fail to parser stun server address: %s", server);
ai=linphone_core_get_stun_server_addrinfo(lc);
if (ai==NULL){
ms_warning("Fail to resolve STUN server for ICE gathering.");
return -1;
}
if (lc->vtable.display_status != NULL)
lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
/* Gather local host candidates. */
if (linphone_core_get_local_ip_for(AF_INET, server, local_addr) < 0) {
if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
ms_error("Fail to get local ip");
return -1;
}
......@@ -663,7 +716,7 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
ms_message("ICE: gathering candidate from [%s]",server);
/* Gather local srflx candidates. */
ice_session_gather_candidates(call->ice_session, ss, ss_len);
ice_session_gather_candidates(call->ice_session, ai->ai_addr, ai->ai_addrlen);
return 0;
}
......
......@@ -255,7 +255,7 @@ LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf);
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen);
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port);
int set_lock_file();
int get_lock_file();
int remove_lock_file();
......@@ -307,6 +307,8 @@ void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt);
int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_resolve_stun_server(LinphoneCore *lc);
const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc);
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params);
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
......@@ -492,6 +494,8 @@ typedef struct net_config
char *nat_address; /* may be IP or host name */
char *nat_address_ip; /* ip translated from nat_address */
char *stun_server;
struct addrinfo *stun_addrinfo;
unsigned long stun_res_id;
char *relay;
int download_bw;
int upload_bw;
......
......@@ -58,6 +58,8 @@ struct SalCustomHeader;
typedef struct SalCustomHeader SalCustomHeader;
struct addrinfo;
typedef enum {
SalTransportUDP, /*UDP*/
SalTransportTCP, /*TCP*/
......@@ -596,6 +598,10 @@ SalPrivacy sal_op_get_privacy(const SalOp* op);
/*misc*/
void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen);
typedef void (*SalResolverCallback)(void *data, const char *name, struct addrinfo *ai_list);
unsigned long sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data);
void sal_resolve_cancel(Sal *sal, unsigned long id);
SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value);
const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment