mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-02-07 14:18:25 +00:00
remove all getaddrinfo() blocking calls from coreapi.
Stun server is resolved asynchronously.
This commit is contained in:
parent
f8bc426a19
commit
573f530569
5 changed files with 126 additions and 37 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
121
coreapi/misc.c
121
coreapi/misc.c
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue