Commit c329b106 authored by Simon Morlat's avatar Simon Morlat
Browse files

implement independant controls for media and sip network reachabilities.

parent b689c4bc
......@@ -102,6 +102,8 @@ static FILE * liblinphone_log_collection_file = NULL;
static size_t liblinphone_log_collection_file_size = 0;
static bool_t liblinphone_serialize_logs = FALSE;
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
static void set_sip_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
static void set_media_network_reachable(LinphoneCore* lc,bool_t isReachable);
static void linphone_core_run_hooks(LinphoneCore *lc);
#include "enum.h"
......@@ -2556,7 +2558,7 @@ void linphone_core_iterate(LinphoneCore *lc){
if (lc->network_reachable_to_be_notified) {
lc->network_reachable_to_be_notified=FALSE;
linphone_core_notify_network_reachable(lc,lc->network_reachable);
linphone_core_notify_network_reachable(lc,lc->sip_network_reachable);
}
if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) {
if (sal_get_root_ca(lc->sal)) {
......@@ -2696,7 +2698,7 @@ void linphone_core_iterate(LinphoneCore *lc){
linphone_core_run_hooks(lc);
linphone_core_do_plugin_tasks(lc);
if (lc->network_reachable && lc->netup_time!=0 && (current_real_time-lc->netup_time)>3){
if (lc->sip_network_reachable && lc->netup_time!=0 && (current_real_time-lc->netup_time)>3){
/*not do that immediately, take your time.*/
linphone_core_send_initial_subscribes(lc);
}
......@@ -6166,7 +6168,7 @@ void sip_config_uninit(LinphoneCore *lc)
lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up);
lp_config_set_int(lc->config,"sip","register_only_when_upnp_is_ok",config->register_only_when_upnp_is_ok);
if (lc->network_reachable) {
if (lc->sip_network_reachable) {
for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
_linphone_proxy_config_unregister(cfg); /* to unregister without changing the stored flag enable_register */
......@@ -6431,17 +6433,17 @@ static void linphone_core_uninit(LinphoneCore *lc)
ms_list_free_with_data(lc->vtable_refs,(void (*)(void *))v_table_reference_destroy);
}
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){
static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, time_t curtime){
// second get the list of available proxies
const MSList *elem=linphone_core_get_proxy_config_list(lc);
if (lc->network_reachable==isReachable) return; // no change, ignore.
if (lc->sip_network_reachable==is_sip_reachable) return; // no change, ignore.
lc->network_reachable_to_be_notified=TRUE;
ms_message("Network state is now [%s]",isReachable?"UP":"DOWN");
ms_message("SIP network reachability state is now [%s]",is_sip_reachable?"UP":"DOWN");
for(;elem!=NULL;elem=elem->next){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
if (linphone_proxy_config_register_enabled(cfg) ) {
if (!isReachable) {
if (!is_sip_reachable) {
linphone_proxy_config_stop_refreshing(cfg);
linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone,"Registration impossible (network down)");
}else{
......@@ -6450,26 +6452,23 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
}
}
lc->netup_time=curtime;
lc->network_reachable=isReachable;
lc->sip_network_reachable=is_sip_reachable;
if (!lc->network_reachable){
if (!lc->sip_network_reachable){
linphone_core_invalidate_friend_subscriptions(lc);
sal_reset_transports(lc->sal);
/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
}else{
linphone_core_resolve_stun_server(lc);
if (lp_config_get_int(lc->config, "net", "recreate_sockets_when_network_is_up", 0)){
ms_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets);
}
}
#ifdef BUILD_UPNP
if(lc->upnp == NULL) {
if(isReachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
if(is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
lc->upnp = linphone_upnp_context_new(lc);
}
} else {
if(!isReachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
if(!is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
linphone_upnp_context_destroy(lc->upnp);
lc->upnp = NULL;
}
......@@ -6477,9 +6476,37 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
#endif
}
void linphone_core_repair_calls(LinphoneCore *lc){
if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1) && lc->media_network_reachable){
/*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
}
}
static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reachable){
if (lc->media_network_reachable==is_media_reachable) return; // no change, ignore.
ms_message("Media network reachability state is now [%s]",is_media_reachable?"UP":"DOWN");
lc->media_network_reachable=is_media_reachable;
if (!lc->media_network_reachable){
/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
}else{
if (lp_config_get_int(lc->config, "net", "recreate_sockets_when_network_is_up", 0)){
ms_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets);
}
linphone_core_repair_calls(lc);
}
}
static void set_network_reachable(LinphoneCore *lc, bool_t is_network_reachable, time_t curtime){
set_sip_network_reachable(lc, is_network_reachable, curtime);
set_media_network_reachable(lc, is_network_reachable);
}
void linphone_core_refresh_registers(LinphoneCore* lc) {
const MSList *elem;
if (!lc->network_reachable) {
if (!lc->sip_network_reachable) {
ms_warning("Refresh register operation not available (network unreachable)");
return;
}
......@@ -6503,17 +6530,30 @@ void __linphone_core_invalidate_registers(LinphoneCore* lc){
}
}
void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) {
//first disable automatic mode
static void disable_internal_network_reachability_detection(LinphoneCore *lc){
if (lc->auto_net_state_mon) {
ms_message("Disabling automatic network state monitoring");
lc->auto_net_state_mon=FALSE;
}
set_network_reachable(lc,isReachable, ms_time(NULL));
}
void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) {
disable_internal_network_reachability_detection(lc);
set_network_reachable(lc, isReachable, ms_time(NULL));
}
void linphone_core_set_media_network_reachable(LinphoneCore *lc, bool_t is_reachable){
disable_internal_network_reachability_detection(lc);
set_media_network_reachable(lc, is_reachable);
}
void linphone_core_set_sip_network_reachable(LinphoneCore *lc, bool_t is_reachable){
disable_internal_network_reachability_detection(lc);
set_sip_network_reachable(lc, is_reachable, ms_time(NULL));
}
bool_t linphone_core_is_network_reachable(LinphoneCore* lc) {
return lc->network_reachable;
return lc->sip_network_reachable;
}
ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc){
return sal_get_socket(lc->sal);
......
......@@ -3743,6 +3743,22 @@ LINPHONE_PUBLIC void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t
*/
LINPHONE_PUBLIC bool_t linphone_core_is_network_reachable(LinphoneCore* lc);
/**
* @ingroup network_parameters
* This method is called by the application to notify the linphone core library when the SIP network is reachable.
* This is for advanced usage, when SIP and RTP layers are required to use different interfaces.
* Most applications just need linphone_core_set_network_reachable().
*/
LINPHONE_PUBLIC void linphone_core_set_sip_network_reachable(LinphoneCore* lc,bool_t value);
/**
* @ingroup network_parameters
* This method is called by the application to notify the linphone core library when the media (RTP) network is reachable.
* This is for advanced usage, when SIP and RTP layers are required to use different interfaces.
* Most applications just need linphone_core_set_network_reachable().
*/
LINPHONE_PUBLIC void linphone_core_set_media_network_reachable(LinphoneCore* lc,bool_t value);
/**
* @ingroup network_parameters
* enable signaling keep alive. small udp packet sent periodically to keep udp NAT association
......
......@@ -921,13 +921,16 @@ struct _LinphoneCore
bool_t preview_finished;
bool_t auto_net_state_mon;
bool_t network_reachable;
bool_t sip_network_reachable;
bool_t media_network_reachable;
bool_t network_reachable_to_be_notified; /*set to true when state must be notified in next iterate*/
bool_t use_preview_window;
bool_t network_last_status;
bool_t ringstream_autorelease;
bool_t vtables_running;
bool_t pad[3];
char localip[LINPHONE_IPADDR_SIZE];
int device_rotation;
int max_calls;
......@@ -1037,6 +1040,7 @@ void ec_calibrator_destroy(EcCalibrator *ecc);
void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed);
void linphone_call_set_broken(LinphoneCall *call);
void linphone_call_repair_if_broken(LinphoneCall *call);
void linphone_core_repair_calls(LinphoneCore *lc);
void linphone_core_preempt_sound_resources(LinphoneCore *lc);
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
......
......@@ -1362,7 +1362,7 @@ static bool_t can_register(LinphoneProxyConfig *cfg){
}
#endif //BUILD_UPNP
if (lc->sip_conf.register_only_when_network_is_up){
return lc->network_reachable;
return lc->sip_network_reachable;
}
return TRUE;
}
......@@ -1434,13 +1434,9 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
cfg->state=state;
}
if (lc){
linphone_core_notify_registration_state_changed(lc,cfg,state,message);
if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1)){
/*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
}
linphone_core_repair_calls(lc);
}
} else {
/*state already reported*/
......
......@@ -367,7 +367,7 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
ms_mutex_lock(&lupnp->mutex);
if(lupnp->lc->network_reachable) {
if(lupnp->lc->sip_network_reachable) {
/* Send port binding removes */
if(lupnp->sip_udp != NULL) {
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp, TRUE);
......
......@@ -5474,6 +5474,7 @@ static void _call_with_network_switch(bool_t use_ice, bool_t with_socket_refresh
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
MSList *lcs = NULL;
int ice_reinvite = use_ice ? 1 : 0;
bool_t call_ok;
lcs = ms_list_append(lcs, marie->lc);
......@@ -5503,9 +5504,10 @@ static void _call_with_network_switch(bool_t use_ice, bool_t with_socket_refresh
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2));
/*pauline shall receive a reINVITE to update the session*/
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallUpdating, 1+ice_reinvite));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1+ice_reinvite));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2+ice_reinvite));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2+ice_reinvite));
/*check that media is back*/
check_media_direction(marie, linphone_core_get_current_call(marie->lc), lcs, LinphoneMediaDirectionSendRecv, LinphoneMediaDirectionInvalid);
......@@ -5532,6 +5534,69 @@ static void call_with_network_switch_and_socket_refresh(void){
_call_with_network_switch(TRUE, TRUE);
}
static void call_with_sip_and_rtp_independant_switches(){
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
MSList *lcs = NULL;
bool_t call_ok;
bool_t use_ice = TRUE;
bool_t with_socket_refresh = TRUE;
lcs = ms_list_append(lcs, marie->lc);
lcs = ms_list_append(lcs, pauline->lc);
if (use_ice){
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
}
if (with_socket_refresh){
lp_config_set_int(linphone_core_get_config(marie->lc), "net", "recreate_sockets_when_network_is_up", 1);
lp_config_set_int(linphone_core_get_config(pauline->lc), "net", "recreate_sockets_when_network_is_up", 1);
}
linphone_core_set_media_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
if (!call_ok) goto end;
wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000);
if (use_ice) BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
/*marie looses the SIP network and reconnects*/
linphone_core_set_sip_network_reachable(marie->lc, FALSE);
wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000);
/*marie will reconnect and register*/
linphone_core_set_sip_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2));
wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000);
/*at this stage, no reINVITE is expected to be send*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallUpdating, 1, int, "%i"); /*1: because of ICE reinvite*/
/*now we notify the a reconnection of media network*/
linphone_core_set_media_network_reachable(marie->lc, FALSE);
linphone_core_set_media_network_reachable(marie->lc, TRUE);
/*pauline shall receive a reINVITE to update the session*/
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallUpdating, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 3));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 3));
/*check that media is back*/
check_media_direction(marie, linphone_core_get_current_call(marie->lc), lcs, LinphoneMediaDirectionSendRecv, LinphoneMediaDirectionInvalid);
liblinphone_tester_check_rtcp(pauline, marie);
if (use_ice) BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
/*pauline shall be able to end the call without problem now*/
end_call(pauline, marie);
end:
ms_list_free(lcs);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#ifdef CALL_LOGS_STORAGE_ENABLED
static void call_logs_if_no_db_set(void) {
......@@ -5987,8 +6052,8 @@ test_t call_tests[] = {
{ "Call established with rejected info during re-invite",call_established_with_rejected_info_during_reinvite},
{ "Call redirected by callee", call_redirect},
{ "Call with specified codec bitrate", call_with_specified_codec_bitrate},
{ "Call with no audio codec", call_with_no_audio_codec},
{ "Video call with no audio and no video codec", video_call_with_no_audio_and_no_video_codec},
{ "Call with no audio codec", call_with_no_audio_codec},
{ "Video call with no audio and no video codec", video_call_with_no_audio_and_no_video_codec},
{ "Call with in-dialog UPDATE request", call_with_in_dialog_update },
{ "Call with in-dialog codec change", call_with_in_dialog_codec_change },
{ "Call with in-dialog codec change no sdp", call_with_in_dialog_codec_change_no_sdp },
......@@ -6025,6 +6090,7 @@ test_t call_tests[] = {
{ "Call with network switch in early state 2", call_with_network_switch_in_early_state_2 },
{ "Call with network switch and ICE", call_with_network_switch_and_ice },
{ "Call with network switch with socket refresh", call_with_network_switch_and_socket_refresh },
{ "Call with SIP and RTP independant switches", call_with_sip_and_rtp_independant_switches},
{ "Call with rtcp-mux", call_with_rtcp_mux},
{ "Call with rtcp-mux not accepted", call_with_rtcp_mux_not_accepted},
{ "Call with ICE and rtcp-mux", call_with_ice_and_rtcp_mux},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment