From df4385b17cf738b0db6ebba3827e2393a9e9974b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Tue, 23 Sep 2014 16:02:42 +0200 Subject: [PATCH] Fix registration issues when tunneling is enabled --- coreapi/TunnelManager.cc | 85 ++++++++++++++------------------------- coreapi/TunnelManager.hh | 36 ++++++++--------- coreapi/linphone_tunnel.h | 1 - coreapi/proxy.c | 7 +--- tester/transport_tester.c | 46 +++++++++++++-------- 5 files changed, 78 insertions(+), 97 deletions(-) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index d88212c68..0fd7212fa 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -111,6 +111,7 @@ void TunnelManager::startClient() { if(mTunnelizeSipPackets) { sal_enable_tunnel(mCore->sal, mTunnelClient); } + mConnecting = true; } void TunnelManager::stopClient(){ @@ -148,11 +149,12 @@ TunnelManager::TunnelManager(LinphoneCore* lc) : mExosipTransport(NULL), #endif mMode(LinphoneTunnelModeDisable), - mTunnelClient(NULL), - mIsConnected(false), - mHttpProxyPort(0), - mPreviousRegistrationEnabled(false), + mAutoDetecting(false), + mConnecting(false), + mScheduledRegistration(false), mTunnelizeSipPackets(true), + mTunnelClient(NULL), + mHttpProxyPort(0), mVTable(NULL) { linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this); @@ -175,79 +177,46 @@ TunnelManager::~TunnelManager(){ linphone_vtable_destroy(mVTable); } -void TunnelManager::registration(){ - // registration occurs always after an unregistation has been made. First we - // need to reset the previous registration mode +void TunnelManager::doRegistration(){ LinphoneProxyConfig* lProxy; linphone_core_get_default_proxy(mCore, &lProxy); if (lProxy) { - linphone_proxy_config_edit(lProxy); - linphone_proxy_config_enable_register(lProxy,mPreviousRegistrationEnabled); - linphone_proxy_config_done(lProxy); + if(linphone_proxy_config_get_state(lProxy) != LinphoneRegistrationProgress) { + linphone_proxy_config_refresh_register(lProxy); + mScheduledRegistration = false; + } else { + mScheduledRegistration = true; + } + } else { + mScheduledRegistration = false; } } void TunnelManager::processTunnelEvent(const Event &ev){ if (ev.mData.mConnected){ ms_message("Tunnel is up, registering now"); - registration(); + doRegistration(); } else { ms_error("Tunnel has been disconnected"); } + mConnecting = false; } -void TunnelManager::waitUnRegistration() { - LinphoneProxyConfig* lProxy; - - linphone_core_get_default_proxy(mCore, &lProxy); - if (lProxy){ - mPreviousRegistrationEnabled=linphone_proxy_config_register_enabled(lProxy); - if (linphone_proxy_config_is_registered(lProxy)) { - int i=0; - linphone_proxy_config_edit(lProxy); - linphone_proxy_config_enable_register(lProxy,FALSE); - linphone_proxy_config_done(lProxy); - sal_unregister(lProxy->op); - //make sure unregister is sent and authenticated - do{ - linphone_core_iterate(mCore); - ms_usleep(20000); - if (i>100){ - ms_message("tunnel: timeout for unregistration expired, giving up"); - break; - } - i++; - }while(linphone_proxy_config_is_registered(lProxy)); - ms_message("Unregistration %s", linphone_proxy_config_is_registered(lProxy)?"failed":"succeeded"); - }else{ - ms_message("No registration pending"); - } - } -} - -/*Each time tunnel is enabled/disabled, we need to unregister previous session and re-register. Since tunnel initialization -is asynchronous, we temporary disable auto register while tunnel sets up, and reenable it when re-registering. */ void TunnelManager::setMode(LinphoneTunnelMode mode) { if(mMode != mode) { - waitUnRegistration(); switch(mode) { case LinphoneTunnelModeEnable: mMode = mode; startClient(); - /* registration is done by proccessTunnelEvent() when the tunnel - the tunnel succeed to connect */ break; case LinphoneTunnelModeDisable: mMode = mode; stopClient(); - registration(); + doRegistration(); break; case LinphoneTunnelModeAuto: mMode = mode; autoDetect(); - /* Registration is not needed because processUdpMirrorEvent() will - call either connect() or disconnect(). Should disconnect() is called, - processUdpMirrorEvent() care to call registratin() */ break; default: ms_error("TunnelManager::setMode(): invalid mode (%d)", mode); @@ -263,6 +232,9 @@ void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){ } void TunnelManager::onIterate(){ + if(mScheduledRegistration) { + doRegistration(); + } mMutex.lock(); while(!mEvq.empty()){ Event ev=mEvq.front(); @@ -331,18 +303,18 @@ void TunnelManager::processUdpMirrorEvent(const Event &ev){ if (ev.mData.mHaveUdp) { LOGI("Tunnel is not required, disabling"); stopClient(); - registration(); + doRegistration(); + mAutoDetecting = false; } else { mCurrentUdpMirrorClient++; if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) { - // enable tunnel but also try backup server LOGI("Tunnel is required, enabling; Trying backup udp mirror"); - UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient; lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this); } else { LOGI("Tunnel is required, enabling; no backup udp mirror available"); startClient(); + mAutoDetecting = false; } } } @@ -369,7 +341,10 @@ void TunnelManager::networkReachableCb(LinphoneCore *lc, bool_t reachable) { } void TunnelManager::autoDetect() { - // first check if udp mirrors was provisionned + if(mAutoDetecting) { + LOGE("Cannot start auto detection. One auto detection is going on"); + return; + } if (mUdpMirrorClients.empty()) { LOGE("No UDP mirror server configured aborting auto detection"); return; @@ -377,6 +352,7 @@ void TunnelManager::autoDetect() { mCurrentUdpMirrorClient = mUdpMirrorClients.begin(); UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient; lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this); + mAutoDetecting = true; } void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) { @@ -389,10 +365,9 @@ void TunnelManager::tunnelizeSipPackets(bool enable){ if(enable != mTunnelizeSipPackets) { mTunnelizeSipPackets = enable; if(isConnected()) { - waitUnRegistration(); if(mTunnelizeSipPackets) sal_enable_tunnel(mCore->sal, mTunnelClient); else sal_disable_tunnel(mCore->sal); - registration(); + doRegistration(); } } } diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index 38b6b90e3..9b1a4c3a9 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -167,37 +167,37 @@ namespace belledonnecomm { private: void onIterate(); - void registration(); - void waitUnRegistration(); - void processTunnelEvent(const Event &ev); - void processUdpMirrorEvent(const Event &ev); - void postEvent(const Event &ev); + void doRegistration(); void startClient(); void stopClient(); void autoDetect(); + void processTunnelEvent(const Event &ev); + void processUdpMirrorEvent(const Event &ev); + void postEvent(const Event &ev); private: LinphoneCore* mCore; -#ifndef USE_BELLESIP - TunnelSocket *mSipSocket; - eXosip_transport_hooks_t mExosipTransport; -#endif LinphoneTunnelMode mMode; - std::queue mEvq; - std::list mServerAddrs; - UdpMirrorClientList mUdpMirrorClients; - UdpMirrorClientList::iterator mCurrentUdpMirrorClient; + bool mAutoDetecting; + bool mConnecting; + bool mScheduledRegistration; + bool mTunnelizeSipPackets; TunnelClient* mTunnelClient; - Mutex mMutex; - bool mIsConnected; - LinphoneRtpTransportFactories mTransportFactories; std::string mHttpUserName; std::string mHttpPasswd; std::string mHttpProxyHost; int mHttpProxyPort; - bool mPreviousRegistrationEnabled; - bool mTunnelizeSipPackets; LinphoneCoreVTable *mVTable; + std::list mServerAddrs; + UdpMirrorClientList mUdpMirrorClients; + UdpMirrorClientList::iterator mCurrentUdpMirrorClient; + LinphoneRtpTransportFactories mTransportFactories; + Mutex mMutex; + std::queue mEvq; +#ifndef USE_BELLESIP + TunnelSocket *mSipSocket; + eXosip_transport_hooks_t mExosipTransport; +#endif }; /** diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index 3a2c66330..fa8317d1d 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -268,7 +268,6 @@ LINPHONE_PUBLIC void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); */ LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel); - /** * @} **/ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index eab2e70a7..13fa6e048 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1408,12 +1408,7 @@ static bool_t can_register(LinphoneProxyConfig *cfg){ } #endif //BUILD_UPNP if (lc->sip_conf.register_only_when_network_is_up){ - LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); - if (tunnel && linphone_tunnel_get_mode(tunnel)){ - return linphone_tunnel_connected(tunnel); - }else{ - return lc->network_reachable; - } + return lc->network_reachable; } return TRUE; } diff --git a/tester/transport_tester.c b/tester/transport_tester.c index 014481f32..3726b84fd 100644 --- a/tester/transport_tester.c +++ b/tester/transport_tester.c @@ -59,7 +59,7 @@ static char* get_public_contact_ip(LinphoneCore* lc) { ms_free(contact); return ms_strdup(contact_host_ip); } -static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, LinphoneMediaEncryption encryption) { +static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption) { if (linphone_core_tunnel_available()){ char *tmp_char; LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc"); @@ -69,7 +69,7 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon LinphoneAddress *server_addr = linphone_address_new(linphone_proxy_config_get_server_addr(proxy)); LinphoneAddress *route = linphone_address_new(linphone_proxy_config_get_route(proxy)); const char * tunnel_ip = get_ip_from_hostname("tunnel.linphone.org"); - char *public_ip; + char *public_ip, *public_ip2=NULL; CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,1)); public_ip = get_public_contact_ip(pauline->lc); @@ -77,7 +77,7 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon linphone_core_set_media_encryption(pauline->lc, encryption); - if (use_tunnel){ + if (tunnel_mode != LinphoneTunnelModeDisable){ LinphoneTunnel *tunnel = linphone_core_get_tunnel(pauline->lc); LinphoneTunnelConfig *config = linphone_tunnel_config_new(); @@ -91,24 +91,30 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon tmp_char = linphone_address_as_string(route); linphone_proxy_config_set_route(proxy, tmp_char); ms_free(tmp_char); - linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeEnable); - if(with_sip) linphone_tunnel_enable_sip(tunnel, with_sip); linphone_tunnel_config_set_host(config, "tunnel.linphone.org"); linphone_tunnel_config_set_port(config, 443); + linphone_tunnel_config_set_remote_udp_mirror_port(config, 12345); linphone_tunnel_add_server(tunnel, config); + linphone_tunnel_set_mode(tunnel, tunnel_mode); + linphone_tunnel_enable_sip(tunnel, with_sip); linphone_proxy_config_done(proxy); /*enabling the tunnel cause another REGISTER to be made*/ CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,2)); - /* Ensure that we did use the tunnel. If so, we should see contact changed from: - Contact: ;.[...] - To: - Contact: ;[....] (91.121.209.194 must be tunnel.liphone.org) - */ - ms_free(public_ip); - public_ip = get_public_contact_ip(pauline->lc); - CU_ASSERT_STRING_EQUAL(public_ip, tunnel_ip); + if(tunnel_mode == LinphoneTunnelModeEnable) { + /* Ensure that we did use the tunnel. If so, we should see contact changed from: + Contact: ;.[...] + To: + Contact: ;[....] (91.121.209.194 must be tunnel.liphone.org) + */ + ms_free(public_ip); + public_ip = get_public_contact_ip(pauline->lc); + CU_ASSERT_STRING_EQUAL(public_ip, tunnel_ip); + } else { + public_ip2 = get_public_contact_ip(pauline->lc); + CU_ASSERT_STRING_EQUAL(public_ip, public_ip2); + } } CU_ASSERT_TRUE(call(pauline,marie)); @@ -121,6 +127,7 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon end_call(pauline,marie); ms_free(public_ip); + if(public_ip2 != NULL) ms_free(public_ip2); linphone_address_destroy(server_addr); linphone_address_destroy(route); linphone_core_manager_destroy(pauline); @@ -131,21 +138,26 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon } static void call_with_tunnel(void) { - call_with_transport_base(TRUE, TRUE, LinphoneMediaEncryptionNone); + call_with_transport_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone); } static void call_with_tunnel_srtp(void) { - call_with_transport_base(TRUE, TRUE, LinphoneMediaEncryptionSRTP); + call_with_transport_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionSRTP); } static void call_with_tunnel_without_sip(void) { - call_with_transport_base(TRUE, FALSE, LinphoneMediaEncryptionNone); + call_with_transport_base(LinphoneTunnelModeEnable, FALSE, LinphoneMediaEncryptionNone); +} + +static void call_with_tunnel_auto(void) { + call_with_transport_base(LinphoneTunnelModeAuto, TRUE, LinphoneMediaEncryptionNone); } test_t transport_tests[] = { { "Tunnel only", call_with_tunnel }, { "Tunnel with SRTP", call_with_tunnel_srtp }, - { "Tunnel without SIP", call_with_tunnel_without_sip } + { "Tunnel without SIP", call_with_tunnel_without_sip }, + { "Tunnel in automatic mode", call_with_tunnel_auto } }; test_suite_t transport_test_suite = {