Commit e2247611 authored by Ghislain MARY's avatar Ghislain MARY

Handle DNS SRV resolution of STUN server.

parent b6076942
......@@ -1154,6 +1154,10 @@ SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int fam
return (SalResolverContext*)belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data);
}
SalResolverContext * sal_resolve(Sal *sal, const char *service, const char *transport, const char *name, int port, int family, SalResolverCallback cb, void *data) {
return (SalResolverContext *)belle_sip_stack_resolve(sal->stack, service, transport, name, port, family, (belle_sip_resolver_callback_t)cb, data);
}
/*
void sal_resolve_cancel(Sal *sal, SalResolverContext* ctx){
belle_sip_stack_resolve_cancel(sal->stack,ctx);
......
......@@ -759,7 +759,7 @@ static void net_config_read (LinphoneCore *lc)
nat_policy_ref = lp_config_get_string(lc->config, "net", "nat_policy_ref", NULL);
if (nat_policy_ref != NULL) {
lc->nat_policy = linphone_nat_policy_new_from_config(lc->config, nat_policy_ref);
lc->nat_policy = linphone_core_create_nat_policy_from_config(lc, nat_policy_ref);
}
lc->net_conf.nat_address_ip = NULL;
......@@ -5073,31 +5073,18 @@ void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf)
linphone_call_send_dtmf(call, dtmf);
}
void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){
if (lc->net_conf.stun_server!=NULL)
ms_free(lc->net_conf.stun_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);
}
void linphone_core_set_stun_server(LinphoneCore *lc, const char *server) {
if (lc->nat_policy != NULL)
linphone_nat_policy_set_stun_server(lc->nat_policy, lc->net_conf.stun_server);
else if (linphone_core_ready(lc))
lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server);
linphone_nat_policy_set_stun_server(lc->nat_policy, server);
else
lp_config_set_string(lc->config, "net", "stun_server", server);
}
const char * linphone_core_get_stun_server(const LinphoneCore *lc){
return lc->net_conf.stun_server;
if (lc->nat_policy != NULL)
return linphone_nat_policy_get_stun_server(lc->nat_policy);
else
return lp_config_get_string(lc->config, "net", "stun_server", NULL);
}
......@@ -5173,7 +5160,7 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy
nat_policy = linphone_nat_policy_ref(lc->nat_policy);
linphone_nat_policy_clear(nat_policy);
} else {
nat_policy = linphone_nat_policy_new();
nat_policy = linphone_core_create_nat_policy(lc);
}
switch (pol) {
......@@ -6364,13 +6351,6 @@ void net_config_uninit(LinphoneCore *lc)
{
net_config_t *config=&lc->net_conf;
if (config->stun_server!=NULL){
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);
ms_free(lc->net_conf.nat_address);
......@@ -6381,7 +6361,7 @@ void net_config_uninit(LinphoneCore *lc)
lp_config_set_int(lc->config,"net","mtu",config->mtu);
if (lc->nat_policy != NULL) {
lp_config_set_string(lc->config, "net", "nat_policy_ref", lc->nat_policy->ref);
linphone_nat_policy_save_to_config(lc->nat_policy, lc->config);
linphone_nat_policy_save_to_config(lc->nat_policy);
}
}
......
......@@ -584,16 +584,20 @@ static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addr
}
void linphone_core_resolve_stun_server(LinphoneCore *lc){
/*
* WARNING: stun server resolution only done in IPv4.
* TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering.
*/
const char *server=lc->net_conf.stun_server;
if (lc->sal && server && !lc->net_conf.stun_res){
char host[NI_MAXHOST];
int port=3478;
linphone_parse_host_port(server,host,sizeof(host),&port);
lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_INET,(SalResolverCallback)stun_server_resolved,lc);
if (lc->nat_policy != NULL) {
linphone_nat_policy_resolve_stun_server(lc->nat_policy);
} else {
/*
* WARNING: stun server resolution only done in IPv4.
* TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering.
*/
const char *server=linphone_core_get_stun_server(lc);
if (lc->sal && server && !lc->net_conf.stun_res){
char host[NI_MAXHOST];
int port=3478;
linphone_parse_host_port(server,host,sizeof(host),&port);
lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_INET,(SalResolverCallback)stun_server_resolved,lc);
}
}
}
......@@ -609,18 +613,22 @@ void linphone_core_resolve_stun_server(LinphoneCore *lc){
* 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!=NULL && wait_ms<wait_limit){
sal_iterate(lc->sal);
ms_usleep(50000);
wait_ms+=50;
if (lc->nat_policy != NULL) {
return linphone_nat_policy_get_stun_server_addrinfo(lc->nat_policy);
} else {
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!=NULL && wait_ms<wait_limit){
sal_iterate(lc->sal);
ms_usleep(50000);
wait_ms+=50;
}
}
return lc->net_conf.stun_addrinfo;
}
return lc->net_conf.stun_addrinfo;
}
void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable) {
......
......@@ -21,11 +21,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "private.h"
static LinphoneNatPolicy * _linphone_nat_policy_new_with_ref(LinphoneCore *lc, const char *ref) {
LinphoneNatPolicy *policy = belle_sip_object_new(LinphoneNatPolicy);
belle_sip_object_ref(policy);
policy->lc = lc;
policy->ref = belle_sip_strdup(ref);
return policy;
}
static LinphoneNatPolicy * linphone_nat_policy_new(LinphoneCore *lc) {
char ref[17] = { 0 };
belle_sip_random_token(ref, 16);
return _linphone_nat_policy_new_with_ref(lc, ref);
}
static void linphone_nat_policy_destroy(LinphoneNatPolicy *policy) {
if (policy->ref) belle_sip_free(policy->ref);
if (policy->stun_server) belle_sip_free(policy->stun_server);
if (policy->stun_addrinfo) freeaddrinfo(policy->stun_addrinfo);
}
static bool_t linphone_nat_policy_stun_server_activated(LinphoneNatPolicy *policy) {
const char *server = linphone_nat_policy_get_stun_server(policy);
return (server != NULL) && (server[0] != '\0')
&& ((linphone_nat_policy_stun_enabled(policy) == TRUE) || (linphone_nat_policy_turn_enabled(policy) == TRUE));
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneNatPolicy);
......@@ -37,54 +59,6 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneNatPolicy, belle_sip_object_t,
);
static LinphoneNatPolicy * _linphone_nat_policy_new_with_ref(const char *ref) {
LinphoneNatPolicy *policy = belle_sip_object_new(LinphoneNatPolicy);
belle_sip_object_ref(policy);
policy->ref = belle_sip_strdup(ref);
return policy;
}
LinphoneNatPolicy * linphone_nat_policy_new(void) {
char ref[17] = { 0 };
belle_sip_random_token(ref, 16);
return _linphone_nat_policy_new_with_ref(ref);
}
LinphoneNatPolicy * linphone_nat_policy_new_from_config(LpConfig *config, const char *ref) {
LinphoneNatPolicy *policy = NULL;
char *section;
int index;
bool_t finished = FALSE;
for (index = 0; finished != TRUE; index++) {
section = belle_sip_strdup_printf("nat_policy_%i", index);
if (lp_config_has_section(config, section)) {
const char *config_ref = lp_config_get_string(config, section, "ref", NULL);
if ((config_ref != NULL) && (strcmp(config_ref, ref) == 0)) {
const char *server = lp_config_get_string(config, section, "stun_server", NULL);
MSList *l = lp_config_get_string_list(config, section, "protocols", NULL);
policy = _linphone_nat_policy_new_with_ref(ref);
if (server != NULL) linphone_nat_policy_set_stun_server(policy, server);
if (l != NULL) {
bool_t upnp_enabled = FALSE;
MSList *elem;
for (elem = l; elem != NULL; elem = elem->next) {
const char *value = (const char *)elem->data;
if (strcmp(value, "stun") == 0) linphone_nat_policy_enable_stun(policy, TRUE);
else if (strcmp(value, "turn") == 0) linphone_nat_policy_enable_turn(policy, TRUE);
else if (strcmp(value, "ice") == 0) linphone_nat_policy_enable_ice(policy, TRUE);
else if (strcmp(value, "upnp") == 0) upnp_enabled = TRUE;
}
if (upnp_enabled) linphone_nat_policy_enable_upnp(policy, TRUE);
}
finished = TRUE;
}
} else finished = TRUE;
belle_sip_free(section);
}
return policy;
}
static void _linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy, LpConfig *config, int index) {
char *section;
MSList *l = NULL;
......@@ -103,7 +77,8 @@ static void _linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy,
belle_sip_free(section);
}
void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy, LpConfig *config) {
void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy) {
LpConfig *config = policy->lc->config;
char *section;
int index;
bool_t finished = FALSE;
......@@ -195,11 +170,114 @@ const char * linphone_nat_policy_get_stun_server(const LinphoneNatPolicy *policy
}
void linphone_nat_policy_set_stun_server(LinphoneNatPolicy *policy, const char *stun_server) {
char *new_stun_server = NULL;
if (stun_server != NULL) new_stun_server = belle_sip_strdup(stun_server);
if (policy->stun_server != NULL) {
belle_sip_free(policy->stun_server);
policy->stun_server = NULL;
}
if (stun_server != NULL) {
policy->stun_server = belle_sip_strdup(stun_server);
if (new_stun_server != NULL) {
policy->stun_server = new_stun_server;
linphone_nat_policy_resolve_stun_server(policy);
}
}
static void stun_server_resolved(LinphoneNatPolicy *policy, const char *name, struct addrinfo *addrinfo) {
if (policy->stun_addrinfo) {
belle_sip_freeaddrinfo(policy->stun_addrinfo);
policy->stun_addrinfo = NULL;
}
if (addrinfo) {
ms_message("Stun server resolution successful.");
} else {
ms_warning("Stun server resolution failed.");
}
policy->stun_addrinfo = addrinfo;
policy->stun_resolver_context = NULL;
}
void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy *policy) {
const char *service = NULL;
/*
* WARNING: stun server resolution only done in IPv4.
* TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering.
*/
if (linphone_nat_policy_stun_server_activated(policy)
&& (policy->lc->sal != NULL)
&& !policy->stun_resolver_context) {
char host[NI_MAXHOST];
int port = 3478;
linphone_parse_host_port(policy->stun_server, host, sizeof(host), &port);
if (linphone_nat_policy_turn_enabled(policy)) service = "turn";
else if (linphone_nat_policy_stun_enabled(policy)) service = "stun";
if (service != NULL) {
policy->stun_resolver_context = sal_resolve(policy->lc->sal, service, "udp", host, port, AF_INET, (SalResolverCallback)stun_server_resolved, policy);
}
}
}
const struct addrinfo * linphone_nat_policy_get_stun_server_addrinfo(LinphoneNatPolicy *policy) {
/*
* 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.
*/
if (linphone_nat_policy_stun_server_activated(policy)) {
int wait_ms = 0;
int wait_limit = 1000;
linphone_nat_policy_resolve_stun_server(policy);
while ((policy->stun_addrinfo == NULL) && (policy->stun_resolver_context != NULL) && (wait_ms < wait_limit)) {
sal_iterate(policy->lc->sal);
ms_usleep(50000);
wait_ms += 50;
}
}
return policy->stun_addrinfo;
}
LinphoneNatPolicy * linphone_core_create_nat_policy(LinphoneCore *lc) {
return linphone_nat_policy_new(lc);
}
LinphoneNatPolicy * linphone_core_create_nat_policy_from_config(LinphoneCore *lc, const char *ref) {
LpConfig *config = lc->config;
LinphoneNatPolicy *policy = NULL;
char *section;
int index;
bool_t finished = FALSE;
for (index = 0; finished != TRUE; index++) {
section = belle_sip_strdup_printf("nat_policy_%i", index);
if (lp_config_has_section(config, section)) {
const char *config_ref = lp_config_get_string(config, section, "ref", NULL);
if ((config_ref != NULL) && (strcmp(config_ref, ref) == 0)) {
const char *server = lp_config_get_string(config, section, "stun_server", NULL);
MSList *l = lp_config_get_string_list(config, section, "protocols", NULL);
policy = _linphone_nat_policy_new_with_ref(lc, ref);
if (server != NULL) linphone_nat_policy_set_stun_server(policy, server);
if (l != NULL) {
bool_t upnp_enabled = FALSE;
MSList *elem;
for (elem = l; elem != NULL; elem = elem->next) {
const char *value = (const char *)elem->data;
if (strcmp(value, "stun") == 0) linphone_nat_policy_enable_stun(policy, TRUE);
else if (strcmp(value, "turn") == 0) linphone_nat_policy_enable_turn(policy, TRUE);
else if (strcmp(value, "ice") == 0) linphone_nat_policy_enable_ice(policy, TRUE);
else if (strcmp(value, "upnp") == 0) upnp_enabled = TRUE;
}
if (upnp_enabled) linphone_nat_policy_enable_upnp(policy, TRUE);
}
finished = TRUE;
}
} else finished = TRUE;
belle_sip_free(section);
}
return policy;
}
......@@ -37,12 +37,6 @@ extern "C" {
typedef struct _LinphoneNatPolicy LinphoneNatPolicy;
/**
* Create a new LinphoneNatPolicy object with every policies being disabled.
* @return A new LinphoneNatPolicy object.
*/
LINPHONE_PUBLIC LinphoneNatPolicy * linphone_nat_policy_new(void);
/**
* Acquire a reference to the LinphoneNatPolicy object.
* @param[in] policy LinphoneNatPolicy object.
......@@ -152,6 +146,35 @@ LINPHONE_PUBLIC const char * linphone_nat_policy_get_stun_server(const LinphoneN
*/
LINPHONE_PUBLIC void linphone_nat_policy_set_stun_server(LinphoneNatPolicy *policy, const char *stun_server);
/**
* Start a STUN server DNS resolution.
* @param[in] policy LinphoneNatPolicy object
*/
LINPHONE_PUBLIC void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy *policy);
/**
* Get the addrinfo representation of the STUN server address.
* WARNING: This function may block for up to 1 second.
* @param[in] policy LinphoneNatPolicy object
* @return addrinfo representation of the STUN server address.
*/
LINPHONE_PUBLIC const struct addrinfo * linphone_nat_policy_get_stun_server_addrinfo(LinphoneNatPolicy *policy);
/**
* Create a new LinphoneNatPolicy object with every policies being disabled.
* @param[in] lc LinphoneCore object
* @return A new LinphoneNatPolicy object.
*/
LINPHONE_PUBLIC LinphoneNatPolicy * linphone_core_create_nat_policy(LinphoneCore *lc);
/**
* Create a new LinphoneNatPolicy by reading the config of a LinphoneCore according to the passed ref.
* @param[in] lc LinphoneCore object
* @param[in] ref The reference of a NAT policy in the config of the LinphoneCore
* @return A new LinphoneNatPolicy object.
*/
LINPHONE_PUBLIC LinphoneNatPolicy * linphone_core_create_nat_policy_from_config(LinphoneCore *lc, const char *ref);
/**
* @}
*/
......
......@@ -437,6 +437,7 @@ LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, Li
LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc);
LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_import_friend(LinphoneFriendList *list, LinphoneFriend *lf, bool_t synchronize);
int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port);
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port);
bool_t host_has_ipv6_network(void);
......@@ -799,7 +800,6 @@ 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;
SalResolverContext * stun_res;
int download_bw;
......@@ -1190,6 +1190,9 @@ BELLE_SIP_DECLARE_VPTR(LinphoneBuffer);
struct _LinphoneNatPolicy {
belle_sip_object_t base;
void *user_data;
LinphoneCore *lc;
SalResolverContext *stun_resolver_context;
struct addrinfo *stun_addrinfo;
char *stun_server;
char *ref;
bool_t stun_enabled;
......@@ -1200,8 +1203,7 @@ struct _LinphoneNatPolicy {
BELLE_SIP_DECLARE_VPTR(LinphoneNatPolicy);
LinphoneNatPolicy * linphone_nat_policy_new_from_config(LpConfig *config, const char *ref);
void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy, LpConfig *config);
void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy);
/*****************************************************************************
......
......@@ -1358,7 +1358,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
if (cfg->nat_policy != NULL) {
lp_config_set_string(config, key, "nat_policy_ref", cfg->nat_policy->ref);
linphone_nat_policy_save_to_config(cfg->nat_policy, config);
linphone_nat_policy_save_to_config(cfg->nat_policy);
}
}
......@@ -1423,7 +1423,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc
nat_policy_ref = lp_config_get_string(config, key, "nat_policy_ref", NULL);
if (nat_policy_ref != NULL) {
cfg->nat_policy = linphone_nat_policy_new_from_config(config, nat_policy_ref);
cfg->nat_policy = linphone_core_create_nat_policy_from_config(lc, nat_policy_ref);
}
return cfg;
......
......@@ -807,6 +807,7 @@ typedef void (*SalResolverCallback)(void *data, const char *name, struct addrinf
typedef struct SalResolverContext SalResolverContext;
LINPHONE_PUBLIC SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data);
LINPHONE_PUBLIC SalResolverContext * sal_resolve(Sal *sal, const char *service, const char *transport, const char *name, int port, int family, SalResolverCallback cb, void *data);
//void sal_resolve_cancel(Sal *sal, SalResolverContext *ctx);
SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value);
......
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