Fix registration issues when tunneling is enabled

This commit is contained in:
François Grisez 2014-09-23 16:02:42 +02:00
parent 54a47a2bd7
commit df4385b17c
5 changed files with 78 additions and 97 deletions

View file

@ -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();
}
}
}

View file

@ -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<Event> mEvq;
std::list <ServerAddr> 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 <ServerAddr> mServerAddrs;
UdpMirrorClientList mUdpMirrorClients;
UdpMirrorClientList::iterator mCurrentUdpMirrorClient;
LinphoneRtpTransportFactories mTransportFactories;
Mutex mMutex;
std::queue<Event> mEvq;
#ifndef USE_BELLESIP
TunnelSocket *mSipSocket;
eXosip_transport_hooks_t mExosipTransport;
#endif
};
/**

View file

@ -268,7 +268,6 @@ LINPHONE_PUBLIC void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel);
*/
LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel);
/**
* @}
**/

View file

@ -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;
}

View file

@ -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: <sip:pauline@192.168.0.201>;.[...]
To:
Contact: <sip:pauline@91.121.209.194:43867>;[....] (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: <sip:pauline@192.168.0.201>;.[...]
To:
Contact: <sip:pauline@91.121.209.194:43867>;[....] (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 = {