diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 564d80d51..ea97ad5f3 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -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 diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 4d2f230d2..3b12d4132 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -42,6 +42,7 @@ linphone_include_HEADERS=\ linphone_tunnel.h \ lpc2xml.h \ lpconfig.h \ + nat_policy.h \ sipsetup.h \ xml2lpc.h \ xmlrpc.h \ @@ -80,6 +81,7 @@ liblinphone_la_SOURCES=\ lsd.c \ message_storage.c \ misc.c \ + nat_policy.c \ offeranswer.c offeranswer.h\ player.c \ presence.c \ diff --git a/coreapi/linphone_proxy_config.h b/coreapi/linphone_proxy_config.h index 2fb5bda9f..128d777a3 100644 --- a/coreapi/linphone_proxy_config.h +++ b/coreapi/linphone_proxy_config.h @@ -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 const 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); + /** * @} */ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index aedc39a40..9e44ac9dd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -755,13 +755,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_nat_policy_new_from_config(lc->config, 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); @@ -778,7 +787,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){ @@ -5080,7 +5090,9 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ linphone_core_resolve_stun_server(lc); } - if (linphone_core_ready(lc)) + 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); } @@ -5154,66 +5166,59 @@ 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; + + if (lc->nat_policy != NULL) { + nat_policy = linphone_nat_policy_ref(lc->nat_policy); + linphone_nat_policy_clear(nat_policy); + } else { + nat_policy = linphone_nat_policy_new(); + } 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; - } - } - 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 (lc->sip_conf.contact) update_primary_contact(lc); - if (linphone_core_ready(lc)) - lp_config_set_string(lc->config,"net","firewall_policy",policy); + + linphone_nat_policy_set_stun_server(nat_policy, linphone_core_get_stun_server(lc)); + 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; @@ -5227,6 +5232,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; +} /******************************************************************************* @@ -6342,6 +6379,10 @@ 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, lc->config); + } } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 92b1eb09b..343b088f8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -407,6 +407,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 @@ -416,6 +417,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 @@ -2178,6 +2180,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 */ @@ -3190,6 +3193,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); @@ -3198,9 +3202,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); diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 131378cc0..b466c4d7c 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -529,6 +529,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) { @@ -644,6 +669,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); diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index d99264bed..feae2a88d 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -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 * diff --git a/coreapi/nat_policy.c b/coreapi/nat_policy.c new file mode 100644 index 000000000..926900461 --- /dev/null +++ b/coreapi/nat_policy.c @@ -0,0 +1,205 @@ +/* +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 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); +} + + +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 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; + + 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); + 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); +} + +void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy, LpConfig *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) { + 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); + } +} diff --git a/coreapi/nat_policy.h b/coreapi/nat_policy.h new file mode 100644 index 000000000..b46d7129a --- /dev/null +++ b/coreapi/nat_policy.h @@ -0,0 +1,164 @@ +/* +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; + + +/** + * 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. + * @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 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 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); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LINPHONE_NAT_POLICY_H_ */ diff --git a/coreapi/private.h b/coreapi/private.h index 436228f3d..881d5ce6a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -614,6 +614,7 @@ struct _LinphoneProxyConfig char *dial_prefix; LinphoneRegistrationState state; LinphoneAVPFMode avpf_mode; + LinphoneNatPolicy *nat_policy; bool_t commit; bool_t reg_sendregister; @@ -957,6 +958,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; @@ -1185,6 +1187,22 @@ struct _LinphoneBuffer { BELLE_SIP_DECLARE_VPTR(LinphoneBuffer); +struct _LinphoneNatPolicy { + belle_sip_object_t base; + void *user_data; + char *stun_server; + char *ref; + bool_t stun_enabled; + bool_t turn_enabled; + bool_t ice_enabled; + bool_t upnp_enabled; +}; + +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); + /***************************************************************************** * XML-RPC interface * @@ -1405,7 +1423,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 diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 6cd24c61f..2f0532455 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1355,6 +1355,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, config); + } } @@ -1377,6 +1382,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 +1421,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_nat_policy_new_from_config(config, nat_policy_ref); + } + return cfg; } @@ -1677,3 +1688,15 @@ void linphone_proxy_config_set_ref_key(LinphoneProxyConfig *cfg, const char *ref } if (refkey) cfg->refkey=ms_strdup(refkey); } + +const 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 (cfg->nat_policy != NULL) { + linphone_nat_policy_unref(cfg->nat_policy); + cfg->nat_policy = NULL; + } + if (policy != NULL) cfg->nat_policy = linphone_nat_policy_ref(policy); +}