forked from mirrors/linphone-iphone
Merge branch 'dev_turn'
This commit is contained in:
commit
22df29159f
20 changed files with 1076 additions and 254 deletions
|
|
@ -48,6 +48,7 @@ set(LINPHONE_HEADER_FILES
|
|||
linphone_tunnel.h
|
||||
lpc2xml.h
|
||||
lpconfig.h
|
||||
nat_policy.h
|
||||
ringtoneplayer.h
|
||||
sipsetup.h
|
||||
sqlite3_bctbx_vfs.h
|
||||
|
|
@ -102,6 +103,7 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
lsd.c
|
||||
message_storage.c
|
||||
misc.c
|
||||
nat_policy.c
|
||||
offeranswer.c
|
||||
offeranswer.h
|
||||
player.c
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ linphone_include_HEADERS=\
|
|||
linphone_tunnel.h \
|
||||
lpc2xml.h \
|
||||
lpconfig.h \
|
||||
nat_policy.h \
|
||||
sipsetup.h \
|
||||
sqlite3_bctbx_vfs.h \
|
||||
xml2lpc.h \
|
||||
|
|
@ -81,6 +82,7 @@ liblinphone_la_SOURCES=\
|
|||
lsd.c \
|
||||
message_storage.c \
|
||||
misc.c \
|
||||
nat_policy.c \
|
||||
offeranswer.c offeranswer.h\
|
||||
player.c \
|
||||
presence.c \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -547,6 +547,24 @@ LINPHONE_PUBLIC const char * linphone_proxy_config_get_ref_key(const LinphonePro
|
|||
**/
|
||||
LINPHONE_PUBLIC void linphone_proxy_config_set_ref_key(LinphoneProxyConfig *cfg, const char *refkey);
|
||||
|
||||
/**
|
||||
* Get The policy that is used to pass through NATs/firewalls when using this proxy config.
|
||||
* If it is set to NULL, the default NAT policy from the core will be used instead.
|
||||
* @param[in] cfg #LinphoneProxyConfig object
|
||||
* @return LinphoneNatPolicy object in use.
|
||||
* @see linphone_core_get_nat_policy()
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneNatPolicy * linphone_proxy_config_get_nat_policy(const LinphoneProxyConfig *cfg);
|
||||
|
||||
/**
|
||||
* Set the policy to use to pass through NATs/firewalls when using this proxy config.
|
||||
* If it is set to NULL, the default NAT policy from the core will be used instead.
|
||||
* @param[in] cfg #LinphoneProxyConfig object
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @see linphone_core_set_nat_policy()
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_proxy_config_set_nat_policy(LinphoneProxyConfig *cfg, LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1311,7 +1311,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, const SalM
|
|||
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
|
||||
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
|
||||
SalMediaDescription *md;
|
||||
LinphoneFirewallPolicy fpol;
|
||||
LinphoneNatPolicy *nat_policy = NULL;
|
||||
int i;
|
||||
|
||||
call->dir=LinphoneCallIncoming;
|
||||
|
|
@ -1386,28 +1386,26 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
|
|||
}
|
||||
}
|
||||
|
||||
fpol=linphone_core_get_firewall_policy(call->core);
|
||||
/*create the ice session now if ICE is required*/
|
||||
if (fpol==LinphonePolicyUseIce){
|
||||
if (call->dest_proxy != NULL) nat_policy = linphone_proxy_config_get_nat_policy(call->dest_proxy);
|
||||
if (nat_policy == NULL) nat_policy = linphone_core_get_nat_policy(call->core);
|
||||
if ((nat_policy != NULL) && linphone_nat_policy_ice_enabled(nat_policy)) {
|
||||
/* Create the ice session now if ICE is required */
|
||||
if (md){
|
||||
linphone_call_create_ice_session(call, IR_Controlled);
|
||||
}else{
|
||||
fpol=LinphonePolicyNoFirewall;
|
||||
nat_policy = NULL;
|
||||
ms_warning("ICE not supported for incoming INVITE without SDP.");
|
||||
}
|
||||
}
|
||||
|
||||
/*reserve the sockets immediately*/
|
||||
linphone_call_init_media_streams(call);
|
||||
switch (fpol) {
|
||||
case LinphonePolicyUseIce:
|
||||
if (nat_policy != NULL) {
|
||||
if (linphone_nat_policy_ice_enabled(nat_policy)) {
|
||||
call->defer_notify_incoming = linphone_call_prepare_ice(call,TRUE) == 1;
|
||||
break;
|
||||
case LinphonePolicyUseStun:
|
||||
} else if (linphone_nat_policy_stun_enabled(nat_policy)) {
|
||||
call->ping_time=linphone_core_run_stun_tests(call->core,call);
|
||||
/* No break to also destroy ice session in this case. */
|
||||
break;
|
||||
case LinphonePolicyUseUpnp:
|
||||
} else if (linphone_nat_policy_upnp_enabled(nat_policy)) {
|
||||
#ifdef BUILD_UPNP
|
||||
if(!lc->rtp_conf.disable_upnp) {
|
||||
call->upnp_session = linphone_upnp_session_new(call);
|
||||
|
|
@ -1419,9 +1417,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
|
|||
}
|
||||
}
|
||||
#endif //BUILD_UPNP
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
discover_mtu(lc,linphone_address_get_domain(from));
|
||||
|
|
@ -1438,11 +1434,11 @@ void linphone_call_free_media_resources(LinphoneCall *call){
|
|||
int i;
|
||||
|
||||
linphone_call_stop_media_streams(call);
|
||||
linphone_call_delete_upnp_session(call);
|
||||
linphone_call_delete_ice_session(call);
|
||||
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
|
||||
ms_media_stream_sessions_uninit(&call->sessions[i]);
|
||||
}
|
||||
linphone_call_delete_upnp_session(call);
|
||||
linphone_call_delete_ice_session(call);
|
||||
linphone_call_stats_uninit(&call->stats[LINPHONE_CALL_STATS_AUDIO]);
|
||||
linphone_call_stats_uninit(&call->stats[LINPHONE_CALL_STATS_VIDEO]);
|
||||
linphone_call_stats_uninit(&call->stats[LINPHONE_CALL_STATS_TEXT]);
|
||||
|
|
@ -2466,13 +2462,15 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
|
|||
|
||||
/* init zrtp even if we didn't explicitely set it, just in case peer offers it */
|
||||
if (ms_zrtp_available()) {
|
||||
char *uri = linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to);
|
||||
MSZrtpParams params;
|
||||
memset(¶ms,0,sizeof(MSZrtpParams));
|
||||
/*call->current_params.media_encryption will be set later when zrtp is activated*/
|
||||
params.zid_file=lc->zrtp_secrets_cache;
|
||||
params.uri= linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to);
|
||||
params.uri=uri;
|
||||
setZrtpCryptoTypesParameters(¶ms,call->core);
|
||||
audio_stream_enable_zrtp(call->audiostream,¶ms);
|
||||
if (uri != NULL) ms_free(uri);
|
||||
}
|
||||
|
||||
media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[call->main_audio_stream_index]);
|
||||
|
|
|
|||
|
|
@ -759,13 +759,22 @@ static void net_config_read (LinphoneCore *lc)
|
|||
int tmp;
|
||||
const char *tmpstr;
|
||||
LpConfig *config=lc->config;
|
||||
const char *nat_policy_ref;
|
||||
|
||||
nat_policy_ref = lp_config_get_string(lc->config, "net", "nat_policy_ref", NULL);
|
||||
if (nat_policy_ref != NULL) {
|
||||
lc->nat_policy = linphone_core_create_nat_policy_from_config(lc, nat_policy_ref);
|
||||
}
|
||||
|
||||
lc->net_conf.nat_address_ip = NULL;
|
||||
tmp=lp_config_get_int(config,"net","download_bw",0);
|
||||
linphone_core_set_download_bandwidth(lc,tmp);
|
||||
tmp=lp_config_get_int(config,"net","upload_bw",0);
|
||||
linphone_core_set_upload_bandwidth(lc,tmp);
|
||||
linphone_core_set_stun_server(lc,lp_config_get_string(config,"net","stun_server",NULL));
|
||||
if (lc->nat_policy == NULL) /* For compatibility, now the STUN server is stored in the NAT policy. */
|
||||
linphone_core_set_stun_server(lc,lp_config_get_string(config,"net","stun_server",NULL));
|
||||
else
|
||||
linphone_core_set_stun_server(lc, linphone_nat_policy_get_stun_server(lc->nat_policy));
|
||||
tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL);
|
||||
if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL;
|
||||
linphone_core_set_nat_address(lc,tmpstr);
|
||||
|
|
@ -782,7 +791,8 @@ static void net_config_read (LinphoneCore *lc)
|
|||
linphone_core_enable_dns_srv(lc, tmp);
|
||||
|
||||
/* This is to filter out unsupported firewall policies */
|
||||
linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc));
|
||||
if (nat_policy_ref == NULL)
|
||||
linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc));
|
||||
}
|
||||
|
||||
static void build_sound_devices_table(LinphoneCore *lc){
|
||||
|
|
@ -5103,29 +5113,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);
|
||||
}
|
||||
|
||||
if (linphone_core_ready(lc))
|
||||
lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server);
|
||||
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, 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -5194,66 +5193,71 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc)
|
|||
return lc->net_conf.nat_address_ip;
|
||||
}
|
||||
|
||||
void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){
|
||||
const char *policy = "none";
|
||||
void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol) {
|
||||
LinphoneNatPolicy *nat_policy;
|
||||
char *stun_server = NULL;
|
||||
char *stun_server_username = NULL;
|
||||
|
||||
if (lc->nat_policy != NULL) {
|
||||
nat_policy = linphone_nat_policy_ref(lc->nat_policy);
|
||||
stun_server = ms_strdup(linphone_nat_policy_get_stun_server(nat_policy));
|
||||
stun_server_username = ms_strdup(linphone_nat_policy_get_stun_server_username(nat_policy));
|
||||
linphone_nat_policy_clear(nat_policy);
|
||||
} else {
|
||||
nat_policy = linphone_core_create_nat_policy(lc);
|
||||
stun_server = ms_strdup(linphone_core_get_stun_server(lc));
|
||||
}
|
||||
|
||||
switch (pol) {
|
||||
default:
|
||||
case LinphonePolicyNoFirewall:
|
||||
policy = "none";
|
||||
break;
|
||||
case LinphonePolicyUseNatAddress:
|
||||
policy = "nat_address";
|
||||
break;
|
||||
case LinphonePolicyUseStun:
|
||||
policy = "stun";
|
||||
linphone_nat_policy_enable_stun(nat_policy, TRUE);
|
||||
break;
|
||||
case LinphonePolicyUseIce:
|
||||
policy = "ice";
|
||||
linphone_nat_policy_enable_ice(nat_policy, TRUE);
|
||||
linphone_nat_policy_enable_stun(nat_policy, TRUE);
|
||||
break;
|
||||
case LinphonePolicyUseUpnp:
|
||||
#ifdef BUILD_UPNP
|
||||
policy = "upnp";
|
||||
linphone_nat_policy_enable_upnp(nat_policy);
|
||||
#else
|
||||
ms_warning("UPNP is not available, reset firewall policy to no firewall");
|
||||
pol = LinphonePolicyNoFirewall;
|
||||
policy = "none";
|
||||
#endif //BUILD_UPNP
|
||||
break;
|
||||
}
|
||||
#ifdef BUILD_UPNP
|
||||
if(pol == LinphonePolicyUseUpnp) {
|
||||
if(lc->upnp == NULL) {
|
||||
lc->upnp = linphone_upnp_context_new(lc);
|
||||
}
|
||||
} else {
|
||||
if(lc->upnp != NULL) {
|
||||
linphone_upnp_context_destroy(lc->upnp);
|
||||
lc->upnp = NULL;
|
||||
}
|
||||
|
||||
if (stun_server_username != NULL) {
|
||||
linphone_nat_policy_set_stun_server_username(nat_policy, stun_server_username);
|
||||
ms_free(stun_server_username);
|
||||
}
|
||||
linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
|
||||
#endif //BUILD_UPNP
|
||||
switch(pol) {
|
||||
case LinphonePolicyUseUpnp:
|
||||
sal_nat_helper_enable(lc->sal, FALSE);
|
||||
sal_enable_auto_contacts(lc->sal,FALSE);
|
||||
sal_use_rport(lc->sal, FALSE);
|
||||
break;
|
||||
default:
|
||||
sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config,"net","enable_nat_helper",1));
|
||||
sal_enable_auto_contacts(lc->sal,TRUE);
|
||||
sal_use_rport(lc->sal, lp_config_get_int(lc->config,"sip","use_rport",1));
|
||||
break;
|
||||
if (stun_server != NULL) {
|
||||
linphone_nat_policy_set_stun_server(nat_policy, stun_server);
|
||||
ms_free(stun_server);
|
||||
}
|
||||
if (lc->sip_conf.contact) update_primary_contact(lc);
|
||||
if (linphone_core_ready(lc))
|
||||
lp_config_set_string(lc->config,"net","firewall_policy",policy);
|
||||
linphone_core_set_nat_policy(lc, nat_policy);
|
||||
linphone_nat_policy_unref(nat_policy);
|
||||
}
|
||||
LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){
|
||||
|
||||
LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc) {
|
||||
const char *policy;
|
||||
|
||||
policy = lp_config_get_string(lc->config, "net", "firewall_policy", NULL);
|
||||
if ((policy == NULL) || (strcmp(policy, "0") == 0))
|
||||
if (policy == NULL) {
|
||||
LinphoneNatPolicy *nat_policy = linphone_core_get_nat_policy(lc);
|
||||
if (nat_policy == NULL) {
|
||||
return LinphonePolicyNoFirewall;
|
||||
} else if (linphone_nat_policy_upnp_enabled(nat_policy))
|
||||
return LinphonePolicyUseUpnp;
|
||||
else if (linphone_nat_policy_ice_enabled(nat_policy))
|
||||
return LinphonePolicyUseIce;
|
||||
else if (linphone_nat_policy_stun_enabled(nat_policy))
|
||||
return LinphonePolicyUseStun;
|
||||
else
|
||||
return LinphonePolicyNoFirewall;
|
||||
} else if (strcmp(policy, "0") == 0)
|
||||
return LinphonePolicyNoFirewall;
|
||||
else if ((strcmp(policy, "nat_address") == 0) || (strcmp(policy, "1") == 0))
|
||||
return LinphonePolicyUseNatAddress;
|
||||
|
|
@ -5267,6 +5271,38 @@ LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc)
|
|||
return LinphonePolicyNoFirewall;
|
||||
}
|
||||
|
||||
void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy) {
|
||||
if (policy != NULL) policy = linphone_nat_policy_ref(policy); /* Prevent object destruction if the same policy is used */
|
||||
if (lc->nat_policy != NULL) linphone_nat_policy_unref(lc->nat_policy);
|
||||
if (policy != NULL) lc->nat_policy = policy;
|
||||
|
||||
#ifdef BUILD_UPNP
|
||||
linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
|
||||
if (linphone_nat_policy_upnp_enabled(policy)) {
|
||||
if (lc->upnp == NULL) {
|
||||
lc->upnp = linphone_upnp_context_new(lc);
|
||||
}
|
||||
sal_nat_helper_enable(lc->sal, FALSE);
|
||||
sal_enable_auto_contacts(lc->sal, FALSE);
|
||||
sal_use_rport(lc->sal, FALSE);
|
||||
} else {
|
||||
if (lc->upnp != NULL) {
|
||||
linphone_upnp_context_destroy(lc->upnp);
|
||||
lc->upnp = NULL;
|
||||
}
|
||||
#endif
|
||||
sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config, "net", "enable_nat_helper", 1));
|
||||
sal_enable_auto_contacts(lc->sal, TRUE);
|
||||
sal_use_rport(lc->sal, lp_config_get_int(lc->config, "sip", "use_rport", 1));
|
||||
if (lc->sip_conf.contact) update_primary_contact(lc);
|
||||
#ifdef BUILD_UPNP
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
LinphoneNatPolicy * linphone_core_get_nat_policy(const LinphoneCore *lc) {
|
||||
return lc->nat_policy;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
@ -6367,13 +6403,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);
|
||||
|
|
@ -6382,6 +6411,12 @@ void net_config_uninit(LinphoneCore *lc)
|
|||
ms_free(lc->net_conf.nat_address_ip);
|
||||
}
|
||||
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);
|
||||
linphone_nat_policy_unref(lc->nat_policy);
|
||||
lc->nat_policy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -406,6 +406,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
|
|||
#include "content.h"
|
||||
#include "event.h"
|
||||
#include "linphonefriend.h"
|
||||
#include "nat_policy.h"
|
||||
#include "xmlrpc.h"
|
||||
#include "conference.h"
|
||||
#else
|
||||
|
|
@ -415,6 +416,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
|
|||
#include "linphone/content.h"
|
||||
#include "linphone/event.h"
|
||||
#include "linphone/linphonefriend.h"
|
||||
#include "linphone/nat_policy.h"
|
||||
#include "linphone/xmlrpc.h"
|
||||
#include "linphone/conference.h"
|
||||
#endif
|
||||
|
|
@ -2188,6 +2190,7 @@ typedef struct _LCCallbackObj
|
|||
/**
|
||||
* Policy to use to pass through firewalls.
|
||||
* @ingroup network_parameters
|
||||
* @deprecated Use LinphoneNatPolicy instead
|
||||
**/
|
||||
typedef enum _LinphoneFirewallPolicy {
|
||||
LinphonePolicyNoFirewall, /**< Do not use any mechanism to pass through firewalls */
|
||||
|
|
@ -3186,6 +3189,7 @@ LINPHONE_PUBLIC const char *linphone_core_get_nat_address(const LinphoneCore *lc
|
|||
* @param[in] lc #LinphoneCore object.
|
||||
* @param[in] pol The #LinphoneFirewallPolicy to use.
|
||||
* @ingroup network_parameters
|
||||
* @deprecated Use linphone_core_set_nat_policy() instead.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol);
|
||||
|
||||
|
|
@ -3194,9 +3198,30 @@ LINPHONE_PUBLIC void linphone_core_set_firewall_policy(LinphoneCore *lc, Linphon
|
|||
* @param[in] lc #LinphoneCore object.
|
||||
* @return The #LinphoneFirewallPolicy that is being used.
|
||||
* @ingroup network_parameters
|
||||
* @deprecated Use linphone_core_get_nat_policy() instead.
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Set the policy to use to pass through NATs/firewalls.
|
||||
* It may be overridden by a NAT policy for a specific proxy config.
|
||||
* @param[in] lc #LinphoneCore object
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @ingroup network_parameters
|
||||
* @see linphone_proxy_config_set_nat_policy()
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Get The policy that is used to pass through NATs/firewalls.
|
||||
* It may be overridden by a NAT policy for a specific proxy config.
|
||||
* @param[in] lc #LinphoneCore object
|
||||
* @return LinphoneNatPolicy object in use.
|
||||
* @ingroup network_parameters
|
||||
* @see linphone_proxy_config_get_nat_policy()
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneNatPolicy * linphone_core_get_nat_policy(const LinphoneCore *lc);
|
||||
|
||||
/* sound functions */
|
||||
/* returns a null terminated static array of string describing the sound devices */
|
||||
LINPHONE_PUBLIC const char** linphone_core_get_sound_devices(LinphoneCore *lc);
|
||||
|
|
|
|||
|
|
@ -530,6 +530,31 @@ const char *lp_config_get_string(const LpConfig *lpconfig, const char *section,
|
|||
return default_string;
|
||||
}
|
||||
|
||||
MSList * lp_config_get_string_list(const LpConfig *lpconfig, const char *section, const char *key, MSList *default_list) {
|
||||
LpItem *item;
|
||||
LpSection *sec = lp_config_find_section(lpconfig, section);
|
||||
if (sec != NULL) {
|
||||
item = lp_section_find_item(sec, key);
|
||||
if (item != NULL) {
|
||||
MSList *l = NULL;
|
||||
char *str;
|
||||
char *ptr;
|
||||
str = ptr = ms_strdup(item->value);
|
||||
while (ptr != NULL) {
|
||||
char *next = strstr(ptr, ",");
|
||||
if (next != NULL) {
|
||||
*(next++) = '\0';
|
||||
}
|
||||
l = ms_list_append(l, ms_strdup(ptr));
|
||||
ptr = next;
|
||||
}
|
||||
ms_free(str);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
return default_list;
|
||||
}
|
||||
|
||||
bool_t lp_config_get_range(const LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max) {
|
||||
const char *str = lp_config_get_string(lpconfig, section, key, NULL);
|
||||
if (str != NULL) {
|
||||
|
|
@ -645,6 +670,22 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke
|
|||
lpconfig->modified++;
|
||||
}
|
||||
|
||||
void lp_config_set_string_list(LpConfig *lpconfig, const char *section, const char *key, const MSList *value) {
|
||||
char *strvalue = NULL;
|
||||
char *tmp = NULL;
|
||||
const MSList *elem;
|
||||
for (elem = value; elem != NULL; elem = elem->next) {
|
||||
if (strvalue) {
|
||||
tmp = ms_strdup_printf("%s,%s", strvalue, (const char *)elem->data);
|
||||
ms_free(strvalue);
|
||||
strvalue = tmp;
|
||||
}
|
||||
else strvalue = ms_strdup((const char *)elem->data);
|
||||
}
|
||||
lp_config_set_string(lpconfig, section, key, strvalue);
|
||||
if (strvalue) ms_free(strvalue);
|
||||
}
|
||||
|
||||
void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value) {
|
||||
char tmp[30];
|
||||
snprintf(tmp, sizeof(tmp), "%i-%i", min_value, max_value);
|
||||
|
|
|
|||
|
|
@ -104,6 +104,13 @@ LINPHONE_PUBLIC int lp_config_read_file(LpConfig *lpconfig, const char *filename
|
|||
**/
|
||||
LINPHONE_PUBLIC const char *lp_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string);
|
||||
|
||||
/**
|
||||
* Retrieves a configuration item as a list of strings, given its section, key, and default value.
|
||||
* @ingroup misc
|
||||
* The default value is returned if the config item isn't found.
|
||||
*/
|
||||
LINPHONE_PUBLIC MSList * lp_config_get_string_list(const LpConfig *lpconfig, const char *section, const char *key, MSList *default_list);
|
||||
|
||||
/**
|
||||
* Retrieves a configuration item as a range, given its section, key, and default min and max values.
|
||||
*
|
||||
|
|
@ -144,6 +151,12 @@ LINPHONE_PUBLIC float lp_config_get_float(const LpConfig *lpconfig,const char *s
|
|||
**/
|
||||
LINPHONE_PUBLIC void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value);
|
||||
|
||||
/**
|
||||
* Sets a string list config item
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void lp_config_set_string_list(LpConfig *lpconfig, const char *section, const char *key, const MSList *value);
|
||||
|
||||
/**
|
||||
* Sets a range config item
|
||||
*
|
||||
|
|
|
|||
281
coreapi/misc.c
281
coreapi/misc.c
|
|
@ -317,28 +317,30 @@ static ortp_socket_t create_socket(int local_port){
|
|||
return sock;
|
||||
}
|
||||
|
||||
static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
|
||||
char buf[STUN_MAX_MESSAGE_SIZE];
|
||||
int len = STUN_MAX_MESSAGE_SIZE;
|
||||
StunAtrString username;
|
||||
StunAtrString password;
|
||||
StunMessage req;
|
||||
int err;
|
||||
memset(&req, 0, sizeof(StunMessage));
|
||||
memset(&username,0,sizeof(username));
|
||||
memset(&password,0,sizeof(password));
|
||||
stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
|
||||
len = stunEncodeMessage( &req, buf, len, &password);
|
||||
if (len<=0){
|
||||
static int send_stun_request(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t change_addr){
|
||||
char *buf = NULL;
|
||||
int len;
|
||||
int err = 0;
|
||||
MSStunMessage *req = ms_stun_binding_request_create();
|
||||
UInt96 tr_id = ms_stun_message_get_tr_id(req);
|
||||
tr_id.octet[0] = id;
|
||||
ms_stun_message_set_tr_id(req, tr_id);
|
||||
ms_stun_message_enable_change_ip(req, change_addr);
|
||||
ms_stun_message_enable_change_port(req, change_addr);
|
||||
len = ms_stun_message_encode(req, &buf);
|
||||
if (len <= 0) {
|
||||
ms_error("Fail to encode stun message.");
|
||||
return -1;
|
||||
err = -1;
|
||||
} else {
|
||||
err = sendto(sock, buf, len, 0, server, addrlen);
|
||||
if (err < 0) {
|
||||
ms_error("sendto failed: %s",strerror(errno));
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
err=sendto(sock,buf,len,0,server,addrlen);
|
||||
if (err<0){
|
||||
ms_error("sendto failed: %s",strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
if (buf != NULL) ms_free(buf);
|
||||
ms_free(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port){
|
||||
|
|
@ -387,23 +389,32 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
|
||||
char buf[STUN_MAX_MESSAGE_SIZE];
|
||||
int len = STUN_MAX_MESSAGE_SIZE;
|
||||
StunMessage resp;
|
||||
len=recv(sock,buf,len,0);
|
||||
if (len>0){
|
||||
static int recv_stun_response(ortp_socket_t sock, char *ipaddr, int *port, int *id) {
|
||||
char buf[MS_STUN_MAX_MESSAGE_SIZE];
|
||||
int len = MS_STUN_MAX_MESSAGE_SIZE;
|
||||
MSStunMessage *resp;
|
||||
|
||||
len = recv(sock, buf, len, 0);
|
||||
if (len > 0) {
|
||||
struct in_addr ia;
|
||||
stunParseMessage(buf,len, &resp );
|
||||
*id=resp.msgHdr.tr_id.octet[0];
|
||||
if (resp.hasXorMappedAddress){
|
||||
*port = resp.xorMappedAddress.ipv4.port;
|
||||
ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
|
||||
}else if (resp.hasMappedAddress){
|
||||
*port = resp.mappedAddress.ipv4.port;
|
||||
ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
|
||||
}else return -1;
|
||||
strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
|
||||
resp = ms_stun_message_create_from_buffer_parsing((uint8_t *)buf, len);
|
||||
if (resp != NULL) {
|
||||
const MSStunAddress *stun_addr;
|
||||
UInt96 tr_id = ms_stun_message_get_tr_id(resp);
|
||||
*id = tr_id.octet[0];
|
||||
stun_addr = ms_stun_message_get_xor_mapped_address(resp);
|
||||
if (stun_addr != NULL) {
|
||||
*port = stun_addr->ip.v4.port;
|
||||
ia.s_addr = htonl(stun_addr->ip.v4.addr);
|
||||
} else {
|
||||
stun_addr = ms_stun_message_get_mapped_address(resp);
|
||||
if (stun_addr != NULL) {
|
||||
*port = stun_addr->ip.v4.port;
|
||||
ia.s_addr = htonl(stun_addr->ip.v4.addr);
|
||||
} else len = -1;
|
||||
}
|
||||
if (len > 0) strncpy(ipaddr, inet_ntoa(ia), LINPHONE_IPADDR_SIZE);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
|
@ -459,44 +470,32 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
|
|||
int id;
|
||||
if (loops%20==0){
|
||||
ms_message("Sending stun requests...");
|
||||
sendStunRequest((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,11,TRUE);
|
||||
sendStunRequest((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,1,FALSE);
|
||||
send_stun_request((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,11,TRUE);
|
||||
send_stun_request((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,1,FALSE);
|
||||
if (sock2!=-1){
|
||||
sendStunRequest((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,22,TRUE);
|
||||
sendStunRequest((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,2,FALSE);
|
||||
send_stun_request((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,22,TRUE);
|
||||
send_stun_request((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,2,FALSE);
|
||||
}
|
||||
if (sock3!=-1){
|
||||
sendStunRequest((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,33,TRUE);
|
||||
sendStunRequest((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,3,FALSE);
|
||||
send_stun_request((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,33,TRUE);
|
||||
send_stun_request((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,3,FALSE);
|
||||
}
|
||||
}
|
||||
ms_usleep(10000);
|
||||
|
||||
if (recvStunResponse(sock1,ac->addr,
|
||||
&ac->port,&id)>0){
|
||||
ms_message("STUN test result: local audio port maps to %s:%i",
|
||||
ac->addr,
|
||||
ac->port);
|
||||
if (id==11)
|
||||
cone_audio=TRUE;
|
||||
if (recv_stun_response(sock1, ac->addr, &ac->port, &id) > 0) {
|
||||
ms_message("STUN test result: local audio port maps to %s:%i", ac->addr, ac->port);
|
||||
if (id==11) cone_audio=TRUE;
|
||||
got_audio=TRUE;
|
||||
}
|
||||
if (recvStunResponse(sock2,vc->addr,
|
||||
&vc->port,&id)>0){
|
||||
ms_message("STUN test result: local video port maps to %s:%i",
|
||||
vc->addr,
|
||||
vc->port);
|
||||
if (id==22)
|
||||
cone_video=TRUE;
|
||||
if (recv_stun_response(sock2, vc->addr, &vc->port, &id) > 0) {
|
||||
ms_message("STUN test result: local video port maps to %s:%i", vc->addr, vc->port);
|
||||
if (id==22) cone_video=TRUE;
|
||||
got_video=TRUE;
|
||||
}
|
||||
if (recvStunResponse(sock3,tc->addr,
|
||||
&tc->port,&id)>0){
|
||||
ms_message("STUN test result: local text port maps to %s:%i",
|
||||
tc->addr,
|
||||
tc->port);
|
||||
if (id==33)
|
||||
cone_text=TRUE;
|
||||
if (recv_stun_response(sock3, tc->addr, &tc->port, &id)>0) {
|
||||
ms_message("STUN test result: local text port maps to %s:%i", tc->addr, tc->port);
|
||||
if (id==33) cone_text=TRUE;
|
||||
got_text=TRUE;
|
||||
}
|
||||
ortp_gettimeofday(&cur,NULL);
|
||||
|
|
@ -585,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -610,31 +613,83 @@ 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) {
|
||||
lc->forced_ice_relay = enable;
|
||||
}
|
||||
|
||||
static void stun_auth_requested_cb(LinphoneCall *call, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) {
|
||||
LinphoneProxyConfig *proxy = NULL;
|
||||
const LinphoneNatPolicy *nat_policy = NULL;
|
||||
const LinphoneAddress *addr = NULL;
|
||||
const LinphoneAuthInfo *auth_info = NULL;
|
||||
LinphoneCore *lc = call->core;
|
||||
const char *user = NULL;
|
||||
|
||||
// Get the username from the nat policy or the proxy config
|
||||
if (call->dest_proxy != NULL) proxy = call->dest_proxy;
|
||||
else proxy = linphone_core_get_default_proxy_config(call->core);
|
||||
if (proxy == NULL) return;
|
||||
nat_policy = linphone_proxy_config_get_nat_policy(proxy);
|
||||
if (nat_policy != NULL) {
|
||||
user = linphone_nat_policy_get_stun_server_username(nat_policy);
|
||||
} else {
|
||||
nat_policy = linphone_core_get_nat_policy(call->core);
|
||||
if (nat_policy != NULL) {
|
||||
user = linphone_nat_policy_get_stun_server_username(nat_policy);
|
||||
}
|
||||
}
|
||||
if (user == NULL) {
|
||||
/* If the username has not been found in the nat_policy, take the username from the currently used proxy config. */
|
||||
addr = linphone_proxy_config_get_identity_address(proxy);
|
||||
if (addr == NULL) return;
|
||||
user = linphone_address_get_username(addr);
|
||||
}
|
||||
if (user == NULL) return;
|
||||
|
||||
auth_info = linphone_core_find_auth_info(lc, realm, user, NULL);
|
||||
if (auth_info != NULL) {
|
||||
const char *hash = linphone_auth_info_get_ha1(auth_info);
|
||||
if (hash != NULL) {
|
||||
*ha1 = hash;
|
||||
} else {
|
||||
*password = linphone_auth_info_get_passwd(auth_info);
|
||||
}
|
||||
*username = user;
|
||||
} else {
|
||||
ms_warning("No auth info found for STUN auth request");
|
||||
}
|
||||
}
|
||||
|
||||
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
|
||||
char local_addr[64];
|
||||
const struct addrinfo *ai = NULL;
|
||||
IceCheckList *audio_check_list;
|
||||
IceCheckList *video_check_list;
|
||||
IceCheckList *text_check_list;
|
||||
const char *server = linphone_core_get_stun_server(lc);
|
||||
LinphoneNatPolicy *nat_policy = NULL;
|
||||
const char *server = NULL;
|
||||
|
||||
if (call->dest_proxy != NULL) nat_policy = linphone_proxy_config_get_nat_policy(call->dest_proxy);
|
||||
if (nat_policy == NULL) nat_policy = linphone_core_get_nat_policy(lc);
|
||||
if (nat_policy != NULL) server = linphone_nat_policy_get_stun_server(nat_policy);
|
||||
|
||||
if (call->ice_session == NULL) return -1;
|
||||
audio_check_list = ice_session_check_list(call->ice_session, call->main_audio_stream_index);
|
||||
|
|
@ -646,8 +701,8 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
|
|||
ms_warning("Ice gathering is not implemented for ipv6");
|
||||
return -1;
|
||||
}
|
||||
if (server){
|
||||
ai=linphone_core_get_stun_server_addrinfo(lc);
|
||||
if ((nat_policy != NULL) && (server != NULL) && (server[0] != '\0')) {
|
||||
ai=linphone_nat_policy_get_stun_server_addrinfo(nat_policy);
|
||||
if (ai==NULL){
|
||||
ms_warning("Fail to resolve STUN server for ICE gathering, continuing without stun.");
|
||||
}
|
||||
|
|
@ -658,31 +713,35 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
|
|||
|
||||
ice_session_enable_forced_relay(call->ice_session, lc->forced_ice_relay);
|
||||
|
||||
// TODO: Handle IPv6
|
||||
/* Gather local host candidates. */
|
||||
if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
|
||||
ms_error("Fail to get local ip");
|
||||
return -1;
|
||||
}
|
||||
if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) {
|
||||
ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[call->main_audio_stream_index].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[call->main_audio_stream_index].rtcp_port, 2, NULL);
|
||||
ice_add_local_candidate(audio_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_audio_stream_index].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(audio_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_audio_stream_index].rtcp_port, 2, NULL);
|
||||
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
|
||||
}
|
||||
if (linphone_core_video_enabled(lc) && (video_check_list != NULL)
|
||||
&& (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) {
|
||||
ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[call->main_video_stream_index].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL);
|
||||
ice_add_local_candidate(video_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_video_stream_index].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(video_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL);
|
||||
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
|
||||
}
|
||||
if (call->params->realtimetext_enabled && (text_check_list != NULL)
|
||||
&& (ice_check_list_state(text_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(text_check_list) == FALSE)) {
|
||||
ice_add_local_candidate(text_check_list, "host", local_addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(text_check_list, "host", local_addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL);
|
||||
ice_add_local_candidate(text_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(text_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL);
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateInProgress;
|
||||
}
|
||||
if (ai){
|
||||
ms_message("ICE: gathering candidate from [%s]",server);
|
||||
if ((ai != NULL) && (nat_policy != NULL)
|
||||
&& (linphone_nat_policy_stun_enabled(nat_policy) || linphone_nat_policy_turn_enabled(nat_policy))) {
|
||||
ms_message("ICE: gathering candidate from [%s] using %s", server, linphone_nat_policy_turn_enabled(nat_policy) ? "TURN" : "STUN");
|
||||
/* Gather local srflx candidates. */
|
||||
ice_session_enable_turn(call->ice_session, linphone_nat_policy_turn_enabled(nat_policy));
|
||||
ice_session_set_stun_auth_requested_cb(call->ice_session, (MSStunAuthRequestedCb)stun_auth_requested_cb, call);
|
||||
ice_session_gather_candidates(call->ice_session, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
||||
return 1;
|
||||
} else {
|
||||
|
|
@ -835,7 +894,8 @@ void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDes
|
|||
}
|
||||
|
||||
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy) {
|
||||
const char *rtp_addr, *rtcp_addr;
|
||||
IceCandidate *rtp_candidate = NULL;
|
||||
IceCandidate *rtcp_candidate = NULL;
|
||||
IceSessionState session_state = ice_session_state(session);
|
||||
int nb_candidates;
|
||||
int i, j;
|
||||
|
|
@ -843,9 +903,9 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess
|
|||
|
||||
if (session_state == IS_Completed) {
|
||||
if (use_nortpproxy) desc->set_nortpproxy = TRUE;
|
||||
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
|
||||
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_candidate, NULL);
|
||||
if (result == TRUE) {
|
||||
strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
|
||||
strncpy(desc->addr, rtp_candidate->taddr.ip, sizeof(desc->addr));
|
||||
} else {
|
||||
ms_warning("If ICE has completed successfully, rtp_addr should be set!");
|
||||
}
|
||||
|
|
@ -862,14 +922,16 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess
|
|||
if (!sal_stream_description_active(stream) || (cl == NULL)) continue;
|
||||
if (ice_check_list_state(cl) == ICL_Completed) {
|
||||
if (use_nortpproxy) stream->set_nortpproxy = TRUE;
|
||||
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
|
||||
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_candidate, &rtcp_candidate);
|
||||
} else {
|
||||
stream->set_nortpproxy = FALSE;
|
||||
result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
|
||||
result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_candidate, &rtcp_candidate);
|
||||
}
|
||||
if (result == TRUE) {
|
||||
strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr));
|
||||
strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr));
|
||||
strncpy(stream->rtp_addr, rtp_candidate->taddr.ip, sizeof(stream->rtp_addr));
|
||||
strncpy(stream->rtcp_addr, rtcp_candidate->taddr.ip, sizeof(stream->rtcp_addr));
|
||||
stream->rtp_port = rtp_candidate->taddr.port;
|
||||
stream->rtcp_port = rtcp_candidate->taddr.port;
|
||||
} else {
|
||||
memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr));
|
||||
memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr));
|
||||
|
|
@ -916,13 +978,12 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess
|
|||
}
|
||||
}
|
||||
if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
|
||||
int rtp_port, rtcp_port;
|
||||
memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
|
||||
if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port) == TRUE) {
|
||||
strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
|
||||
stream->ice_remote_candidates[0].port = rtp_port;
|
||||
strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
|
||||
stream->ice_remote_candidates[1].port = rtcp_port;
|
||||
if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_candidate, &rtcp_candidate) == TRUE) {
|
||||
strncpy(stream->ice_remote_candidates[0].addr, rtp_candidate->taddr.ip, sizeof(stream->ice_remote_candidates[0].addr));
|
||||
stream->ice_remote_candidates[0].port = rtp_candidate->taddr.port;
|
||||
strncpy(stream->ice_remote_candidates[1].addr, rtcp_candidate->taddr.ip, sizeof(stream->ice_remote_candidates[1].addr));
|
||||
stream->ice_remote_candidates[1].port = rtcp_candidate->taddr.port;
|
||||
} else {
|
||||
ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state");
|
||||
}
|
||||
|
|
@ -1066,7 +1127,8 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
|
|||
get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port);
|
||||
if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
|
||||
default_candidate = TRUE;
|
||||
ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID,
|
||||
// TODO: Handle IPv6
|
||||
ice_add_remote_candidate(cl, candidate->type, AF_INET, candidate->addr, candidate->port, candidate->componentID,
|
||||
candidate->priority, candidate->foundation, default_candidate);
|
||||
}
|
||||
if (ice_restarted == FALSE) {
|
||||
|
|
@ -1082,7 +1144,8 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
|
|||
/* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */
|
||||
ice_check_list_unselect_valid_pairs(cl);
|
||||
}
|
||||
ice_add_losing_pair(cl, j + 1, remote_candidate->addr, remote_candidate->port, addr, port);
|
||||
// TODO: Handle IPv6
|
||||
ice_add_losing_pair(cl, j + 1, AF_INET, remote_candidate->addr, remote_candidate->port, addr, port);
|
||||
losing_pairs_added = TRUE;
|
||||
}
|
||||
if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl);
|
||||
|
|
|
|||
303
coreapi/nat_policy.c
Normal file
303
coreapi/nat_policy.c
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
linphone
|
||||
Copyright (C) 2010-2016 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "linphonecore.h"
|
||||
#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_server_username) belle_sip_free(policy->stun_server_username);
|
||||
if (policy->stun_addrinfo) bctbx_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);
|
||||
|
||||
BELLE_SIP_INSTANCIATE_VPTR(LinphoneNatPolicy, belle_sip_object_t,
|
||||
(belle_sip_object_destroy_t)linphone_nat_policy_destroy,
|
||||
NULL, // clone
|
||||
NULL, // marshal
|
||||
TRUE
|
||||
);
|
||||
|
||||
|
||||
static void _linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy, LpConfig *config, int index) {
|
||||
char *section;
|
||||
MSList *l = NULL;
|
||||
|
||||
section = belle_sip_strdup_printf("nat_policy_%i", index);
|
||||
lp_config_set_string(config, section, "ref", policy->ref);
|
||||
lp_config_set_string(config, section, "stun_server", policy->stun_server);
|
||||
lp_config_set_string(config, section, "stun_server_username", policy->stun_server_username);
|
||||
if (linphone_nat_policy_upnp_enabled(policy)) {
|
||||
l = ms_list_append(l, "upnp");
|
||||
} else {
|
||||
if (linphone_nat_policy_stun_enabled(policy)) l = ms_list_append(l, "stun");
|
||||
if (linphone_nat_policy_turn_enabled(policy)) l = ms_list_append(l, "turn");
|
||||
if (linphone_nat_policy_ice_enabled(policy)) l = ms_list_append(l, "ice");
|
||||
}
|
||||
lp_config_set_string_list(config, section, "protocols", l);
|
||||
belle_sip_free(section);
|
||||
ms_list_free(l);
|
||||
}
|
||||
|
||||
void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy) {
|
||||
LpConfig *config = policy->lc->config;
|
||||
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, policy->ref) == 0)) {
|
||||
_linphone_nat_policy_save_to_config(policy, config, index);
|
||||
finished = TRUE;
|
||||
}
|
||||
} else {
|
||||
_linphone_nat_policy_save_to_config(policy, config, index);
|
||||
finished = TRUE;
|
||||
}
|
||||
belle_sip_free(section);
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneNatPolicy * linphone_nat_policy_ref(LinphoneNatPolicy *policy) {
|
||||
belle_sip_object_ref(policy);
|
||||
return policy;
|
||||
}
|
||||
|
||||
void linphone_nat_policy_unref(LinphoneNatPolicy *policy) {
|
||||
belle_sip_object_unref(policy);
|
||||
}
|
||||
|
||||
void *linphone_nat_policy_get_user_data(const LinphoneNatPolicy *policy) {
|
||||
return policy->user_data;
|
||||
}
|
||||
|
||||
void linphone_nat_policy_set_user_data(LinphoneNatPolicy *policy, void *ud) {
|
||||
policy->user_data = ud;
|
||||
}
|
||||
|
||||
|
||||
void linphone_nat_policy_clear(LinphoneNatPolicy *policy) {
|
||||
linphone_nat_policy_enable_stun(policy, FALSE);
|
||||
linphone_nat_policy_enable_turn(policy, FALSE);
|
||||
linphone_nat_policy_enable_ice(policy, FALSE);
|
||||
linphone_nat_policy_enable_upnp(policy, FALSE);
|
||||
linphone_nat_policy_set_stun_server(policy, NULL);
|
||||
}
|
||||
|
||||
bool_t linphone_nat_policy_stun_enabled(const LinphoneNatPolicy *policy) {
|
||||
return policy->stun_enabled;
|
||||
}
|
||||
|
||||
void linphone_nat_policy_enable_stun(LinphoneNatPolicy *policy, bool_t enable) {
|
||||
policy->stun_enabled = enable;
|
||||
}
|
||||
|
||||
bool_t linphone_nat_policy_turn_enabled(const LinphoneNatPolicy *policy) {
|
||||
return policy->turn_enabled;
|
||||
}
|
||||
|
||||
void linphone_nat_policy_enable_turn(LinphoneNatPolicy *policy, bool_t enable) {
|
||||
policy->turn_enabled = enable;
|
||||
}
|
||||
|
||||
bool_t linphone_nat_policy_ice_enabled(const LinphoneNatPolicy *policy) {
|
||||
return policy->ice_enabled;
|
||||
}
|
||||
|
||||
void linphone_nat_policy_enable_ice(LinphoneNatPolicy *policy, bool_t enable) {
|
||||
policy->ice_enabled = enable;
|
||||
}
|
||||
|
||||
bool_t linphone_nat_policy_upnp_enabled(const LinphoneNatPolicy *policy) {
|
||||
return policy->upnp_enabled;
|
||||
}
|
||||
|
||||
void linphone_nat_policy_enable_upnp(LinphoneNatPolicy *policy, bool_t enable) {
|
||||
policy->upnp_enabled = enable;
|
||||
if (enable) {
|
||||
#ifdef BUILD_UPNP
|
||||
policy->stun_enabled = policy->turn_enabled = policy->ice_enabled = FALSE;
|
||||
ms_warning("Enabling uPnP NAT policy has disabled any other previously enabled policies");
|
||||
#else
|
||||
ms_warning("Cannot enable the uPnP NAT policy because the uPnP support is not compiled in");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const char * linphone_nat_policy_get_stun_server(const LinphoneNatPolicy *policy) {
|
||||
return policy->stun_server;
|
||||
}
|
||||
|
||||
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 (new_stun_server != NULL) {
|
||||
policy->stun_server = new_stun_server;
|
||||
linphone_nat_policy_resolve_stun_server(policy);
|
||||
}
|
||||
}
|
||||
|
||||
const char * linphone_nat_policy_get_stun_server_username(const LinphoneNatPolicy *policy) {
|
||||
return policy->stun_server_username;
|
||||
}
|
||||
|
||||
void linphone_nat_policy_set_stun_server_username(LinphoneNatPolicy *policy, const char *username) {
|
||||
char *new_username = NULL;
|
||||
|
||||
if (username != NULL) new_username = belle_sip_strdup(username);
|
||||
if (policy->stun_server_username != NULL) {
|
||||
belle_sip_free(policy->stun_server_username);
|
||||
policy->stun_server_username = NULL;
|
||||
}
|
||||
if (new_username != NULL) policy->stun_server_username = new_username;
|
||||
}
|
||||
|
||||
static void stun_server_resolved(LinphoneNatPolicy *policy, const char *name, struct addrinfo *addrinfo) {
|
||||
if (policy->stun_addrinfo) {
|
||||
bctbx_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);
|
||||
const char *username = lp_config_get_string(config, section, "stun_server_username", 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 (username != NULL) linphone_nat_policy_set_stun_server_username(policy, username);
|
||||
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;
|
||||
}
|
||||
205
coreapi/nat_policy.h
Normal file
205
coreapi/nat_policy.h
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
nat_policy.h
|
||||
Copyright (C) 2010-2016 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef LINPHONE_NAT_POLICY_H_
|
||||
#define LINPHONE_NAT_POLICY_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup network_parameters
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Policy to use to pass through NATs/firewalls.
|
||||
*/
|
||||
typedef struct _LinphoneNatPolicy LinphoneNatPolicy;
|
||||
|
||||
|
||||
/**
|
||||
* Acquire a reference to the LinphoneNatPolicy object.
|
||||
* @param[in] policy LinphoneNatPolicy object.
|
||||
* @return The same LinphoneNatPolicy object.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneNatPolicy * linphone_nat_policy_ref(LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Release reference to the LinphoneNatPolicy object.
|
||||
* @param[in] policy LinphoneNatPolicy object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_unref(LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Retrieve the user pointer associated with the LinphoneNatPolicy object.
|
||||
* @param[in] policy LinphoneNatPolicy object.
|
||||
* @return The user pointer associated with the LinphoneNatPolicy object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void *linphone_nat_policy_get_user_data(const LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Assign a user pointer to the LinphoneNatPolicy object.
|
||||
* @param[in] policy LinphoneNatPolicy object.
|
||||
* @param[in] ud The user pointer to associate with the LinphoneNatPolicy object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_set_user_data(LinphoneNatPolicy *policy, void *ud);
|
||||
|
||||
/**
|
||||
* Clear a NAT policy (deactivate all protocols and unset the STUN server).
|
||||
* @param[in] policy LinphoneNatPolicy object.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_clear(LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Tell whether STUN is enabled.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @return Boolean value telling whether STUN is enabled.
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_nat_policy_stun_enabled(const LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Enable STUN.
|
||||
* If TURN is also enabled, TURN will be used instead of STUN.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @param[in] enable Boolean value telling whether to enable STUN.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_enable_stun(LinphoneNatPolicy *policy, bool_t enable);
|
||||
|
||||
/**
|
||||
* Tell whether TURN is enabled.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @return Boolean value telling whether TURN is enabled.
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_nat_policy_turn_enabled(const LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Enable TURN.
|
||||
* If STUN is also enabled, it is ignored and TURN is used.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @param[in] enable Boolean value telling whether to enable TURN.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_enable_turn(LinphoneNatPolicy *policy, bool_t enable);
|
||||
|
||||
/**
|
||||
* Tell whether ICE is enabled.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @return Boolean value telling whether ICE is enabled.
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_nat_policy_ice_enabled(const LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Enable ICE.
|
||||
* ICE can be enabled without STUN/TURN, in which case only the local candidates will be used.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @param[in] enable Boolean value telling whether to enable ICE.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_enable_ice(LinphoneNatPolicy *policy, bool_t enable);
|
||||
|
||||
/**
|
||||
* Tell whether uPnP is enabled.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @return Boolean value telling whether uPnP is enabled.
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_nat_policy_upnp_enabled(const LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Enable uPnP.
|
||||
* This has the effect to disable every other policies (ICE, STUN and TURN).
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @param[in] enable Boolean value telling whether to enable uPnP.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_enable_upnp(LinphoneNatPolicy *policy, bool_t enable);
|
||||
|
||||
/**
|
||||
* Get the STUN/TURN server to use with this NAT policy.
|
||||
* Used when STUN or TURN are enabled.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @return The STUN server used by this NAT policy.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char * linphone_nat_policy_get_stun_server(const LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Set the STUN/TURN server to use with this NAT policy.
|
||||
* Used when STUN or TURN are enabled.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @param[in] stun_server The STUN server to use with this NAT policy.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_set_stun_server(LinphoneNatPolicy *policy, const char *stun_server);
|
||||
|
||||
/**
|
||||
* Get the username used to authenticate with the STUN/TURN server.
|
||||
* The authentication will search for a LinphoneAuthInfo with this username.
|
||||
* If it is not set the username of the currently used LinphoneProxyConfig is used to search for a LinphoneAuthInfo.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @return The username used to authenticate with the STUN/TURN server.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char * linphone_nat_policy_get_stun_server_username(const LinphoneNatPolicy *policy);
|
||||
|
||||
/**
|
||||
* Seth the username used to authenticate with the STUN/TURN server.
|
||||
* The authentication will search for a LinphoneAuthInfo with this username.
|
||||
* If it is not set the username of the currently used LinphoneProxyConfig is used to search for a LinphoneAuthInfo.
|
||||
* @param[in] policy LinphoneNatPolicy object
|
||||
* @param[in] username The username used to authenticate with the STUN/TURN server.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_nat_policy_set_stun_server_username(LinphoneNatPolicy *policy, const char *username);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LINPHONE_NAT_POLICY_H_ */
|
||||
|
|
@ -448,6 +448,7 @@ int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphoneP
|
|||
return -1;
|
||||
|
||||
presence_model_add_person(model, person);
|
||||
linphone_presence_person_unref(person);
|
||||
} else {
|
||||
/* Add the activity to the first person in the model. */
|
||||
person = (LinphonePresencePerson *)ms_list_nth_data(model->persons, 0);
|
||||
|
|
|
|||
|
|
@ -440,6 +440,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);
|
||||
|
|
@ -616,6 +617,7 @@ struct _LinphoneProxyConfig
|
|||
char *dial_prefix;
|
||||
LinphoneRegistrationState state;
|
||||
LinphoneAVPFMode avpf_mode;
|
||||
LinphoneNatPolicy *nat_policy;
|
||||
|
||||
bool_t commit;
|
||||
bool_t reg_sendregister;
|
||||
|
|
@ -800,7 +802,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;
|
||||
|
|
@ -959,6 +960,7 @@ struct _LinphoneCore
|
|||
char* user_certificates_path;
|
||||
LinphoneVideoPolicy video_policy;
|
||||
time_t network_last_check;
|
||||
LinphoneNatPolicy *nat_policy;
|
||||
|
||||
bool_t use_files;
|
||||
bool_t apply_nat_settings;
|
||||
|
|
@ -1187,6 +1189,25 @@ struct _LinphoneBuffer {
|
|||
|
||||
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 *stun_server_username;
|
||||
char *ref;
|
||||
bool_t stun_enabled;
|
||||
bool_t turn_enabled;
|
||||
bool_t ice_enabled;
|
||||
bool_t upnp_enabled;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneNatPolicy);
|
||||
|
||||
void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* XML-RPC interface *
|
||||
|
|
@ -1407,7 +1428,8 @@ BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs),
|
|||
BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession),
|
||||
BELLE_SIP_TYPE_ID(LinphoneTunnelConfig),
|
||||
BELLE_SIP_TYPE_ID(LinphoneFriendListCbs),
|
||||
BELLE_SIP_TYPE_ID(LinphoneEvent)
|
||||
BELLE_SIP_TYPE_ID(LinphoneEvent),
|
||||
BELLE_SIP_TYPE_ID(LinphoneNatPolicy)
|
||||
BELLE_SIP_DECLARE_TYPES_END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -221,6 +221,9 @@ void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg){
|
|||
if (cfg->sent_headers!=NULL) sal_custom_header_free(cfg->sent_headers);
|
||||
if (cfg->pending_contact) linphone_address_unref(cfg->pending_contact);
|
||||
if (cfg->refkey) ms_free(cfg->refkey);
|
||||
if (cfg->nat_policy != NULL) {
|
||||
linphone_nat_policy_unref(cfg->nat_policy);
|
||||
}
|
||||
_linphone_proxy_config_release_ops(cfg);
|
||||
}
|
||||
|
||||
|
|
@ -1355,6 +1358,11 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
|
|||
lp_config_set_int(config,key,"privacy",cfg->privacy);
|
||||
if (cfg->refkey) lp_config_set_string(config,key,"refkey",cfg->refkey);
|
||||
lp_config_set_int(config, key, "publish_expires", cfg->publish_expires);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1377,6 +1385,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc
|
|||
LinphoneProxyConfig *cfg;
|
||||
char key[50];
|
||||
LpConfig *config=lc->config;
|
||||
const char *nat_policy_ref;
|
||||
|
||||
sprintf(key,"proxy_%i",index);
|
||||
|
||||
|
|
@ -1415,6 +1424,11 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc
|
|||
CONFIGURE_STRING_VALUE(cfg,config,key,ref_key,"refkey")
|
||||
CONFIGURE_INT_VALUE(cfg,config,key,publish_expires,"publish_expires")
|
||||
|
||||
nat_policy_ref = lp_config_get_string(config, key, "nat_policy_ref", NULL);
|
||||
if (nat_policy_ref != NULL) {
|
||||
cfg->nat_policy = linphone_core_create_nat_policy_from_config(lc, nat_policy_ref);
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
|
|
@ -1677,3 +1691,13 @@ void linphone_proxy_config_set_ref_key(LinphoneProxyConfig *cfg, const char *ref
|
|||
}
|
||||
if (refkey) cfg->refkey=ms_strdup(refkey);
|
||||
}
|
||||
|
||||
LinphoneNatPolicy * linphone_proxy_config_get_nat_policy(const LinphoneProxyConfig *cfg) {
|
||||
return cfg->nat_policy;
|
||||
}
|
||||
|
||||
void linphone_proxy_config_set_nat_policy(LinphoneProxyConfig *cfg, LinphoneNatPolicy *policy) {
|
||||
if (policy != NULL) policy = linphone_nat_policy_ref(policy); /* Prevent object destruction if the same policy is used */
|
||||
if (cfg->nat_policy != NULL) linphone_nat_policy_unref(cfg->nat_policy);
|
||||
if (policy != NULL) cfg->nat_policy = policy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -811,6 +811,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);
|
||||
|
|
|
|||
|
|
@ -1175,7 +1175,7 @@ static void call_with_no_sdp_ack_without_sdp(void){
|
|||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
static void check_nb_media_starts(LinphoneCoreManager *caller, LinphoneCoreManager *callee, unsigned int caller_nb_media_starts, unsigned int callee_nb_media_starts) {
|
||||
void check_nb_media_starts(LinphoneCoreManager *caller, LinphoneCoreManager *callee, unsigned int caller_nb_media_starts, unsigned int callee_nb_media_starts) {
|
||||
LinphoneCall *c1 = linphone_core_get_current_call(caller->lc);
|
||||
LinphoneCall *c2 = linphone_core_get_current_call(callee->lc);
|
||||
BC_ASSERT_PTR_NOT_NULL(c1);
|
||||
|
|
@ -3999,10 +3999,10 @@ void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList*
|
|||
|
||||
if (video_dir != LinphoneMediaDirectionInactive){
|
||||
BC_ASSERT_TRUE(linphone_call_params_video_enabled(params));
|
||||
BC_ASSERT_EQUAL(linphone_call_params_get_video_direction(params), video_dir, int, "%d");
|
||||
linphone_call_set_next_video_frame_decoded_callback(call,linphone_call_iframe_decoded_cb,mgr->lc);
|
||||
linphone_call_send_vfu_request(call);
|
||||
}
|
||||
BC_ASSERT_EQUAL(linphone_call_params_get_video_direction(params), video_dir, int, "%d");
|
||||
linphone_call_set_next_video_frame_decoded_callback(call,linphone_call_iframe_decoded_cb,mgr->lc);
|
||||
linphone_call_send_vfu_request(call);
|
||||
|
||||
switch (video_dir) {
|
||||
case LinphoneMediaDirectionInactive:
|
||||
|
|
|
|||
|
|
@ -369,6 +369,7 @@ void liblinphone_tester_init(void(*ftester_printf)(int level, const char *fmt, v
|
|||
void liblinphone_tester_uninit(void);
|
||||
int liblinphone_tester_set_log_file(const char *filename);
|
||||
bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state);
|
||||
void check_nb_media_starts(LinphoneCoreManager *caller, LinphoneCoreManager *callee, unsigned int caller_nb_media_starts, unsigned int callee_nb_media_starts);
|
||||
|
||||
LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file, bool_t do_registration);
|
||||
void linphone_conference_server_destroy(LinphoneConferenceServer *conf_srv);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "linphonecore.h"
|
||||
#include "private.h"
|
||||
#include "liblinphone_tester.h"
|
||||
|
|
@ -24,52 +23,34 @@
|
|||
#include "ortp/port.h"
|
||||
|
||||
|
||||
static const char* stun_address = "stun.linphone.org";
|
||||
static const char *stun_address = "stun.linphone.org";
|
||||
|
||||
|
||||
static int test_stun_encode( char*buffer, size_t len, bool_t expect_fail )
|
||||
static size_t test_stun_encode(char **buffer)
|
||||
{
|
||||
StunAtrString username;
|
||||
StunAtrString password;
|
||||
StunMessage req;
|
||||
memset(&req, 0, sizeof(StunMessage));
|
||||
memset(&username,0,sizeof(username));
|
||||
memset(&password,0,sizeof(password));
|
||||
stunBuildReqSimple( &req, &username, TRUE , TRUE , 11);
|
||||
len = stunEncodeMessage( &req, buffer, (unsigned int)len, &password);
|
||||
if (len<=0){
|
||||
if( expect_fail )
|
||||
ms_message("Fail to encode stun message (EXPECTED).\n");
|
||||
else
|
||||
ms_error("Fail to encode stun message.\n");
|
||||
return -1;
|
||||
}
|
||||
return (int)len;
|
||||
MSStunMessage *req = ms_stun_binding_request_create();
|
||||
UInt96 tr_id = ms_stun_message_get_tr_id(req);
|
||||
tr_id.octet[0] = 11;
|
||||
ms_stun_message_set_tr_id(req, tr_id);
|
||||
return ms_stun_message_encode(req, buffer);
|
||||
}
|
||||
|
||||
|
||||
static void linphone_stun_test_encode(void)
|
||||
{
|
||||
char smallBuff[12];
|
||||
size_t smallLen = 12;
|
||||
char bigBuff[STUN_MAX_MESSAGE_SIZE];
|
||||
size_t bigLen = STUN_MAX_MESSAGE_SIZE;
|
||||
|
||||
size_t len = test_stun_encode(smallBuff, smallLen, TRUE);
|
||||
BC_ASSERT(len == -1);
|
||||
|
||||
len = test_stun_encode(bigBuff, bigLen, TRUE);
|
||||
char *buffer = NULL;
|
||||
size_t len = test_stun_encode(&buffer);
|
||||
BC_ASSERT(len > 0);
|
||||
BC_ASSERT_PTR_NOT_NULL(buffer);
|
||||
if (buffer != NULL) ms_free(buffer);
|
||||
ms_message("STUN message encoded in %i bytes", (int)len);
|
||||
}
|
||||
|
||||
|
||||
static void linphone_stun_test_grab_ip(void)
|
||||
{
|
||||
LinphoneCoreManager* lc_stun = linphone_core_manager_new2( "stun_rc", FALSE);
|
||||
LinphoneCoreManager* lc_stun = linphone_core_manager_new2("stun_rc", FALSE);
|
||||
LinphoneCall dummy_call;
|
||||
int ping_time;
|
||||
int tmp=0;
|
||||
int tmp = 0;
|
||||
|
||||
memset(&dummy_call, 0, sizeof(LinphoneCall));
|
||||
dummy_call.main_audio_stream_index = 0;
|
||||
|
|
@ -82,41 +63,121 @@ static void linphone_stun_test_grab_ip(void)
|
|||
linphone_core_set_stun_server(lc_stun->lc, stun_address);
|
||||
BC_ASSERT_STRING_EQUAL(stun_address, linphone_core_get_stun_server(lc_stun->lc));
|
||||
|
||||
wait_for(lc_stun->lc,lc_stun->lc,&tmp,1);
|
||||
wait_for(lc_stun->lc, lc_stun->lc, &tmp, 1);
|
||||
|
||||
ping_time = linphone_core_run_stun_tests(lc_stun->lc, &dummy_call);
|
||||
BC_ASSERT(ping_time != -1);
|
||||
|
||||
ms_message("Round trip to STUN: %d ms", ping_time);
|
||||
|
||||
BC_ASSERT( dummy_call.ac.addr[0] != '\0');
|
||||
BC_ASSERT( dummy_call.ac.port != 0);
|
||||
BC_ASSERT(dummy_call.ac.addr[0] != '\0');
|
||||
BC_ASSERT(dummy_call.ac.port != 0);
|
||||
#ifdef VIDEO_ENABLED
|
||||
BC_ASSERT( dummy_call.vc.addr[0] != '\0');
|
||||
BC_ASSERT( dummy_call.vc.port != 0);
|
||||
BC_ASSERT(dummy_call.vc.addr[0] != '\0');
|
||||
BC_ASSERT(dummy_call.vc.port != 0);
|
||||
#endif
|
||||
BC_ASSERT( dummy_call.tc.addr[0] != '\0');
|
||||
BC_ASSERT( dummy_call.tc.port != 0);
|
||||
BC_ASSERT(dummy_call.tc.addr[0] != '\0');
|
||||
BC_ASSERT(dummy_call.tc.port != 0);
|
||||
|
||||
ms_message("STUN test result: local audio port maps to %s:%i",
|
||||
dummy_call.ac.addr,
|
||||
dummy_call.ac.port);
|
||||
ms_message("STUN test result: local audio port maps to %s:%i", dummy_call.ac.addr, dummy_call.ac.port);
|
||||
#ifdef VIDEO_ENABLED
|
||||
ms_message("STUN test result: local video port maps to %s:%i",
|
||||
dummy_call.vc.addr,
|
||||
dummy_call.vc.port);
|
||||
ms_message("STUN test result: local video port maps to %s:%i", dummy_call.vc.addr, dummy_call.vc.port);
|
||||
#endif
|
||||
ms_message("STUN test result: local text port maps to %s:%i",
|
||||
dummy_call.tc.addr,
|
||||
dummy_call.tc.port);
|
||||
ms_message("STUN test result: local text port maps to %s:%i", dummy_call.tc.addr, dummy_call.tc.port);
|
||||
|
||||
linphone_core_manager_destroy(lc_stun);
|
||||
}
|
||||
|
||||
static void configure_nat_policy(LinphoneCore *lc, bool_t turn_enabled) {
|
||||
const char *username = "liblinphone-tester";
|
||||
const char *password = "retset-enohpnilbil";
|
||||
LinphoneAuthInfo *auth_info = linphone_core_create_auth_info(lc, username, NULL, password, NULL, "sip.linphone.org", NULL);
|
||||
LinphoneNatPolicy *nat_policy = linphone_core_create_nat_policy(lc);
|
||||
linphone_nat_policy_enable_ice(nat_policy, TRUE);
|
||||
if (turn_enabled) {
|
||||
linphone_nat_policy_enable_turn(nat_policy, TRUE);
|
||||
linphone_nat_policy_set_stun_server(nat_policy, "sip1.linphone.org:3479");
|
||||
linphone_nat_policy_set_stun_server_username(nat_policy, username);
|
||||
} else {
|
||||
linphone_nat_policy_enable_stun(nat_policy, TRUE);
|
||||
linphone_nat_policy_set_stun_server(nat_policy, "stun.linphone.org");
|
||||
}
|
||||
linphone_core_set_nat_policy(lc, nat_policy);
|
||||
linphone_core_add_auth_info(lc, auth_info);
|
||||
linphone_nat_policy_unref(nat_policy);
|
||||
linphone_auth_info_destroy(auth_info);
|
||||
}
|
||||
|
||||
static void ice_turn_call_base(bool_t forced_relay, bool_t caller_turn_enabled, bool_t callee_turn_enabled) {
|
||||
LinphoneCoreManager *marie;
|
||||
LinphoneCoreManager *pauline;
|
||||
LinphoneIceState expected_ice_state = LinphoneIceStateHostConnection;
|
||||
MSList *lcs = NULL;
|
||||
|
||||
marie = linphone_core_manager_new("marie_rc");
|
||||
lcs = ms_list_append(lcs, marie->lc);
|
||||
pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
|
||||
lcs = ms_list_append(lcs, pauline->lc);
|
||||
|
||||
configure_nat_policy(marie->lc, caller_turn_enabled);
|
||||
configure_nat_policy(pauline->lc, callee_turn_enabled);
|
||||
if (forced_relay == TRUE) {
|
||||
linphone_core_enable_forced_ice_relay(marie->lc, TRUE);
|
||||
linphone_core_enable_forced_ice_relay(pauline->lc, TRUE);
|
||||
expected_ice_state = LinphoneIceStateRelayConnection;
|
||||
}
|
||||
|
||||
BC_ASSERT_TRUE(call(marie, pauline));
|
||||
|
||||
/* Wait for the ICE reINVITE to complete */
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
|
||||
BC_ASSERT_TRUE(check_ice(pauline, marie, expected_ice_state));
|
||||
check_nb_media_starts(pauline, marie, 1, 1);
|
||||
check_media_direction(marie, linphone_core_get_current_call(marie->lc), lcs, LinphoneMediaDirectionSendRecv, LinphoneMediaDirectionInactive);
|
||||
check_media_direction(pauline, linphone_core_get_current_call(pauline->lc), lcs, LinphoneMediaDirectionSendRecv, LinphoneMediaDirectionInactive);
|
||||
liblinphone_tester_check_rtcp(marie, pauline);
|
||||
if (forced_relay == TRUE) {
|
||||
LinphoneCall *call = linphone_core_get_current_call(marie->lc);
|
||||
BC_ASSERT_PTR_NOT_NULL(call->ice_session);
|
||||
if (call->ice_session != NULL) {
|
||||
IceCheckList *cl = ice_session_check_list(call->ice_session, 0);
|
||||
BC_ASSERT_PTR_NOT_NULL(cl);
|
||||
if (cl != NULL) {
|
||||
BC_ASSERT_TRUE(cl->rtp_turn_context->stats_nb_send_indication > 0);
|
||||
BC_ASSERT_TRUE(cl->rtp_turn_context->stats_nb_data_indication > 0);
|
||||
BC_ASSERT_TRUE(cl->rtp_turn_context->stats_nb_received_channel_msg > 0);
|
||||
BC_ASSERT_TRUE(cl->rtp_turn_context->stats_nb_sent_channel_msg > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end_call(marie, pauline);
|
||||
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(marie);
|
||||
ms_list_free(lcs);
|
||||
}
|
||||
|
||||
static void basic_ice_turn_call(void) {
|
||||
ice_turn_call_base(FALSE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static void relayed_ice_turn_call(void) {
|
||||
ice_turn_call_base(TRUE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static void relayed_ice_turn_to_ice_stun_call(void) {
|
||||
ice_turn_call_base(TRUE, TRUE, FALSE);
|
||||
}
|
||||
|
||||
|
||||
test_t stun_tests[] = {
|
||||
TEST_NO_TAG("Basic Stun test (Ping/public IP)", linphone_stun_test_grab_ip),
|
||||
TEST_NO_TAG("STUN encode buffer protection", linphone_stun_test_encode)
|
||||
TEST_ONE_TAG("Basic Stun test (Ping/public IP)", linphone_stun_test_grab_ip, "STUN"),
|
||||
TEST_ONE_TAG("STUN encode", linphone_stun_test_encode, "STUN"),
|
||||
TEST_TWO_TAGS("Basic ICE+TURN call", basic_ice_turn_call, "ICE", "TURN"),
|
||||
TEST_TWO_TAGS("Relayed ICE+TURN call", relayed_ice_turn_call, "ICE", "TURN"),
|
||||
TEST_TWO_TAGS("Relayed ICE+TURN to ICE+STUN call", relayed_ice_turn_to_ice_stun_call, "ICE", "TURN")
|
||||
};
|
||||
|
||||
test_suite_t stun_test_suite = {"Stun", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
|
||||
|
|
|
|||
|
|
@ -218,13 +218,12 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) {
|
|||
bool_t wait_for_stun_resolution(LinphoneCoreManager *m) {
|
||||
MSTimeSpec start;
|
||||
int timeout_ms = 10000;
|
||||
|
||||
liblinphone_tester_clock_start(&start);
|
||||
while (m->lc->net_conf.stun_addrinfo == NULL && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
|
||||
while (linphone_core_get_stun_server_addrinfo(m->lc) == NULL && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
|
||||
linphone_core_iterate(m->lc);
|
||||
ms_usleep(20000);
|
||||
}
|
||||
return m->lc->net_conf.stun_addrinfo != NULL;
|
||||
return linphone_core_get_stun_server_addrinfo(m->lc) != NULL;
|
||||
}
|
||||
|
||||
static void set_codec_enable(LinphoneCore* lc,const char* type,int rate,bool_t enable) {
|
||||
|
|
@ -342,6 +341,7 @@ void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file) {
|
|||
|
||||
void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies) {
|
||||
LinphoneProxyConfig* proxy;
|
||||
LinphoneNatPolicy *nat_policy;
|
||||
int proxy_count;
|
||||
|
||||
/*BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count, int, "%d");*/
|
||||
|
|
@ -373,7 +373,9 @@ void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies
|
|||
linphone_address_clean(mgr->identity);
|
||||
}
|
||||
|
||||
if (linphone_core_get_stun_server(mgr->lc) != NULL){
|
||||
nat_policy = linphone_core_get_nat_policy(mgr->lc);
|
||||
if ((nat_policy != NULL) && (linphone_nat_policy_get_stun_server(nat_policy) != NULL) &&
|
||||
(linphone_nat_policy_stun_enabled(nat_policy) || linphone_nat_policy_turn_enabled(nat_policy))) {
|
||||
/*before we go, ensure that the stun server is resolved, otherwise all ice related test will fail*/
|
||||
BC_ASSERT_TRUE(wait_for_stun_resolution(mgr));
|
||||
}
|
||||
|
|
@ -559,6 +561,7 @@ int liblinphone_tester_after_each(void) {
|
|||
ms_error("%s", format);
|
||||
|
||||
all_leaks_buffer = ms_strcat_printf(all_leaks_buffer, "\n%s", format);
|
||||
ms_free(format);
|
||||
}
|
||||
|
||||
// prevent any future leaks
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue