update proxy config etag on status PublishOk. It allows PUBLISH to be consistent over network state changes, avoiding orphan tuples to remain server side.

This commit is contained in:
Jehan Monnier 2017-09-14 13:08:30 +02:00
parent 6c7c56271a
commit 5a985ca79d
3 changed files with 174 additions and 108 deletions

View file

@ -826,6 +826,13 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr
return NULL;
}
void linphone_proxy_config_set_etag(LinphoneProxyConfig *cfg,const char* sip_etag) {
if (cfg->sip_etag) ms_free(cfg->sip_etag);
if (sip_etag)
cfg->sip_etag = ms_strdup(sip_etag);
else
cfg->sip_etag = NULL;
}
/**
* Commits modification made to the proxy configuration.
**/
@ -867,11 +874,7 @@ LinphoneStatus linphone_proxy_config_done(LinphoneProxyConfig *cfg)
ms_message("Publish params have changed on proxy config [%p]",cfg);
if (cfg->presence_publish_event) {
if (cfg->publish) {
const char * sip_etag = linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag");
if (sip_etag) {
if (cfg->sip_etag) ms_free(cfg->sip_etag);
cfg->sip_etag = ms_strdup(sip_etag);
}
linphone_proxy_config_set_etag(cfg, linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag"));
}
/*publish is terminated*/
linphone_event_terminate(cfg->presence_publish_event);
@ -1542,9 +1545,22 @@ void linphone_proxy_config_set_nat_policy(LinphoneProxyConfig *cfg, LinphoneNatP
}
void linphone_proxy_config_notify_publish_state_changed(LinphoneProxyConfig *cfg, LinphonePublishState state) {
if ((cfg->presence_publish_event != NULL) && ((state == LinphonePublishCleared) || (state == LinphonePublishError))) {
linphone_event_unref(cfg->presence_publish_event);
cfg->presence_publish_event = NULL;
if (cfg->presence_publish_event != NULL) {
switch (state) {
case LinphonePublishCleared:
linphone_proxy_config_set_etag(cfg,NULL);
case LinphonePublishError:
linphone_event_unref(cfg->presence_publish_event);
cfg->presence_publish_event = NULL;
break;
case LinphonePublishOk:
linphone_proxy_config_set_etag(cfg,linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag"));
break;
default:
break;
}
}
}

View file

@ -1571,8 +1571,157 @@ static void extended_notify_sub_unsub_sub2(void) {
bctbx_list_free(lcs);
}
static void simple_publish_with_expire(int expires) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneProxyConfig* proxy;
LinphonePresenceModel* presence;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
proxy = linphone_core_get_default_proxy_config(marie->lc);
linphone_proxy_config_edit(proxy);
if (expires > 0) {
linphone_proxy_config_set_publish_expires(proxy,expires);
}
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1));
presence = linphone_presence_model_new();
linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
linphone_core_set_presence_model(marie->lc,presence);
linphone_presence_model_unref(presence);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_done(proxy);
/*make sure no publish is sent*/
BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3,2000));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,FALSE);
linphone_proxy_config_done(proxy);
/*fixme PUBLISH state machine is too simple, clear state should only be propagated at API level when 200ok is received*/
/*BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));*/
wait_for_until(marie->lc,marie->lc,NULL,0,2000);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishCleared,1));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,3));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_set_publish_expires(proxy, linphone_proxy_config_get_publish_expires(proxy)+1);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(marie);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,3,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(marie);
}
static void simple_publish(void) {
simple_publish_with_expire(-1);
}
static void publish_with_expires(void) {
simple_publish_with_expire(2);
}
static void publish_with_dual_identity(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new("multi_account_rc");
const bctbx_list_t* proxies;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(pauline->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
for (proxies = linphone_core_get_proxy_config_list(pauline->lc); proxies!=NULL; proxies = proxies->next) {
LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) proxies->data;
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
}
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(pauline);
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,4,int,"%i");
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(pauline);
}
static void publish_with_network_state_changes(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneFriend* marie_as_friend = linphone_core_create_friend_with_address(pauline->lc, get_identity(marie));
LinphoneProxyConfig* proxy;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, cbs,TRUE);
linphone_core_cbs_unref(cbs);
linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL);
linphone_core_set_user_agent(marie->lc, "full-presence-support-bypass", NULL);
proxy = linphone_core_get_default_proxy_config(marie->lc);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1));
linphone_core_set_network_reachable(marie->lc, FALSE);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationNone,1));
BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2,1000));
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i");
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishError,0,int,"%i");
linphone_core_set_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2));
linphone_core_manager_stop(marie);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,2,int,"%i");
linphone_core_manager_destroy(marie);
/*make sure there is no remaining publish caused by network failure*/
linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL);
linphone_core_set_user_agent(pauline->lc, "full-presence-support-bypass", NULL);
linphone_core_add_friend(pauline->lc, marie_as_friend);
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityAway,1));
linphone_friend_unref(marie_as_friend);
linphone_core_manager_destroy(pauline);
}
test_t presence_server_tests[] = {
TEST_NO_TAG("Simple Publish", simple_publish),
TEST_NO_TAG("Publish with 2 identities", publish_with_dual_identity),
TEST_NO_TAG("Simple Publish with expires", publish_with_expires),
TEST_ONE_TAG("Publish with network state changes", publish_with_network_state_changes, "presence"),
TEST_NO_TAG("Simple", simple),
TEST_NO_TAG("Fast activity change", fast_activity_change),
TEST_NO_TAG("Forked subscribe with late publish", test_forked_subscribe_notify_publish),

View file

@ -142,101 +142,6 @@ void notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *l
counters->number_of_NotifyPresenceReceivedForUriOrTel++;
}
static void simple_publish_with_expire(int expires) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneProxyConfig* proxy;
LinphonePresenceModel* presence;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
proxy = linphone_core_get_default_proxy_config(marie->lc);
linphone_proxy_config_edit(proxy);
if (expires > 0) {
linphone_proxy_config_set_publish_expires(proxy,expires);
}
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1));
presence = linphone_presence_model_new();
linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
linphone_core_set_presence_model(marie->lc,presence);
linphone_presence_model_unref(presence);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_done(proxy);
/*make sure no publish is sent*/
BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3,2000));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,FALSE);
linphone_proxy_config_done(proxy);
/*fixme PUBLISH state machine is too simple, clear state should only be propagated at API level when 200ok is received*/
/*BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));*/
wait_for_until(marie->lc,marie->lc,NULL,0,2000);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishCleared,1));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,3));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_set_publish_expires(proxy, linphone_proxy_config_get_publish_expires(proxy)+1);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(marie);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,3,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(marie);
}
static void simple_publish(void) {
simple_publish_with_expire(-1);
}
static void publish_with_expires(void) {
simple_publish_with_expire(2);
}
static void publish_with_dual_identity(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new("multi_account_rc");
const bctbx_list_t* proxies;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(pauline->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
for (proxies = linphone_core_get_proxy_config_list(pauline->lc); proxies!=NULL; proxies = proxies->next) {
LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) proxies->data;
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
}
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(pauline);
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,4,int,"%i");
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(pauline);
}
static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) {
stats initial_caller=caller_mgr->stat;
stats initial_callee=callee_mgr->stat;
@ -640,14 +545,10 @@ test_t presence_tests[] = {
TEST_ONE_TAG("Simple Subscribe", simple_subscribe,"presence"),
TEST_ONE_TAG("Simple Subscribe with early NOTIFY", simple_subscribe_with_early_notify,"presence"),
TEST_NO_TAG("Simple Subscribe with friend from rc", simple_subscribe_with_friend_from_rc),
TEST_NO_TAG("Simple Publish", simple_publish),
TEST_NO_TAG("Publish with 2 identities", publish_with_dual_identity),
TEST_NO_TAG("Simple Publish with expires", publish_with_expires),
TEST_ONE_TAG("Publish with network state changes", publish_with_network_state_changes, "presence"),
/*TEST_ONE_TAG("Call with presence", call_with_presence, "LeaksMemory"),*/
TEST_NO_TAG("Unsubscribe while subscribing", unsubscribe_while_subscribing),
TEST_NO_TAG("Presence information", presence_information),
TEST_NO_TAG("App managed presence failure", subscribe_failure_handle_by_app),
TEST_ONE_TAG("App managed presence failure", subscribe_failure_handle_by_app, "LeaksMemory"),
TEST_NO_TAG("Presence SUBSCRIBE forked", subscribe_presence_forked),
TEST_NO_TAG("Presence SUBSCRIBE expired", subscribe_presence_expired),
};