Commit f0352a1b authored by Nicolas Michon's avatar Nicolas Michon
Browse files

Add dependent proxy config mecanism

parent c5ffe5d8
......@@ -74,3 +74,32 @@ This pseudo code shows how to unregister a user associated to a #LinphoneProxyCo
.. seealso:: A complete tutorial can be found at: :ref:`"Basic registration" <basic_registration_code_sample>` source code.
Proxies dependency
------------------
As an example, a practical use case of dependent proxies could be as follows:
On a mobile device app, a proxy configuration is registered to a non-modifiable server that does not support push notifications, thus being unreachable most of the time.
To enable push notifications, we could add another proxy configuration and mark the initial one 'dependent' on a proxy pointing to a push-enabled server (refered to as 'master' or 'dependency').
The proxy configuration will wait for successful registration on its dependency before triggering its own.
Once registered, both proxy configurations will share the same contact address (the 'master' one). Meaning that calls to the dependent address will go through the push-enabled master server.
This mecanism must be enabled before the proxy configuration is added to the core (before :cpp:func:`linphone_core_add_proxy_config`).
.. code-block:: c
LinphoneProxyConfig* dependent_proxy_cfg;
LinphoneProxyConfig* master_proxy_cfg;
linphone_proxy_config_set_ref_key(master_proxy_cfg, "unique-proxy-id");
linphone_proxy_config_set_depends_on(dependent_proxy_cfg, "unique-proxy-id");
//Add master first
linphone_core_add_proxy_config(lc, master_proxy_cfg);
linphone_core_add_proxy_config(lc, dependent_proxy_cfg);
Note that this mecanism is atypical and should rarely be used.
......@@ -111,6 +111,8 @@ struct _LinphoneProxyConfig
bool_t commit;
bool_t reg_sendregister;
/* Used to completely disable registration on a dependent proxy config. (Won't be enabled back even if it's 'master' proxy config state goes to LinphoneRegistrationOk) */
bool_t reg_dependent_disabled;
bool_t publish;
bool_t dial_escape_plus;
......@@ -134,6 +136,7 @@ struct _LinphoneProxyConfig
char *refkey;
char *sip_etag; /*publish context*/
char *depends_on; /* NULL or points to another proxy_config->refkey */
char *conference_factory_uri;
bool_t push_notification_allowed;
......
......@@ -114,7 +114,7 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cfg) {
const char *dial_prefix = lc ? lp_config_get_default_string(lc->config,"proxy","dial_prefix",NULL) : NULL;
const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL;
const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL;
const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL;
const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; //TODO return list instead of string
const char *realm = lc ? lp_config_get_default_string(lc->config, "proxy", "realm", NULL) : NULL;
......@@ -122,11 +122,13 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf
const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL;
const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL;
const char *refkey = lc ? lp_config_get_default_string(lc->config, "proxy", "refkey", NULL) : NULL;
const char *depends_on = lc ? lp_config_get_default_string(lc->config, "proxy", "depends_on", NULL) : NULL;
const char *nat_policy_ref = lc ? lp_config_get_default_string(lc->config, "proxy", "nat_policy_ref", NULL):NULL;
const char *conference_factory_uri = lc ? lp_config_get_default_string(lc->config, "proxy", "conference_factory_uri", NULL):NULL;
cfg->lc = lc;
cfg->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600;
cfg->reg_sendregister = lc ? !!lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1;
cfg->reg_dependent_disabled = cfg->depends_on && !cfg->reg_sendregister;
cfg->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL;
cfg->dial_escape_plus = lc ? !!lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0;
cfg->privacy = lc ? (LinphonePrivacyMask)lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : (LinphonePrivacyMask)LinphonePrivacyDefault;
......@@ -155,6 +157,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf
ms_error("Cannot create default nat policy with ref [%s] for proxy config [%p]",nat_policy_ref,cfg);
}
}
cfg->depends_on = depends_on ? ms_strdup(depends_on) : NULL;
linphone_proxy_config_set_conference_factory_uri(cfg, conference_factory_uri ? ms_strdup(conference_factory_uri) : NULL);
}
......@@ -257,6 +260,7 @@ 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->depends_on) ms_free(cfg->depends_on);
if (cfg->nat_policy != NULL) {
linphone_nat_policy_unref(cfg->nat_policy);
}
......@@ -322,7 +326,6 @@ LinphoneStatus linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, c
return 0;
}
LinphoneStatus linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, const LinphoneAddress *addr){
if (!addr || linphone_address_get_username(addr)==NULL){
char* as_string = addr ? linphone_address_as_string(addr) : ms_strdup("NULL");
......@@ -419,12 +422,20 @@ bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *cfg){
return FALSE;
if (cfg->identity_address==NULL)
return FALSE;
if (cfg->depends_on != NULL && linphone_core_get_proxy_config_by_refkey(lc, cfg->depends_on) == NULL) {
ms_message("LinphoneProxyConfig marked as dependent but no proxy configuration found for refkey [%s]", cfg->depends_on);
return FALSE;
}
return TRUE;
}
void linphone_proxy_config_enableregister(LinphoneProxyConfig *cfg, bool_t val){
if (val != cfg->reg_sendregister) cfg->register_changed = TRUE;
cfg->reg_sendregister=val;
cfg->reg_sendregister = val;
if (cfg->depends_on && !val) {
cfg->reg_dependent_disabled = TRUE;
}
}
void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, int val){
......@@ -452,8 +463,20 @@ void linphone_proxy_config_edit(LinphoneProxyConfig *cfg){
/*Don't stop refresher*/
}
void linphone_proxy_config_apply(LinphoneProxyConfig *cfg,LinphoneCore *lc){
void linphone_proxy_config_apply(LinphoneProxyConfig *cfg, LinphoneCore *lc){
cfg->lc=lc;
if (cfg->depends_on != NULL) {
//disable register if master cfg is not yet registered
LinphoneProxyConfig *masterCfg = linphone_core_get_proxy_config_by_refkey(lc, cfg->depends_on);
if (masterCfg && masterCfg->state != LinphoneRegistrationOk) {
if (cfg->reg_sendregister != FALSE) {
cfg->register_changed = TRUE;
}
cfg->reg_sendregister = FALSE;
//We do not call linphone_proxy_config_enable_register on purpose here
//Explicitely disabling register on a dependent config puts it in a disabled state (see cfg->reg_dependent_disabled) to avoid automatic re-enable if masterCfg reach LinphoneRegistrationOk
}
}
linphone_proxy_config_done(cfg);
}
......@@ -488,19 +511,27 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){
}
static LinphoneAddress *guess_contact_for_register (LinphoneProxyConfig *cfg) {
LinphoneProxyConfig *ref = cfg;
LinphoneAddress *result = nullptr;
LinphoneAddress *proxy = linphone_address_new(cfg->reg_proxy);
if (cfg->depends_on) {
//In case of dependent proxy config, force contact of 'master' proxy config, but only after a successful register
LinphoneProxyConfig *master = linphone_core_get_proxy_config_by_refkey(cfg->lc, cfg->depends_on);
//if (master) ref = master;
return linphone_address_clone(master->contact_address);
}
LinphoneAddress *proxy = linphone_address_new(ref->reg_proxy);
if (!proxy)
return nullptr;
const char *host = linphone_address_get_domain(proxy);
if (host) {
result = linphone_address_clone(cfg->identity_address);
if (cfg->contact_params) {
result = linphone_address_clone(ref->identity_address);
if (ref->contact_params) {
// We want to add a list of contacts params to the linphone address
linphone_address_set_params(result, cfg->contact_params);
linphone_address_set_params(result, ref->contact_params);
}
if (cfg->contact_uri_params)
linphone_address_set_uri_params(result, cfg->contact_uri_params);
if (ref->contact_uri_params)
linphone_address_set_uri_params(result, ref->contact_uri_params);
}
linphone_address_unref(proxy);
return result;
......@@ -514,10 +545,10 @@ void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) {
}
static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){
if (cfg->reg_sendregister){
LinphoneAddress* proxy=linphone_address_new(cfg->reg_proxy);
char* proxy_string;
char * from = linphone_address_as_string(cfg->identity_address);
if (cfg->reg_sendregister) {
LinphoneAddress* proxy = linphone_address_new(cfg->reg_proxy);
char *proxy_string;
char *from = linphone_address_as_string(cfg->identity_address);
ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",cfg,linphone_core_get_version());
proxy_string=linphone_address_as_string_uri_only(proxy);
linphone_address_unref(proxy);
......@@ -884,7 +915,6 @@ LinphoneStatus linphone_proxy_config_done(LinphoneProxyConfig *cfg)
} else {
ms_message("Publish params have not changed on proxy config [%p]",cfg);
}
linphone_proxy_config_write_all_to_config_file(cfg->lc);
return 0;
}
......@@ -1056,6 +1086,17 @@ void linphone_proxy_config_set_custom_header(LinphoneProxyConfig *cfg, const cha
cfg->register_changed = TRUE;
}
const char *linphone_proxy_config_get_depends_on(LinphoneProxyConfig *cfg) {
return cfg->depends_on;
}
void linphone_proxy_config_set_depends_on(LinphoneProxyConfig *cfg, const char *depends_on) {
if (cfg) {
if (cfg->depends_on) ms_free(cfg->depends_on);
cfg->depends_on = ms_strdup(depends_on);
}
}
LinphoneStatus linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
if (!linphone_proxy_config_check(lc,cfg)) {
return -1;
......@@ -1069,6 +1110,29 @@ LinphoneStatus linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyCon
return 0;
}
//If a proxy config dependency is removed, re-enable 'normal' behavior for previously dependent configs
void linphone_core_remove_dependent_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg) {
bctbx_list_t *it = lc->sip_conf.proxies;
for (;it;it = it->next) {
LinphoneProxyConfig *tmp = reinterpret_cast<LinphoneProxyConfig *>(it->data);
if (tmp != cfg && tmp->depends_on && strcmp(tmp->depends_on, cfg->refkey) == 0) {
ms_message("Updating dependent proxy config [%p] caused by removal of 'master' proxy config refkey[%s]", tmp, cfg->refkey);
bctbx_free(tmp->depends_on);
tmp->depends_on = NULL;
linphone_proxy_config_edit(tmp);
//Only re-enable register if proxy wasn't explicitely disabled
linphone_proxy_config_enable_register(tmp, tmp->reg_dependent_disabled != TRUE);
tmp->reg_dependent_disabled = FALSE;
linphone_proxy_config_done(tmp);
//Force update on dependent if master wasn't registered
if (cfg->state != LinphoneRegistrationOk) {
linphone_proxy_config_update(tmp);
}
}
}
}
void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
/* check this proxy config is in the list before doing more*/
if (bctbx_list_find(lc->sip_conf.proxies,cfg)==NULL) {
......@@ -1076,6 +1140,7 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf
return;
}
lc->sip_conf.proxies=bctbx_list_remove(lc->sip_conf.proxies,cfg);
linphone_core_remove_dependent_proxy_config(lc, cfg);
/* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */
lc->sip_conf.deleted_proxies=bctbx_list_append(lc->sip_conf.deleted_proxies,cfg);
......@@ -1099,9 +1164,7 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf
linphone_proxy_config_set_conference_factory_uri(cfg, NULL);
}
void linphone_core_clear_proxy_config(LinphoneCore *lc){
void linphone_core_clear_proxy_config(LinphoneCore *lc) {
bctbx_list_t* list=bctbx_list_copy(linphone_core_get_proxy_config_list((const LinphoneCore*)lc));
bctbx_list_t* copy=list;
for(;list!=NULL;list=list->next){
......@@ -1119,6 +1182,18 @@ int linphone_core_get_default_proxy_config_index(LinphoneCore *lc) {
return pos;
}
LinphoneProxyConfig *linphone_core_get_proxy_config_by_refkey(LinphoneCore *lc, const char *refkey) {
if (refkey == NULL || lc == NULL) return NULL;
bctbx_list_t *list = lc->sip_conf.proxies;
for (;list!=NULL;list=list->next) {
LinphoneProxyConfig *tmp = reinterpret_cast<LinphoneProxyConfig *>(list->data);
if (tmp && tmp->refkey && strcmp(refkey, tmp->refkey) == 0) {
return tmp;
}
}
return NULL;
}
void linphone_core_set_default_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config){
/* check if this proxy is in our list */
if (config!=NULL){
......@@ -1196,6 +1271,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
lp_config_set_int(config, key, "privacy", (int)cfg->privacy);
lp_config_set_int(config, key, "push_notification_allowed", (int)cfg->push_notification_allowed);
if (cfg->refkey) lp_config_set_string(config, key, "refkey", cfg->refkey);
if (cfg->depends_on) lp_config_set_string(config, key, "depends_on", cfg->depends_on);
lp_config_set_int(config, key, "publish_expires", cfg->publish_expires);
if (cfg->nat_policy != NULL) {
......@@ -1267,6 +1343,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc
CONFIGURE_INT_VALUE(cfg, config, key, privacy, "privacy", LinphonePrivacyMask)
CONFIGURE_STRING_VALUE(cfg, config, key, ref_key, "refkey")
CONFIGURE_STRING_VALUE(cfg, config, key, depends_on, "depends_on")
CONFIGURE_INT_VALUE(cfg, config, key, publish_expires, "publish_expires", int)
nat_policy_ref = lp_config_get_string(config, key, "nat_policy_ref", NULL);
......@@ -1276,6 +1353,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc
CONFIGURE_STRING_VALUE(cfg, config, key, conference_factory_uri, "conference_factory_uri");
cfg->reg_dependent_disabled = cfg->depends_on && !cfg->reg_sendregister;
return cfg;
}
......@@ -1303,7 +1382,6 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){
ms_error("Could not retrieve proxy uri !");
}
}
}
SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){
......@@ -1316,8 +1394,13 @@ SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){
static bool_t can_register(LinphoneProxyConfig *cfg){
LinphoneCore *lc=cfg->lc;
if (lc->sip_conf.register_only_when_network_is_up){
return lc->sip_network_state.global_state;
if (lc->sip_conf.register_only_when_network_is_up && !lc->sip_network_state.global_state) {
return FALSE;
}
if (cfg->depends_on) {
LinphoneProxyConfig *masterCfg = linphone_core_get_proxy_config_by_refkey(lc, cfg->depends_on);
return masterCfg && linphone_proxy_config_get_state(masterCfg) == LinphoneRegistrationOk && !cfg->reg_dependent_disabled;
}
return TRUE;
}
......@@ -1361,8 +1444,32 @@ void * linphone_proxy_config_get_user_data(const LinphoneProxyConfig *cfg) {
return cfg->user_data;
}
//Enable register on proxy config dependent on the given one (if any).
//Also force contact address of dependent proxy config to the given one
void _linphone_update_dependent_proxy_config(LinphoneProxyConfig *cfg) {
if (!cfg || !cfg->lc) return;
bctbx_list_t *it = cfg->lc->sip_conf.proxies;
for (;it;it = it->next) {
LinphoneProxyConfig *tmp = reinterpret_cast<LinphoneProxyConfig *>(it->data);
if (tmp != cfg && tmp->depends_on && strcmp(tmp->depends_on, cfg->refkey) == 0) {
if (tmp->reg_dependent_disabled) continue;
linphone_proxy_config_edit(tmp);
linphone_proxy_config_enable_register(tmp, TRUE);
const SalAddress *salAddr = cfg->op->getContactAddress();
if (salAddr) {
tmp->contact_address = linphone_address_new(sal_address_as_string(salAddr));
}
linphone_proxy_config_done(tmp);
linphone_proxy_config_update(tmp);
}
}
}
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){
LinphoneCore *lc=cfg->lc;
LinphoneCore *lc = cfg->lc;
if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/
ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s] on core [%p]" ,
cfg,
......@@ -1371,11 +1478,14 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
linphone_registration_state_to_string(state),
cfg->lc);
if (state == LinphoneRegistrationOk) {
const SalAddress *salAddr = cfg->op->getContactAddress();
if (salAddr)
L_GET_PRIVATE_FROM_C_OBJECT(cfg->contact_address)->setInternalAddress(const_cast<SalAddress *>(salAddr));
if (!cfg->depends_on) {
const SalAddress *salAddr = cfg->op->getContactAddress();
if (salAddr)
L_GET_PRIVATE_FROM_C_OBJECT(cfg->contact_address)->setInternalAddress(salAddr);
_linphone_update_dependent_proxy_config(cfg);
}
}
if (linphone_core_should_subscribe_friends_only_when_registered(lc) && cfg->state!=state && state == LinphoneRegistrationOk){
if (linphone_core_should_subscribe_friends_only_when_registered(lc) && cfg->state!=state && state == LinphoneRegistrationOk) {
ms_message("Updating friends for identity [%s] on core [%p]",cfg->reg_identity,cfg->lc);
/* state must be updated before calling linphone_core_update_friends_subscriptions*/
cfg->state=state;
......
......@@ -2180,6 +2180,12 @@ LINPHONE_PUBLIC const bctbx_list_t *linphone_core_get_proxy_config_list(const Li
LINPHONE_PUBLIC void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index);
/**
* @param[in] refkey An arbitrary reference key associated to a proxy configuration
* @return the proxy configuration for the given refkey, or NULL if none found
**/
LINPHONE_PUBLIC LinphoneProxyConfig *linphone_core_get_proxy_config_by_refkey(LinphoneCore *lc, const char *refkey);
/**
* @return the default proxy configuration, that is the one used to determine the current identity.
* @deprecated Use linphone_core_get_default_proxy_config() instead.
......
......@@ -117,7 +117,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg,
#define linphone_proxy_config_expires linphone_proxy_config_set_expires
/**
* @brief Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig .
* @brief Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig.
*
* In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule.
* @param[in] cfg #LinphoneProxyConfig object.
......@@ -586,6 +586,31 @@ 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 refkey of a #LinphoneProxyConfig this proxy config is dependent on.
*
* @param[in] cfg #LinphoneProxyConfig object.
* @return The reference key string this proxy config is dependent on, or NULL if not marked dependent
**/
const char *linphone_proxy_config_get_depends_on(LinphoneProxyConfig *cfg);
/**
* Mark this proxy configuration as being dependent on another.
* The depends_on string must refer to a refkey of a proxy configuration previously added to the core.
*
* @see linphone_proxy_config_set_ref_key()
*
* The proxy configuration marked as dependent will wait for successful registration on its dependency before triggering its own.
*
* Once registered, both proxy configurations will share the same contact address (the 'master' one).
*
* This mecanism must be enabled before the proxy configuration is added to the core
*
* @param[in] cfg #LinphoneProxyConfig object.
* @param[in] depends_on The reference key of a master #LinphoneProxyConfig
**/
void linphone_proxy_config_set_depends_on(LinphoneProxyConfig *cfg, const char *depends_on);
/**
* 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.
......
......@@ -106,6 +106,7 @@ set(RC_FILES
rcfiles/marie_quality_reporting_rc
rcfiles/marie_rc
rcfiles/marie_dual_proxy_rc
rcfiles/marie_dependent_proxy_rc
rcfiles/marie2_rc
rcfiles/marie_rc_rtcp_xr
rcfiles/marie_remote_404_rc
......
......@@ -19,6 +19,8 @@
#include "liblinphone_tester.h"
#include "tester_utils.h"
void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj);
#include <stdlib.h>
const char* phone_normalization(LinphoneProxyConfig *proxy, const char* in) {
......@@ -269,13 +271,141 @@ static void single_route(void) {
linphone_core_manager_destroy(marie);
}
/*
* Dependent proxy config scenario: pauline@example.org, marie@example.org and marie@sip2.linphone.org
* marie@sip2.linphone.org is marked 'Dependent' on marie@example.org.
* Once all registered, we cut the marie@sip2.linphone.org connection.
* A call from pauline@example.org to marie@sip2.linphone.org should work (and go through example.org instead of sip2.linphone.org)
*/
static void dependent_proxy_config(void) {
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
LinphoneCoreManager *marie = linphone_core_manager_new("marie_dependent_proxy_rc");
LinphoneProxyConfig *marie_cfg = linphone_core_get_default_proxy_config(marie->lc);
LinphoneProxyConfig *marie_dependent_cfg = (LinphoneProxyConfig *) linphone_core_get_proxy_config_list(marie->lc)->next->data;
BC_ASSERT_PTR_NOT_NULL(marie_cfg);
BC_ASSERT_PTR_NOT_NULL(marie_dependent_cfg);
BC_ASSERT_STRING_EQUAL("master", linphone_proxy_config_get_depends_on(marie_dependent_cfg));
BC_ASSERT_TRUE(wait_for(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 2));
const LinphoneAddress *marie_cfg_contact = linphone_proxy_config_get_contact(marie_cfg);
const LinphoneAddress *marie_dependent_cfg_contact = linphone_proxy_config_get_contact(marie_dependent_cfg);
ms_message("NMN DEBUG: TESTER. marie_cfg contact = [%s]", linphone_address_as_string(marie_cfg_contact));
ms_message("NMN DEBUG: TESTER. marie_dependent_cfg contact = [%s]", linphone_address_as_string(marie_dependent_cfg_contact));
BC_ASSERT_TRUE(linphone_proxy_config_address_equal(marie_cfg_contact, marie_dependent_cfg_contact) == LinphoneProxyConfigAddressEqual);
//Cut link for dependent proxy config, then call its identity address and check that we receive the call
//(which would be received through the 'master' proxy config server)
linphone_core_set_network_reachable(marie->lc, FALSE);
linphone_proxy_config_edit(marie_dependent_cfg);
linphone_proxy_config_enable_register(marie_dependent_cfg, FALSE);
linphone_proxy_config_done(marie_dependent_cfg);
linphone_core_set_network_reachable(marie->lc, TRUE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 3); //One more time for 'master' proxy config
LinphoneAddress *marie_dependent_addr = linphone_address_new(linphone_proxy_config_get_identity(marie_dependent_cfg));
linphone_core_invite_address(pauline->lc, marie_dependent_addr);
if (BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallIncomingReceived, 1, 10000))) {
linphone_call_accept(linphone_core_get_current_call(marie->lc));
BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 10000));
BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1, 10000));
end_call(pauline, marie);
}
linphone_address_unref(marie_dependent_addr);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie);
}
//Dependent proxy config should not register if its dependency is not in a LinphoneRegistrationOk state
static void proxy_config_dependent_register(void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_dependent_proxy_rc");
const bctbx_list_t *proxyConfigs = linphone_core_get_proxy_config_list(marie->lc);
LinphoneProxyConfig *master = (LinphoneProxyConfig *) proxyConfigs->data;
linphone_proxy_config_edit(master);
linphone_proxy_config_set_server_addr(master, "sip:cannotberesol.ved");
linphone_proxy_config_done(master);
BC_ASSERT_TRUE(wait_for(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 0));
linphone_core_manager_destroy(marie);
}
//Dependent proxy config pointing to inexistant other proxy configuration.
static void invalid_dependent_proxy_config(void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_dependent_proxy_rc");
const bctbx_list_t *proxyConfigs = linphone_core_get_proxy_config_list(marie->lc);
LinphoneProxyConfig *master = (LinphoneProxyConfig *) proxyConfigs->data;
LinphoneProxyConfig *dependent = (LinphoneProxyConfig *) proxyConfigs->next->data;
linphone_core_remove_proxy_config(marie->lc, dependent);
linphone_core_remove_proxy_config(marie->lc, master);
proxyConfigs = linphone_core_get_proxy_config_list(marie->lc);
BC_ASSERT_EQUAL(bctbx_list_size(proxyConfigs), 0, int, "%d");
linphone_proxy_config_set_ref_key(master, "invalid");
linphone_core_add_proxy_config(marie->lc, master);
//Adding a dependent proxy config linking to inexistent refkey should fail
BC_ASSERT_EQUAL(linphone_core_add_proxy_config(marie->lc, dependent), -1, int, "%d");
proxyConfigs = linphone_core_get_proxy_config_list(marie->lc);
BC_ASSERT_EQUAL(bctbx_list_size(proxyConfigs), 1, int, "%d");
linphone_core_manager_destroy(marie);
}
//A dependent proxy config should behave as a normal one after removal of dependency
static void dependent_proxy_dependency_removal(void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_dependent_proxy_rc");
const bctbx_list_t *proxyConfigs = linphone_core_get_proxy_config_list(marie->lc);
LinphoneProxyConfig *master = (LinphoneProxyConfig *) proxyConfigs->data;
linphone_core_set_network_reachable(marie->lc, FALSE);
linphone_core_remove_proxy_config(marie->lc, master);
proxyConfigs = linphone_core_get_proxy_config_list(marie->lc);
BC_ASSERT_EQUAL(bctbx_list_size(proxyConfigs), 1, int, "%d");
linphone_core_set_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE(wait_for(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 1));
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneRegistrationOk, 1, int, "%d");
linphone_core_manager_destroy(marie);
}
test_t proxy_config_tests[] = {
TEST_NO_TAG("Phone normalization without proxy", phone_normalization_without_proxy),
TEST_NO_TAG("Phone normalization with proxy", phone_normalization_with_proxy),
TEST_NO_TAG("Phone normalization with dial escape plus", phone_normalization_with_dial_escape_plus),
TEST_NO_TAG("SIP URI normalization", sip_uri_normalization),
TEST_NO_TAG("Load new default value for proxy config", load_dynamic_proxy_config),
TEST_NO_TAG("Single route", single_route)
TEST_NO_TAG("Single route", single_route),
TEST_NO_TAG("Proxy dependency", dependent_proxy_config),
TEST_NO_TAG("Invalid dependent proxy", invalid_dependent_proxy_config),
TEST_NO_TAG("Dependent proxy dependency register", proxy_config_dependent_register),
TEST_NO_TAG("Dependent proxy dependency removal", dependent_proxy_dependency_removal)
};
test_suite_t proxy_config_test_suite = {"Proxy config", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
......
[sip]
sip_port=-1
sip_tcp_port=-1
sip_tls_port=-1
default_proxy=0
ping_with_options=0
composing_idle_timeout=1
store_ha1_passwd=0 #used for sipp
[auth_info_0]
username=marie
userid=marie
passwd=secret
realm=sip.example.org