diff --git a/.cproject b/.cproject
index 52dd16394..0b797781c 100644
--- a/.cproject
+++ b/.cproject
@@ -238,6 +238,14 @@
true
true
+
+ make
+
+ all
+ true
+ true
+ true
+
diff --git a/.gitignore b/.gitignore
index a89057829..df1c80316 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,4 +41,15 @@ Specfile
.anjuta_sym_db.db
gtk-glade/version_date.h
share/linphone.desktop
+Debug/
+build/macos/Info-linphone.plist
+coreapi/help/Doxyfile
+coreapi/help/buddy_status
+coreapi/help/chatroom
+coreapi/help/doc/
+coreapi/help/helloworld
+coreapi/help/registration
+coreapi/test_ecc
+coreapi/test_lsd
+gtk/version_date.h
diff --git a/build/android/Android.mk b/build/android/Android.mk
index 096f94464..944f23611 100755
--- a/build/android/Android.mk
+++ b/build/android/Android.mk
@@ -66,7 +66,6 @@ LOCAL_CFLAGS += \
LOCAL_CFLAGS += -DIN_LINPHONE
-
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_CFLAGS += -DVIDEO_ENABLED
ifeq ($(BUILD_X264),1)
@@ -94,6 +93,18 @@ LOCAL_STATIC_LIBRARIES := \
libosip2 \
libgsm
+ifeq ($(BUILD_TUNNEL),1)
+LOCAL_CFLAGS +=-DTUNNEL_ENABLED
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../tunnel/include
+LOCAL_SRC_FILES += linphone_tunnel_manager.cc TunnelManager.cc
+ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
+LOCAL_SHARED_LIBRARIES += libtunnelclient
+else
+LOCAL_STATIC_LIBRARIES += libtunnelclient
+endif
+endif
+
+
ifneq ($(BUILD_AMR),0)
LOCAL_CFLAGS += -DHAVE_AMR
diff --git a/configure.ac b/configure.ac
index 568f46b73..6e5e0da42 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([linphone],[3.4.99.4],[linphone-developers@nongnu.org])
+AC_INIT([linphone],[3.4.99.5],[linphone-developers@nongnu.org])
AC_CANONICAL_SYSTEM
AC_CONFIG_SRCDIR([coreapi/linphonecore.c])
@@ -37,6 +37,7 @@ AC_CONFIG_MACRO_DIR([m4])
AC_SUBST([mkdir_p])
AC_ISC_POSIX
AC_PROG_CC
+AC_PROG_CXX
AC_C_INLINE
AM_PROG_CC_STDC
AC_HEADER_STDC
@@ -460,6 +461,32 @@ AC_SUBST(MEDIASTREAMER_LIBS)
AC_SUBST([MS2_VERSION])
AC_SUBST([MS2_DIR])
+
+
+AC_ARG_ENABLE(tunnel,
+ [ --enable-tunnel=[yes/no] Turn on compilation of tunnel support [default=no]],
+ [case "${enableval}" in
+ yes) enable_tunnel=true ;;
+ no) enable_tunnel=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --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)
+ TUNNEL_CFLAGS+="-DTUNNEL_ENABLED"
+ AC_SUBST(TUNNEL_CFLAGS)
+ AC_SUBST(TUNNEL_LIBS)
+fi
+
+
+
+
+
+
+
+
+
+
dnl check for db2html (docbook) to generate html user manual
AC_CHECK_PROG(have_sgmltools,sgmltools, yes, no)
AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes )
@@ -517,6 +544,8 @@ AC_ARG_ENABLE(tests_enabled,
esac],[tests_enabled=false])
AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes)
+
+
dnl ##################################################
dnl # Check for doxygen
dnl ##################################################
diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am
index 316b6f036..301c05976 100644
--- a/coreapi/Makefile.am
+++ b/coreapi/Makefile.am
@@ -10,7 +10,8 @@ linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h ..
INCLUDES = \
-I$(top_srcdir)\
- $(MEDIASTREAMER_CFLAGS)
+ $(MEDIASTREAMER_CFLAGS)\
+ $(TUNNEL_CFLAGS)
lib_LTLIBRARIES=liblinphone.la
@@ -37,7 +38,13 @@ liblinphone_la_SOURCES=\
siplogin.c \
lsd.c linphonecore_utils.h \
ec-calibrator.c \
- conference.c
+ conference.c \
+ linphone_tunnel_manager.h
+
+if BUILD_TUNNEL
+liblinphone_la_SOURCES+=TunnelManager.cc TunnelManager.hh linphone_tunnel_manager.c
+endif
+
liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined
@@ -45,7 +52,8 @@ liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined
liblinphone_la_LIBADD= \
$(EXOSIP_LIBS) \
$(MEDIASTREAMER_LIBS) \
- $(ORTP_LIBS) $(OPENSSL_LIBS)
+ $(ORTP_LIBS) $(OPENSSL_LIBS) \
+ $(TUNNEL_LIBS)
if BUILD_WIN32
liblinphone_la_LIBADD+=$(top_builddir)/oRTP/src/libortp.la
@@ -70,6 +78,8 @@ AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \
$(EXOSIP_CFLAGS) \
-DENABLE_TRACE \
-DLOG_DOMAIN=\"LinphoneCore\" \
- $(IPV6_CFLAGS) \
- -DORTP_INET6 \
- $(VIDEO_CFLAGS)
+ $(IPV6_CFLAGS) \
+ -DORTP_INET6 \
+ $(VIDEO_CFLAGS) \
+ $(TUNNEL_CFLAGS)
+
diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc
new file mode 100644
index 000000000..f1fa17bf7
--- /dev/null
+++ b/coreapi/TunnelManager.cc
@@ -0,0 +1,435 @@
+/*
+ * C Implementation: tunnel
+ *
+ * Description:
+ *
+ *
+ * Author: Simon Morlat , (C) 2009
+ *
+ * Copyright (C) 2010 Belledonne Comunications, Grenoble, France
+ *
+ */
+
+
+#include "TunnelManager.hh"
+
+#include "ortp/rtpsession.h"
+#include "linphonecore.h"
+#include "linphonecore_utils.h"
+#include "eXosip2/eXosip_transport_hook.h"
+#include "tunnel/udp_mirror.hh"
+
+#ifdef ANDROID
+#include
+#endif
+
+#ifdef recvfrom
+#undef recvfrom
+#endif
+#ifdef sendto
+#undef sendto
+#endif
+#ifdef select
+#undef select
+#endif
+
+using namespace belledonnecomm;
+
+Mutex TunnelManager::sMutex;
+
+int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){
+ TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
+ int err;
+ sMutex.lock();
+ if (lTunnelMgr->mSipSocket==NULL){
+ sMutex.unlock();
+ return len;//let ignore the error
+ }
+ err=lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
+ sMutex.unlock();
+ return err;
+}
+
+int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){
+ TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
+ int err;
+ sMutex.lock();
+ if (lTunnelMgr->mSipSocket==NULL){
+ sMutex.unlock();
+ return 0;//let ignore the error
+ }
+ err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen);
+ sMutex.unlock();
+ return err;
+}
+
+int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){
+ struct timeval begin,cur;
+ TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
+ if (tv!=0 && tv->tv_sec){
+ /*this is the select from udp.c, the one that is interesting to us*/
+ unsigned int i;
+ fd_set tmp;
+ int udp_fd=eXosip_get_udp_socket();
+ int controlfd=-1;
+
+ /*
+ Find the udp fd and the control fd
+ */
+ for(i=0;imSipSocket!=NULL){
+ if (lTunnelMgr->mSipSocket->hasData()) {
+ sMutex.unlock();
+ /* we make exosip believe that it has udp data to read*/
+ FD_SET(udp_fd,s1);
+ return 1;
+ }
+ }
+ sMutex.unlock();
+ gettimeofday(&cur,NULL);
+ if (cur.tv_sec-begin.tv_sec>tv->tv_sec) {
+ FD_SET(controlfd,s1);
+ FD_SET(udp_fd,s1);
+ return 0;
+ }
+ FD_ZERO(s1);
+ FD_SET(controlfd,s1);
+ if (select(max_fds,s1,s2,s3,&abit)==1) {
+ return 1;
+ }
+ }while(1);
+
+ }else{
+ /*select called from other places, only the control fd is present */
+ return select(max_fds,s1,s2,s3,tv);
+ }
+}
+
+
+void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
+ addServer(ip,port);
+ mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
+}
+
+void TunnelManager::addServer(const char *ip, int port) {
+ mServerAddrs.push_back(ServerAddr(ip,port));
+ if (mTunnelClient) mTunnelClient->addServer(ip,port);
+}
+
+void TunnelManager::cleanServers() {
+ mServerAddrs.clear();
+
+ UdpMirrorClientList::iterator it;
+ mAutoDetectStarted=false;
+ for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
+ UdpMirrorClient& s=*it++;
+ s.stop();
+ }
+ mUdpMirrorClients.clear();
+ if (mTunnelClient) mTunnelClient->cleanServers();
+}
+
+void TunnelManager::reconnect(){
+ if (mTunnelClient)
+ mTunnelClient->reconnect();
+}
+
+void TunnelManager::setCallback(StateCallback cb, void *userdata) {
+ mCallback=cb;
+ mCallbackData=userdata;
+}
+
+static void sCloseRtpTransport(void *userData, RtpTransport *t){
+ ((TunnelManager::TunnelManager *) userData)->closeRtpTransport(t);
+}
+void TunnelManager::closeRtpTransport(RtpTransport *t){
+ TunnelSocket *socket=(TunnelSocket *) t->data;
+ mTransports.remove(t);
+ mTunnelClient->closeSocket(socket);
+ ms_free(t);
+}
+
+static RtpTransport *sCreateRtpTransport(void* userData, int port){
+ return ((TunnelManager::TunnelManager *) userData)->createRtpTransport(port);
+}
+
+RtpTransport *TunnelManager::createRtpTransport(int port){
+ RtpTransport *t=ms_new0(RtpTransport,1);
+ t->data=mTunnelClient->createSocket(port);
+ t->t_getsocket=NULL;
+ t->t_recvfrom=customRecvfrom;
+ t->t_sendto=customSendto;
+ t->close_fn=sCloseRtpTransport;
+ t->close_data=this;
+ mTransports.push_back(t);
+ return t;
+}
+
+void TunnelManager::start() {
+ if (!mTunnelClient) {
+ mTunnelClient = new TunnelClient();
+ mTunnelClient->setCallback((StateCallback)tunnelCallback,this);
+ std::list::iterator it;
+ for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){
+ const ServerAddr &addr=*it;
+ mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort);
+ }
+ }
+ mTunnelClient->start();
+
+ if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
+}
+
+bool TunnelManager::isStarted() {
+ return mTunnelClient != 0 && mTunnelClient->isStarted();
+}
+
+bool TunnelManager::isReady() const {
+ return mTunnelClient && mTunnelClient->isReady();
+}
+
+int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
+ int size;
+ msgpullup(msg,-1);
+ size=msgdsize(msg);
+ ((TunnelSocket*)t->data)->sendto(msg->b_rptr,size,to,tolen);
+ return size;
+}
+
+int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
+ int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen);
+ if (err>0) return err;
+ return 0;
+}
+
+
+TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
+,mCore(lc)
+,mEnabled(false)
+,mSipSocket(NULL)
+,mCallback(NULL)
+,mTunnelClient(NULL)
+,mAutoDetectStarted(false) {
+
+ mExosipTransport.data=this;
+ mExosipTransport.recvfrom=eXosipRecvfrom;
+ mExosipTransport.sendto=eXosipSendto;
+ mExosipTransport.select=eXosipSelect;
+ mStateChanged=false;
+ linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
+ mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
+ mTransportFactories.audio_rtcp_func_data=this;
+ mTransportFactories.audio_rtp_func=sCreateRtpTransport;
+ mTransportFactories.audio_rtp_func_data=this;
+ mTransportFactories.video_rtcp_func=sCreateRtpTransport;
+ mTransportFactories.video_rtcp_func_data=this;
+ mTransportFactories.video_rtp_func=sCreateRtpTransport;
+ mTransportFactories.video_rtp_func_data=this;
+}
+
+TunnelManager::~TunnelManager(){
+ stopClient();
+}
+
+void TunnelManager::stopClient(){
+ eXosip_transport_hook_register(NULL);
+ if (mSipSocket != NULL){
+ sMutex.lock();
+ mTunnelClient->closeSocket(mSipSocket);
+ mSipSocket = NULL;
+ sMutex.unlock();
+ }
+ if (mTunnelClient){
+ delete mTunnelClient;
+ mTunnelClient=NULL;
+ }
+}
+
+void TunnelManager::processTunnelEvent(){
+ LinphoneProxyConfig* lProxy;
+ linphone_core_get_default_proxy(mCore, &lProxy);
+
+ if (mEnabled && mTunnelClient->isReady()){
+ ms_message("Tunnel is up, registering now");
+ linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
+ eXosip_transport_hook_register(&mExosipTransport);
+ //force transport to udp
+ LCSipTransports lTransport;
+
+ lTransport.udp_port=15060;
+ lTransport.tcp_port=0;
+ lTransport.tls_port=0;
+ lTransport.dtls_port=0;
+
+ linphone_core_set_sip_transports(mCore, &lTransport);
+ //register
+ if (lProxy) {
+ linphone_proxy_config_done(lProxy);
+ }
+ }else if (mEnabled && !mTunnelClient->isReady()){
+ /* we got disconnected from the tunnel */
+ if (lProxy && linphone_proxy_config_is_registered(lProxy)) {
+ /*forces de-registration so that we register again when the tunnel is up*/
+ linphone_proxy_config_edit(lProxy);
+ linphone_core_iterate(mCore);
+ }
+ }
+}
+
+void TunnelManager::enable(bool isEnable) {
+ ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
+ if (isEnable && !mEnabled){
+ mEnabled=true;
+ //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);
+ }
+ //3 insert tunnel
+ start();
+ }else if (!isEnable && mEnabled){
+ 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);
+
+ eXosip_transport_hook_register(NULL);
+ //Restore transport
+ linphone_core_set_sip_transports(mCore, &mRegularTransport);
+ //register
+ if (lProxy) {
+ linphone_proxy_config_done(lProxy);
+ }
+
+ }
+}
+
+void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
+ zis->mStateChanged=true;
+}
+
+/*invoked from linphone_core_iterate() */
+void TunnelManager::sOnIterate(TunnelManager *zis){
+ if (zis->mStateChanged){
+ zis->mStateChanged=false;
+ zis->processTunnelEvent();
+ }
+}
+
+#ifdef ANDROID
+static void linphone_android_log_handler(int lev, const char *fmt, va_list args){
+ int prio;
+ switch(lev){
+ case TUNNEL_DEBUG: prio = ANDROID_LOG_DEBUG; break;
+ case TUNNEL_INFO: prio = ANDROID_LOG_INFO; break;
+ case TUNNEL_NOTICE: prio = ANDROID_LOG_INFO; break;
+ case TUNNEL_WARN: prio = ANDROID_LOG_WARN; break;
+ case TUNNEL_ERROR: prio = ANDROID_LOG_ERROR; break;
+ default: prio = ANDROID_LOG_DEFAULT; break;
+ }
+ __android_log_vprint(prio, LOG_DOMAIN, fmt, args);
+}
+#endif /*ANDROID*/
+
+void TunnelManager::enableLogs(bool value) {
+ enableLogs(value,NULL);
+}
+
+void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
+ if (logHandler != NULL) SetLogHandler(logHandler);
+#ifdef ANDROID
+ else SetLogHandler(linphone_android_log_handler);
+#else
+ else SetLogHandler(default_log_handler);
+#endif
+
+ if (isEnabled) {
+ SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
+ } else {
+ SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
+ }
+}
+
+
+bool TunnelManager::isEnabled() {
+ return mEnabled;
+}
+void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
+ TunnelManager* thiz = (TunnelManager*)data;
+ if (isUdpAvailable) {
+ LOGI("Tunnel is not required, disabling");
+ thiz->enable(false);
+ thiz->mAutoDetectStarted = false;
+ } else {
+ if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
+ //1 enable tunnable but also try backup server
+ LOGI("Tunnel is required, enabling; Trying backup udp mirror");
+
+ UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
+ lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
+ } else {
+ LOGI("Tunnel is required, enabling; no backup udp mirror available");
+ thiz->mAutoDetectStarted = false;
+ }
+ thiz->enable(true);
+ }
+ return;
+}
+
+void TunnelManager::autoDetect() {
+ // first check if udp mirrors was provisionned
+ if (mUdpMirrorClients.empty()) {
+ LOGE("No UDP mirror server configured aborting auto detection");
+ return;
+ }
+ if (mAutoDetectStarted) {
+ LOGE("auto detection already in progress, restarting");
+ (*mCurrentUdpMirrorClient).stop();
+ }
+ mAutoDetectStarted=true;
+ mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
+ UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
+ lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
+
+}
+
+void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
+ mTunnelClient->setHttpProxyAuthInfo(username,passwd);
+}
+
+LinphoneCore *TunnelManager::getLinphoneCore(){
+ return mCore;
+}
diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh
new file mode 100644
index 000000000..20bb75d3d
--- /dev/null
+++ b/coreapi/TunnelManager.hh
@@ -0,0 +1,171 @@
+/*
+ * C Implementation: tunnel
+ *
+ * Description:
+ *
+ *
+ *
+ *Copyright (C) 2011 Belledonne Comunications, Grenoble, France
+ */
+
+#ifndef __TUNNEL_CLIENT_MANAGER_H__
+#define __TUNNEL_CLIENT_MANAGER_H__
+#include
+#include "linphonecore.h"
+#include "tunnel/client.hh"
+extern "C" {
+ #include "eXosip2/eXosip_transport_hook.h"
+}
+namespace belledonnecomm {
+class TunnelClient;
+class UdpMirrorClient;
+/**
+ * @addtogroup tunnel_client
+ * @{
+**/
+
+ /**
+ * The TunnelManager class extends the LinphoneCore functionnality in order to provide an easy to use API to
+ * - provision tunnel servers ip addresses and ports
+ * - start/stop the tunneling service
+ * - be informed of of connection and disconnection events to the tunnel server
+ * - perform auto-detection whether tunneling is required, based on a test of sending/receiving a flow of UDP packets.
+ *
+ * It takes in charge automatically the SIP registration procedure when connecting or disconnecting to a tunnel server.
+ * No other action on LinphoneCore is required to enable full operation in tunnel mode.
+ **/
+ class TunnelManager : public TunnelClientController{
+
+ public:
+ /**
+ * Add a tunnel server. At least one should be provided to be able to connect.
+ * When several addresses are provided, the tunnel client may try each of them until it gets connected.
+ *
+ * @param ip tunnMethod definition for '-isInitialStateOn' not foundel server ip address
+ * @param port tunnel server tls port, recommended value is 443
+ */
+ void addServer(const char *ip, int port);
+ /**
+ *Add tunnel server with auto detection capabilities
+ *
+ * @param ip tunnel server ip address
+ * @param port tunnel server tls port, recommended value is 443
+ * @param udpMirrorPort remote port on the tunnel server side used to test udp reachability
+ * @param delay udp packet round trip delay in ms considered as acceptable. recommanded value is 1000 ms.
+ */
+ void addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay);
+ /**
+ * Removes all tunnel server address previously entered with addServer()
+ **/
+ void cleanServers();
+ /**
+ * Register a state callback to be notified whenever the tunnel client is connected or disconnected to the tunnel server.
+ * @param cb application callback function to use for notifying of connection/disconnection events.
+ * @param userdata An opaque pointer passed to the callback, used optionally by the application to retrieve a context.
+ **/
+ void setCallback(StateCallback cb, void *userdata);
+ /**
+ * Start connecting to a tunnel server.
+ * At this step, nothing is tunneled yet. The enable() method must be used to state whether SIP and RTP traffic
+ * need to be tunneled or not.
+ **/
+ void start();
+ /**
+ * Forces reconnection to the tunnel server.
+ * This method is useful when the device switches from wifi to Edge/3G or vice versa. In most cases the tunnel client socket
+ * won't be notified promptly that its connection is now zombie, so it is recommended to call this method that will cause
+ * the lost connection to be closed and new connection to be issued.
+ **/
+ void reconnect();
+ /**
+ * Sets whether tunneling of SIP and RTP is required.
+ * @param isEnabled If true enter in tunneled mode, if false exits from tunneled mode.
+ * The TunnelManager takes care of refreshing SIP registration when switching on or off the tunneled mode.
+ *
+ **/
+ void enable(bool isEnabled);
+ /**
+ * In auto detect mode, the tunnel manager try to establish a real time rtp cummunication with the tunnel server on specified port.
+ *
In case of success, the tunnel is automatically turned off. Otherwise, if no udp commmunication is feasible, tunnel mode is turned on.
+ *
Call this method each time to run the auto detection algorithm
+ */
+ void autoDetect();
+ /**
+ * Returns a boolean indicating whether tunneled operation is enabled.
+ **/
+ bool isEnabled();
+ /**
+ * Enables debug logs of the Tunnel subsystem.
+ **/
+ void enableLogs(bool isEnabled);
+ /**
+ * Enables debugs logs of the Tunnel subsystem and specify a callback where to receive the debug messages.
+ **/
+ void enableLogs(bool isEnabled,LogHandler logHandler);
+ /**
+ * iOS only feature: specify http proxy credentials.
+ * When the iOS device has an http proxy configured in the iOS settings, the tunnel client will connect to the server
+ * through this http proxy. Credentials might be needed depending on the proxy configuration.
+ * @param username The username.
+ * @param passwd The password.
+ **/
+ void setHttpProxyAuthInfo(const char* username,const char* passwd);
+ ~TunnelManager();
+ TunnelManager(LinphoneCore* lc);
+ /**
+ * Destroy the given RtpTransport.
+ */
+ void closeRtpTransport(RtpTransport *t);
+
+ /**
+ * Create an RtpTransport.
+ */
+ RtpTransport *createRtpTransport(int port);
+
+ /**
+ * Get associated Linphone Core.
+ */
+ LinphoneCore *getLinphoneCore();
+ private:
+ typedef std::list UdpMirrorClientList;
+ typedef std::list RtpTransportList;
+ virtual bool isStarted();
+ virtual bool isReady() const;
+ static int customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen);
+ static int customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen);
+ static int eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata);
+ static int eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata);
+ static int eXosipSelect(int nfds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata);
+ static void tunnelCallback(bool connected, TunnelManager *zis);
+ static void sOnIterate(TunnelManager *zis);
+ static void UdpMirrorClientListener(bool result, void* data);
+
+ void processTunnelEvent();
+ LinphoneCore* mCore;
+ LCSipTransports mRegularTransport;
+ TunnelSocket *mSipSocket;
+ eXosip_transport_hooks_t mExosipTransport;
+ StateCallback mCallback;
+ void * mCallbackData;
+ bool mEnabled;
+ bool mStateChanged;
+ std::list mServerAddrs;
+ UdpMirrorClientList mUdpMirrorClients;
+ UdpMirrorClientList::iterator mCurrentUdpMirrorClient;
+ TunnelClient* mTunnelClient;
+ void stopClient();
+ static Mutex sMutex;
+ bool mAutoDetectStarted;
+ RtpTransportList mTransports;
+ LinphoneRtpTransportFactories mTransportFactories;
+ };
+
+/**
+ * @}
+**/
+
+}
+
+
+
+#endif /*__TUNNEL_CLIENT_MANAGER_H__*/
diff --git a/coreapi/linphone_tunnel_manager.cc b/coreapi/linphone_tunnel_manager.cc
new file mode 100644
index 000000000..0bf2efa3f
--- /dev/null
+++ b/coreapi/linphone_tunnel_manager.cc
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * linphone_tunnel_manager.cc
+ *
+ * Fri Dec 9, 2011
+ * Copyright 2011 Belledonne Communications
+ * Author: Guillaume Beraudo
+ * Email: guillaume dot beraudo at linphone dot org
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "linphone_tunnel_manager.h"
+#include "TunnelManager.hh"
+#include "linphonecore.h"
+#include "private.h"
+#include "lpconfig.h"
+
+static inline belledonnecomm::TunnelManager *bcTunnel(LinphoneTunnelManager *tunnel){
+ return (belledonnecomm::TunnelManager *)tunnel;
+}
+
+extern "C" LinphoneTunnelManager* linphone_core_tunnel_new(LinphoneCore *lc){
+ LinphoneTunnelManager* tunnel= (LinphoneTunnelManager*) new belledonnecomm::TunnelManager(lc);
+ return tunnel;
+}
+
+LinphoneTunnelManager* linphone_tunnel_get(LinphoneCore *lc){
+ return lc->tunnel;
+}
+
+void linphone_tunnel_destroy(LinphoneTunnelManager *tunnel){
+ delete bcTunnel(tunnel);
+}
+
+void linphone_tunnel_add_server(LinphoneTunnelManager *tunnel, const char *host, int port){
+ bcTunnel(tunnel)->addServer(host, port);
+}
+
+void linphone_tunnel_add_server_and_mirror(LinphoneTunnelManager *tunnel, const char *host, int port, int remote_udp_mirror, int delay){
+ bcTunnel(tunnel)->addServer(host, port, remote_udp_mirror, delay);
+}
+
+void linphone_tunnel_clean_servers(LinphoneTunnelManager *tunnel){
+ bcTunnel(tunnel)->cleanServers();
+}
+
+void linphone_tunnel_enable(LinphoneTunnelManager *tunnel, bool_t enabled){
+ bcTunnel(tunnel)->enable(enabled);
+}
+
+bool_t linphone_tunnel_enabled(LinphoneTunnelManager *tunnel){
+ return bcTunnel(tunnel)->isEnabled();
+}
+
+void linphone_tunnel_enable_logs(LinphoneTunnelManager *tunnel, bool_t enabled){
+ bcTunnel(tunnel)->enableLogs(enabled);
+}
+
+void linphone_tunnel_enable_logs_with_handler(LinphoneTunnelManager *tunnel, bool_t enabled, LogHandler logHandler){
+ bcTunnel(tunnel)->enableLogs(enabled, logHandler);
+}
+
+void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnelManager *tunnel, const char* username,const char* passwd){
+ bcTunnel(tunnel)->setHttpProxyAuthInfo(username, passwd);
+}
+
+void linphone_tunnel_reconnect(LinphoneTunnelManager *tunnel){
+ bcTunnel(tunnel)->reconnect();
+}
+
+void linphone_tunnel_auto_detect(LinphoneTunnelManager *tunnel){
+ bcTunnel(tunnel)->autoDetect();
+}
+
+
+static inline _LpConfig *config(LinphoneTunnelManager *tunnel){
+ return ((belledonnecomm::TunnelManager *)tunnel)->getLinphoneCore()->config;
+}
+
+/**
+ * Set tunnel server addresses. "host1:port1 host2:port2 host3:port3"
+**/
+void linphone_tunnel_set_server_addresses(LinphoneTunnelManager *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(LinphoneTunnelManager *tunnel){
+ return lp_config_get_string(config(tunnel),"tunnel","server_addresses", NULL);
+}
+
+/**
+ * Set tunnel state.
+**/
+void linphone_tunnel_set_state(LinphoneTunnelManager *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(LinphoneTunnelManager *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;
+ }
+}
diff --git a/coreapi/linphone_tunnel_manager.h b/coreapi/linphone_tunnel_manager.h
new file mode 100644
index 000000000..2569534e7
--- /dev/null
+++ b/coreapi/linphone_tunnel_manager.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * linphone_tunnel_manager.h
+ *
+ * Fri Dec 9, 2011
+ * Copyright 2011 Belledonne Communications
+ * Author: Guillaume Beraudo
+ * Email: guillaume dot beraudo at linphone dot org
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef LINPHONETUNNELMANAGER_H
+#define LINPHONETUNNELMANAGER_H
+
+#include "linphonecore.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct LinphoneTunnelManager LinphoneTunnelManager;
+typedef void (*LogHandler)(int log_level, const char *str, va_list l);
+
+
+LinphoneTunnelManager *linphone_tunnel_get(LinphoneCore *lc);
+void linphone_tunnel_destroy(LinphoneTunnelManager *tunnel);
+void linphone_tunnel_add_server(LinphoneTunnelManager *tunnel, const char *host, int port);
+void linphone_tunnel_add_server_and_mirror(LinphoneTunnelManager *tunnel, const char *host, int port, int remote_udp_mirror, int delay);
+void linphone_tunnel_clean_servers(LinphoneTunnelManager *tunnel);
+void linphone_tunnel_enable(LinphoneTunnelManager *tunnel, bool_t enabled);
+bool_t linphone_tunnel_enabled(LinphoneTunnelManager *tunnel);
+void linphone_tunnel_enable_logs(LinphoneTunnelManager *tunnel, bool_t enabled);
+void linphone_tunnel_enable_logs_with_handler(LinphoneTunnelManager *tunnel, bool_t enabled, LogHandler logHandler);
+void linphone_tunnel_reconnect(LinphoneTunnelManager *tunnel);
+void linphone_tunnel_auto_detect(LinphoneTunnelManager *tunnel);
+void linphone_tunnel_set_http_proxy_auth_info(const char* username,const char* passwd);
+
+
+/**
+ * LinphoneTunnelState describes the tunnel activation states.
+ */
+typedef enum _LinphoneTunnelState{
+ LinphoneTunnelDisabled, /**a_rtp)
- rtp_session_set_transports(audiostream->session,lc->a_rtp,lc->a_rtcp);
+ if (lc->rtptf){
+ RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
+ RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
+ rtp_session_set_transports(audiostream->session,artp,artcp);
+ }
call->audiostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(audiostream->session,call->audiostream_app_evq);
@@ -858,8 +861,11 @@ void linphone_call_init_media_streams(LinphoneCall *call){
if( lc->video_conf.displaytype != NULL)
video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
- if (lc->v_rtp)
- rtp_session_set_transports(call->videostream->session,lc->v_rtp,lc->v_rtcp);
+ if (lc->rtptf){
+ RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
+ RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
+ rtp_session_set_transports(call->videostream->session,vrtp,vrtcp);
+ }
call->videostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq);
#ifdef TEST_EXT_RENDERER
@@ -1039,7 +1045,15 @@ static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
return !linphone_core_is_in_conference(lc) &&
(current==NULL || current==call);
}
-
+static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
+ int i;
+ for(i=0; icore;
int jitt_comp=lc->rtp_conf.audio_jitt_comp;
@@ -1130,11 +1144,10 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
if (stream->proto == SalProtoRtpSavp) {
const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
SalProtoRtpSavp,SalAudio);
-
audio_stream_enable_strp(
call->audiostream,
stream->crypto[0].algo,
- local_st_desc->crypto[0].master_key,
+ local_st_desc->crypto[find_crypto_index_from_tag(local_st_desc->crypto,stream->crypto[0].tag)].master_key,
stream->crypto[0].master_key);
call->audiostream_encrypted=TRUE;
}else call->audiostream_encrypted=FALSE;
@@ -1306,7 +1319,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){
const char *state_str=NULL;
ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
if (state_str){
- ms_message("Writing echo canceller state, %i bytes",(int)strlen(state_str));
+ ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
lp_config_set_string(call->core->config,"sound","ec_state",state_str);
}
}
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index 55e01193e..ecbd18f28 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -810,6 +810,14 @@ static void autoreplier_config_init(LinphoneCore *lc)
}
*/
+bool_t linphone_core_tunnel_available(){
+#ifdef TUNNEL_ENABLED
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
/**
* Enable adaptive rate control (experimental feature, audio-only).
*
@@ -989,6 +997,36 @@ static void misc_config_read (LinphoneCore *lc) {
lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS);
}
+#ifdef TUNNEL_ENABLED
+static void tunnel_add_servers_from_config(LinphoneTunnelManager *tunnel, const char* confaddress){
+ char *addresses=(char*)ms_strdup(confaddress);
+ char *str1;
+ for(str1=addresses;;str1=NULL){
+ char *port;
+ char *address=strtok(str1," "); // Not thread safe
+ if (!address) break;
+ port=strchr(address, ':');
+ if (!port) ms_fatal("Bad tunnel address %s", address);
+ *port++='\0';
+ linphone_tunnel_add_server(tunnel, address, atoi(port));
+ }
+ ms_free(addresses);
+}
+#endif
+
+void linphone_core_update_tunnel(LinphoneCore *lc){
+#ifdef TUNNEL_ENABLED
+ bool_t enabled;
+ const char* addresses=linphone_tunnel_get_server_addresses(lc->tunnel);
+ if (addresses){
+ linphone_tunnel_clean_servers(lc->tunnel);
+ tunnel_add_servers_from_config(lc->tunnel,addresses);
+ }
+ enabled=linphone_tunnel_get_state(lc->tunnel)==LinphoneTunnelEnabled && addresses!=NULL;
+ linphone_tunnel_enable(lc->tunnel, enabled);
+#endif
+}
+
static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path,
const char *factory_config_path, void * userdata)
{
@@ -1084,6 +1122,10 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
lc->presence_mode=LinphoneStatusOnline;
misc_config_read(lc);
ui_config_read(lc);
+#ifdef TUNNEL_ENABLED
+ lc->tunnel=linphone_core_tunnel_new(lc);
+ linphone_core_update_tunnel(lc);
+#endif
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Ready"));
lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
@@ -3874,14 +3916,8 @@ void linphone_core_stop_waiting(LinphoneCore *lc){
}
}
-void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, RtpTransport *rtcp){
- lc->a_rtp=rtp;
- lc->a_rtcp=rtcp;
-}
-
-void linphone_core_set_video_transports(LinphoneCore *lc, RtpTransport *rtp, RtpTransport *rtcp){
- lc->v_rtp=rtp;
- lc->v_rtcp=rtcp;
+void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTransportFactories *factories){
+ lc->rtptf=factories;
}
/**
@@ -4112,6 +4148,9 @@ static void linphone_core_uninit(LinphoneCore *lc)
linphone_core_free_payload_types(lc);
ortp_exit();
linphone_core_set_state(lc,LinphoneGlobalOff,"Off");
+#ifdef TUNNEL_ENABLED
+ if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel);
+#endif
}
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){
diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h
index 68d658694..e32c4d0fa 100644
--- a/coreapi/linphonecore.h
+++ b/coreapi/linphonecore.h
@@ -344,6 +344,16 @@ typedef enum _LinphoneRegistrationState{
*/
const char *linphone_registration_state_to_string(LinphoneRegistrationState cs);
+/**
+ * True if tunnel support was compiled.
+ */
+bool_t linphone_core_tunnel_available();
+
+/**
+ * Update tunnel using configuration.
+ */
+void linphone_core_update_tunnel(LinphoneCore *lc);
+
LinphoneProxyConfig *linphone_proxy_config_new(void);
int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr);
int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity);
@@ -1006,9 +1016,20 @@ const MSList * linphone_core_get_sip_setups(LinphoneCore *lc);
void linphone_core_destroy(LinphoneCore *lc);
/*for advanced users:*/
-void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, RtpTransport *rtcp);
-void linphone_core_set_video_transports(LinphoneCore *lc, RtpTransport *rtp, RtpTransport *rtcp);
+typedef RtpTransport * (*LinphoneRtpTransportFactoryFunc)(void *data, int port);
+struct _LinphoneRtpTransportFactories{
+ LinphoneRtpTransportFactoryFunc audio_rtp_func;
+ void *audio_rtp_func_data;
+ LinphoneRtpTransportFactoryFunc audio_rtcp_func;
+ void *audio_rtcp_func_data;
+ LinphoneRtpTransportFactoryFunc video_rtp_func;
+ void *video_rtp_func_data;
+ LinphoneRtpTransportFactoryFunc video_rtcp_func;
+ void *video_rtcp_func_data;
+};
+typedef struct _LinphoneRtpTransportFactories LinphoneRtpTransportFactories;
+void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTransportFactories *factories);
int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote);
diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc
index 4552a0523..eca9152f4 100644
--- a/coreapi/linphonecore_jni.cc
+++ b/coreapi/linphonecore_jni.cc
@@ -20,6 +20,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphonecore_utils.h"
#include
+#ifdef TUNNEL_ENABLED
+#include "linphone_tunnel_manager.h"
+#endif
+
extern "C" {
#include "mediastreamer2/mediastream.h"
}
@@ -1591,3 +1595,45 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMaxCalls(JNIEnv *env,
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMaxCalls(JNIEnv *env,jobject thiz,jlong pCore, jint max) {
linphone_core_set_max_calls((LinphoneCore *) pCore, (int) max);
}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelAddServerAndMirror(JNIEnv *env,jobject thiz,jlong pCore,
+ jstring jHost, jint port, jint mirror, jint delay) {
+#ifdef TUNNEL_ENABLED
+ LinphoneTunnelManager *tunnel=((LinphoneCore *) pCore)->tunnel; if (!tunnel) return;
+ const char* cHost=env->GetStringUTFChars(jHost, NULL);
+ linphone_tunnel_add_server_and_mirror(tunnel, cHost, port, mirror, delay);
+ env->ReleaseStringUTFChars(jHost, cHost);
+#endif
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelAutoDetect(JNIEnv *env,jobject thiz,jlong pCore) {
+#ifdef TUNNEL_ENABLED
+ LinphoneTunnelManager *tunnel=((LinphoneCore *) pCore)->tunnel; if (!tunnel) return;
+ linphone_tunnel_auto_detect(tunnel);
+#endif
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelCleanServers(JNIEnv *env,jobject thiz,jlong pCore) {
+#ifdef TUNNEL_ENABLED
+ LinphoneTunnelManager *tunnel=((LinphoneCore *) pCore)->tunnel; if (!tunnel) return;
+ linphone_tunnel_clean_servers(tunnel);
+#endif
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelEnable(JNIEnv *env,jobject thiz,jlong pCore, jboolean enable) {
+#ifdef TUNNEL_ENABLED
+ LinphoneTunnelManager *tunnel=((LinphoneCore *) pCore)->tunnel; if (!tunnel) return;
+ linphone_tunnel_enable(tunnel, enable);
+#endif
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelEnableLogs(JNIEnv *env,jobject thiz,jlong pCore, jboolean enable) {
+#ifdef TUNNEL_ENABLED
+ LinphoneTunnelManager *tunnel=((LinphoneCore *) pCore)->tunnel; if (!tunnel) return;
+ linphone_tunnel_enable_logs(tunnel, enable);
+#endif
+}
+
+extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isTunnelAvailable(JNIEnv *env,jobject thiz){
+ return linphone_core_tunnel_available();
+}
diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c
index ae0fda94a..4010e20b7 100644
--- a/coreapi/offeranswer.c
+++ b/coreapi/offeranswer.c
@@ -142,8 +142,8 @@ static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCry
strncpy(result->master_key, local[j].master_key, 41);
result->tag = local[j].tag;
} else {
- strncpy(result->master_key, remote[j].master_key, 41);
- result->tag = remote[j].tag;
+ strncpy(result->master_key, remote[i].master_key, 41);
+ result->tag = remote[i].tag;
}
result->master_key[40] = '\0';
return TRUE;
diff --git a/coreapi/private.h b/coreapi/private.h
index 3561a4126..bda52f016 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -24,8 +24,11 @@
#ifndef _PRIVATE_H
#define _PRIVATE_H
-
+#ifdef __cplusplus
+extern "C" {
+#endif
#include "linphonecore.h"
+#include "linphone_tunnel_manager.h"
#include "linphonecore_utils.h"
#include "sal.h"
@@ -442,8 +445,7 @@ struct _LinphoneCore
int missed_calls;
VideoPreview *previewstream;
struct _MSEventQueue *msevq;
- RtpTransport *a_rtp,*a_rtcp;
- RtpTransport *v_rtp,*v_rtcp;
+ LinphoneRtpTransportFactories *rtptf;
MSList *bl_reqs;
MSList *subscribers; /* unknown subscribers */
int minutes_away;
@@ -474,8 +476,11 @@ struct _LinphoneCore
int device_rotation;
bool_t ringstream_autorelease;
int max_calls;
+ LinphoneTunnelManager *tunnel;
};
+LinphoneTunnelManager *linphone_core_tunnel_new(LinphoneCore *lc);
+
bool_t linphone_core_can_we_add_call(LinphoneCore *lc);
int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call);
int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call);
@@ -538,4 +543,9 @@ void __linphone_core_invalidate_registers(LinphoneCore* lc);
#define NB_MAX_CALLS (10)
#endif
void call_logs_write_to_config_file(LinphoneCore *lc);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _PRIVATE_H */
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 2d62217ac..42d5ff838 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -8,6 +8,7 @@ UI_FILES= about.ui \
call_logs.ui \
log.ui \
buddylookup.ui \
+ tunnel_config.ui \
waiting.ui
PIXMAPS= \
@@ -74,7 +75,8 @@ endif
AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ \
$(MEDIASTREAMER_CFLAGS) \
$(ORTP_CFLAGS) \
- $(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS)
+ $(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS) \
+ $(TUNNEL_CFLAGS)
version_date.h: $(top_srcdir)/configure.ac
diff --git a/gtk/parameters.ui b/gtk/parameters.ui
index 400622632..2403b3316 100644
--- a/gtk/parameters.ui
+++ b/gtk/parameters.ui
@@ -1,30 +1,31 @@
-
+
+
@@ -41,15 +42,15 @@
10
@@ -152,14 +153,12 @@