diff --git a/configure.ac b/configure.ac index 05dc40e74..04e23a189 100644 --- a/configure.ac +++ b/configure.ac @@ -478,7 +478,7 @@ AC_ARG_ENABLE(tunnel, esac],[enable_tunnel=false]) AM_CONDITIONAL(BUILD_TUNNEL, test x$enable_tunnel = xtrue) if test x$enable_tunnel = xtrue; then - PKG_CHECK_MODULES(TUNNEL, tunnel >= 0.3.1) + PKG_CHECK_MODULES(TUNNEL, tunnel >= 0.3.3) TUNNEL_CFLAGS+="-DTUNNEL_ENABLED" AC_SUBST(TUNNEL_CFLAGS) AC_SUBST(TUNNEL_LIBS) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 44ccfd845..6d0a82a8d 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -40,13 +40,15 @@ liblinphone_la_SOURCES=\ siplogin.c \ lsd.c linphonecore_utils.h \ ec-calibrator.c \ - conference.c + conference.c \ + linphone_tunnel.cc + if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c endif if BUILD_TUNNEL -liblinphone_la_SOURCES+=TunnelManager.cc TunnelManager.hh linphone_tunnel.cc +liblinphone_la_SOURCES+=TunnelManager.cc TunnelManager.hh endif @@ -89,3 +91,6 @@ AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ if BUILD_WIZARD AM_CFLAGS+= -DBUILD_WIZARD endif + +AM_CXXFLAGS=$(AM_CFLAGS) + diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index bbf9cc87d..5eb93b7f1 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -23,15 +23,6 @@ #include #endif -#ifdef recvfrom -#undef recvfrom -#endif -#ifdef sendto -#undef sendto -#endif -#ifdef select -#undef select -#endif using namespace belledonnecomm; @@ -176,9 +167,7 @@ void TunnelManager::start() { const ServerAddr &addr=*it; mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort); } - if(!mHttpUserName.empty()) { - mTunnelClient->setHttpProxyAuthInfo(mHttpUserName.c_str(), mHttpPasswd.c_str()); - } + mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str()); } mTunnelClient->start(); @@ -214,7 +203,8 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mCallback(NULL) ,mEnabled(false) ,mTunnelClient(NULL) -,mAutoDetectStarted(false) { +,mAutoDetectStarted(false) +,mHttpProxyPort(0){ mExosipTransport.data=this; mExosipTransport.recvfrom=eXosipRecvfrom; @@ -281,6 +271,25 @@ void TunnelManager::processTunnelEvent(){ } } +void TunnelManager::waitUnRegistration(){ + LinphoneProxyConfig* lProxy; + linphone_core_get_default_proxy(mCore, &lProxy); + if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) { + int i; + linphone_proxy_config_edit(lProxy); + //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_get_state(lProxy)!=LinphoneRegistrationCleared); + } +} + void TunnelManager::enable(bool isEnable) { ms_message("Turning tunnel [%s]",(isEnable?"on":"off")); if (isEnable && !mEnabled){ @@ -288,29 +297,15 @@ void TunnelManager::enable(bool isEnable) { //1 save transport linphone_core_get_sip_transports(mCore, &mRegularTransport); //2 unregister - LinphoneProxyConfig* lProxy; - linphone_core_get_default_proxy(mCore, &lProxy); - if (lProxy) { - linphone_proxy_config_edit(lProxy); - //make sure unregister is sent - linphone_core_iterate(mCore); - } + waitUnRegistration(); //3 insert tunnel start(); }else if (!isEnable && mEnabled){ + //1 unregister + waitUnRegistration(); + mEnabled=false; stopClient(); - //1 unregister - LinphoneProxyConfig* lProxy; - linphone_core_get_default_proxy(mCore, &lProxy); - if (lProxy) { - linphone_proxy_config_edit(lProxy); - //make sure unregister is sent - linphone_core_iterate(mCore); - } - - //make sure unregister is sent - linphone_core_iterate(mCore); linphone_core_set_rtp_transport_factories(mCore,NULL); @@ -318,6 +313,8 @@ void TunnelManager::enable(bool isEnable) { //Restore transport linphone_core_set_sip_transports(mCore, &mRegularTransport); //register + LinphoneProxyConfig* lProxy; + linphone_core_get_default_proxy(mCore, &lProxy); if (lProxy) { linphone_proxy_config_done(lProxy); } @@ -420,6 +417,14 @@ void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd); } +void TunnelManager::setHttpProxy(const char *host,int port, const char *username, const char *passwd){ + mHttpUserName=username?username:""; + mHttpPasswd=passwd?passwd:""; + mHttpProxyPort=(port>0) ? port : 0; + mHttpProxyHost=host ? host : ""; + if (mTunnelClient) mTunnelClient->setHttpProxy(host, port, username, passwd); +} + LinphoneCore *TunnelManager::getLinphoneCore(){ return mCore; } diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index 0cc560e90..1fb55429e 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -128,6 +128,7 @@ class UdpMirrorClient; * Get associated Linphone Core. */ LinphoneCore *getLinphoneCore(); + virtual void setHttpProxy(const char *host,int port, const char *username, const char *passwd); private: typedef std::list UdpMirrorClientList; virtual bool isStarted(); @@ -140,7 +141,7 @@ class UdpMirrorClient; static void tunnelCallback(bool connected, TunnelManager *zis); static void sOnIterate(TunnelManager *zis); static void UdpMirrorClientListener(bool result, void* data); - + void waitUnRegistration(); void processTunnelEvent(); LinphoneCore* mCore; LCSipTransports mRegularTransport; @@ -159,7 +160,9 @@ class UdpMirrorClient; bool mAutoDetectStarted; LinphoneRtpTransportFactories mTransportFactories; std::string mHttpUserName; - std::string mHttpPasswd; + std::string mHttpPasswd; + std::string mHttpProxyHost; + int mHttpProxyPort; }; /** diff --git a/coreapi/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index 5a341ac7b..5f3bd7284 100644 --- a/coreapi/linphone_tunnel.cc +++ b/coreapi/linphone_tunnel.cc @@ -29,36 +29,64 @@ #include "private.h" #include "lpconfig.h" + +LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ + return lc->tunnel; +} + +#ifdef TUNNEL_ENABLED + static inline belledonnecomm::TunnelManager *bcTunnel(LinphoneTunnel *tunnel){ return (belledonnecomm::TunnelManager *)tunnel; } +static inline _LpConfig *config(LinphoneTunnel *tunnel){ + return ((belledonnecomm::TunnelManager *)tunnel)->getLinphoneCore()->config; +} + extern "C" LinphoneTunnel* linphone_core_tunnel_new(LinphoneCore *lc){ LinphoneTunnel* tunnel= (LinphoneTunnel*) new belledonnecomm::TunnelManager(lc); return tunnel; } -LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ - return lc->tunnel; -} - void linphone_tunnel_destroy(LinphoneTunnel *tunnel){ delete bcTunnel(tunnel); } +static void add_server_to_config(LinphoneTunnel *tunnel, const char *host, int port){ + const char *orig=lp_config_get_string(config(tunnel),"tunnel","server_addresses", NULL); + char *tmp; + if (orig){ + tmp=ms_strdup_printf("%s %s:%i",orig,host,port); + }else tmp=ms_strdup_printf("%s:%i",host, port); + lp_config_set_string(config(tunnel),"tunnel","server_addresses",tmp); + ms_free(tmp); +} + void linphone_tunnel_add_server(LinphoneTunnel *tunnel, const char *host, int port){ bcTunnel(tunnel)->addServer(host, port); + add_server_to_config(tunnel,host,port); } void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror, int delay){ bcTunnel(tunnel)->addServer(host, port, remote_udp_mirror, delay); + /*FIXME, udp-mirror feature not saved in config*/ + add_server_to_config(tunnel,host,port); +} + +char *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){ + const char *tmp=lp_config_get_string(config(tunnel),"tunnel","server_addresses",NULL); + if (tmp) return ms_strdup(tmp); + return NULL; } void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ bcTunnel(tunnel)->cleanServers(); + lp_config_set_string(config(tunnel),"tunnel","server_addresses",NULL); } void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ + lp_config_set_int(config(tunnel),"tunnel","enabled",(int)enabled); bcTunnel(tunnel)->enable(enabled); } @@ -66,18 +94,64 @@ bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ return bcTunnel(tunnel)->isEnabled(); } -void linphone_tunnel_enable_logs(LinphoneTunnel *tunnel, bool_t enabled){ - bcTunnel(tunnel)->enableLogs(enabled); +static OrtpLogFunc tunnelOrtpLogHandler=NULL; + +/* +#define TUNNEL_DEBUG (1) +#define TUNNEL_INFO (1<<1) +#define TUNNEL_NOTICE (1<<2) +#define TUNNEL_WARN (1<<3) +#define TUNNEL_ERROR (1<<4) +#define TUNNEL_ALERT (1<<5) +#define TUNNEL_FATAL (1<<6) +*/ + +static void tunnelLogHandler(int level, const char *fmt, va_list l){ + if (tunnelOrtpLogHandler){ + OrtpLogLevel ortp_level=ORTP_DEBUG; + switch(level){ + case TUNNEL_DEBUG: + ortp_level=ORTP_DEBUG; + break; + case TUNNEL_INFO: + ortp_level=ORTP_MESSAGE; + break; + case TUNNEL_NOTICE: + ortp_level=ORTP_MESSAGE; + break; + case TUNNEL_WARN: + ortp_level=ORTP_WARNING; + break; + case TUNNEL_ERROR: + ortp_level=ORTP_ERROR; + break; + case TUNNEL_ALERT: + ortp_level=ORTP_ERROR; + break; + case TUNNEL_FATAL: + ortp_level=ORTP_FATAL; + break; + default: + ms_fatal("Unexepcted tunnel log %i: %s",level,fmt); + break; + } + tunnelOrtpLogHandler(ortp_level,fmt,l); + } } -void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, LogHandler logHandler){ - bcTunnel(tunnel)->enableLogs(enabled, logHandler); +void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){ + tunnelOrtpLogHandler=logHandler; + bcTunnel(tunnel)->enableLogs(enabled, tunnelLogHandler); } void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char* username,const char* passwd){ bcTunnel(tunnel)->setHttpProxyAuthInfo(username, passwd); } +void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){ + bcTunnel(tunnel)->setHttpProxy(host, port, username, passwd); +} + void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ bcTunnel(tunnel)->reconnect(); } @@ -86,56 +160,6 @@ void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ bcTunnel(tunnel)->autoDetect(); } - -static inline _LpConfig *config(LinphoneTunnel *tunnel){ - return ((belledonnecomm::TunnelManager *)tunnel)->getLinphoneCore()->config; -} - -/** - * Set tunnel server addresses. "host1:port1 host2:port2 host3:port3" -**/ -void linphone_tunnel_set_server_addresses(LinphoneTunnel *tunnel, const char *addresses){ - lp_config_set_string(config(tunnel),"tunnel","server_addresses",addresses); -} - -/** - * Get tunnel server addresses. "host1:port1 host2:port2 host3:port3" -**/ -const char *linphone_tunnel_get_server_addresses(LinphoneTunnel *tunnel){ - return lp_config_get_string(config(tunnel),"tunnel","server_addresses", NULL); -} - -/** - * Set tunnel state. -**/ -void linphone_tunnel_set_state(LinphoneTunnel *tunnel, LinphoneTunnelState state){ - switch (state) { - case LinphoneTunnelEnabled: - lp_config_set_string(config(tunnel),"tunnel","tunnel_state","enabled"); - break; - case LinphoneTunnelDisabled: - lp_config_set_string(config(tunnel),"tunnel","tunnel_state","disabled"); - break; - case LinphoneTunnelAuto: - lp_config_set_string(config(tunnel),"tunnel","tunnel_state","auto"); - break; - } -} - -/** - * Get tunnel state. -**/ -LinphoneTunnelState linphone_tunnel_get_state(LinphoneTunnel *tunnel){ - const char *state=lp_config_get_string(config(tunnel),"tunnel","tunnel_state","disabled"); - if (0==strcmp("enabled", state)){ - return LinphoneTunnelEnabled; - } else if (0==strcmp("auto", state)){ - return LinphoneTunnelAuto; - } else { - return LinphoneTunnelDisabled; - } -} - static void tunnel_add_servers_from_config(LinphoneTunnel *tunnel, const char* confaddress){ char *addresses=(char*)ms_strdup(confaddress); char *str1; @@ -151,19 +175,79 @@ static void tunnel_add_servers_from_config(LinphoneTunnel *tunnel, const char* c ms_free(addresses); } +static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){ + ortp_logv(level,fmt,args); +} + /** - * Update tunnel using configuration. + * Startup tunnel using configuration. + * Called internally from linphonecore at startup. */ -void linphone_tunnel_update(LinphoneTunnel *tunnel){ - bool_t enabled; - const char* addresses=linphone_tunnel_get_server_addresses(tunnel); +void linphone_tunnel_configure(LinphoneTunnel *tunnel){ + bool_t enabled=(bool_t)lp_config_get_int(config(tunnel),"tunnel","enabled",FALSE); + const char* addresses=lp_config_get_string(config(tunnel),"tunnel","server_addresses", NULL); + linphone_tunnel_enable_logs_with_handler(tunnel,TRUE,my_ortp_logv); linphone_tunnel_clean_servers(tunnel); if (addresses){ tunnel_add_servers_from_config(tunnel,addresses); } - enabled=linphone_tunnel_get_state(tunnel)==LinphoneTunnelEnabled && addresses!=NULL; linphone_tunnel_enable(tunnel, enabled); } +#else + +/*stubs to avoid to have #ifdef TUNNEL_ENABLED in upper layers*/ + +void linphone_tunnel_destroy(LinphoneTunnel *tunnel){ +} + + +void linphone_tunnel_add_server(LinphoneTunnel *tunnel, const char *host, int port){ +} + +void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror, int delay){ +} + +char *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){ + return NULL; +} + +void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ +} + +void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ +} + +bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ + return FALSE; +} + +void linphone_tunnel_enable_logs(LinphoneTunnel *tunnel, bool_t enabled){ +} + +void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){ +} + +void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char* username,const char* passwd){ +} + +void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){ +} + +void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ +} + +void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ +} + +void linphone_tunnel_configure(LinphoneTunnel *tunnel){ +} + + +#endif + + + + diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index fe9675eac..362c49f1a 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -28,62 +28,33 @@ #include "linphonecore.h" +/* + * Linphone VoIP tunnel extension API +**/ + #ifdef __cplusplus extern "C" { #endif -typedef void (*LogHandler)(int log_level, const char *str, va_list l); void linphone_tunnel_add_server(LinphoneTunnel *tunnel, const char *host, int port); void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror, int delay); +/*returns a string of space separated list of host:port of tunnel server addresses*/ +char *linphone_tunnel_get_servers(LinphoneTunnel *tunnel); void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel); void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); -void linphone_tunnel_enable_logs(LinphoneTunnel *tunnel, bool_t enabled); -void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, LogHandler logHandler); void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); +void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd); void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd); -/** - * LinphoneTunnelState describes the tunnel activation states. - */ -typedef enum _LinphoneTunnelState{ - LinphoneTunnelDisabled, /**tunnel=linphone_core_tunnel_new(lc); - if (lc->tunnel) linphone_tunnel_update(lc->tunnel); + if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); #endif if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); diff --git a/coreapi/private.h b/coreapi/private.h index 77f62c334..2baa40a90 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -480,6 +480,8 @@ struct _LinphoneCore LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); void linphone_tunnel_destroy(LinphoneTunnel *tunnel); +void linphone_tunnel_configure(LinphoneTunnel *tunnel); +void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler); bool_t linphone_core_can_we_add_call(LinphoneCore *lc); int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index ff9d91cf0..f8187860d 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1003,7 +1003,7 @@ void linphone_gtk_edit_tunnel_closed(GtkWidget *button){ gtk_widget_destroy(pb); } -#ifdef TUNNEL_ENABLED + static void tunnel_get_server_host_and_port(LinphoneTunnel *tunnel, char *host, int size, int *port){ char *colon; char *addresses; @@ -1011,7 +1011,7 @@ static void tunnel_get_server_host_and_port(LinphoneTunnel *tunnel, char *host, char *address; const char* configured_addresses; - configured_addresses=linphone_tunnel_get_server_addresses(tunnel); + configured_addresses=linphone_tunnel_get_servers(tunnel); if (configured_addresses==NULL){ host[0]=0; @@ -1030,39 +1030,35 @@ static void tunnel_get_server_host_and_port(LinphoneTunnel *tunnel, char *host, ms_free(addresses); } -#endif void linphone_gtk_edit_tunnel(GtkButton *button){ GtkWidget *w=linphone_gtk_create_window("tunnel_config"); -#ifdef TUNNEL_ENABLED LinphoneCore *lc=linphone_gtk_get_core(); LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); char host[128]={'\0'}; int port=0; + + if (!tunnel) return; + tunnel_get_server_host_and_port(tunnel, host, sizeof(host), &port); - LinphoneTunnelState state=linphone_tunnel_get_state(tunnel); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"host")),host); if (port==0) port=443; gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port")), port); - if (state == LinphoneTunnelEnabled){ + if (linphone_tunnel_enabled(tunnel)){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_enable")),1); } else{ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_disable")),1); } g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_gtk_edit_tunnel_closed,w); -#endif gtk_widget_show(w); } void linphone_gtk_tunnel_ok(GtkButton *button){ GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); - // Save information to config file -#ifdef TUNNEL_ENABLED LinphoneCore *lc=linphone_gtk_get_core(); - char address[128]={'\0'}; LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); gint port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port"))); @@ -1070,16 +1066,10 @@ void linphone_gtk_tunnel_ok(GtkButton *button){ const char *host=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"host"))); if (tunnel==NULL) return; - - snprintf(address, sizeof address, "%s:%i", host, port); - linphone_tunnel_set_server_addresses(tunnel, address); - if (enabled){ - linphone_tunnel_set_state(tunnel, LinphoneTunnelEnabled); - } else{ - linphone_tunnel_set_state(tunnel,LinphoneTunnelDisabled); - } - linphone_tunnel_update(tunnel); -#endif + if (host && *host=='\0') host=NULL; + linphone_tunnel_clean_servers(tunnel); + linphone_tunnel_add_server(tunnel,host,port); + linphone_tunnel_enable(tunnel,enabled); gtk_widget_destroy(w); }