Tunnel manager.

This commit is contained in:
Guillaume Beraudo 2011-12-15 16:31:55 +01:00
parent 27a5dd7e77
commit 886d80bb6d
19 changed files with 1399 additions and 369 deletions

11
.gitignore vendored
View file

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

View file

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

View file

@ -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 ##################################################

View file

@ -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)

435
coreapi/TunnelManager.cc Normal file
View file

@ -0,0 +1,435 @@
/*
* C Implementation: tunnel
*
* Description:
*
*
* Author: Simon Morlat <simon.morlat@linphone.org>, (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 <android/log.h>
#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;i<max_fds;++i){
if (FD_ISSET(i,s1) && i!=udp_fd){
controlfd=i;
break;
}
}
if (controlfd==-1){
ms_error("Could not find control fd !");
return -1;
}
FD_ZERO(s1);
gettimeofday(&begin,NULL);
do{
struct timeval abit;
abit.tv_sec=0;
abit.tv_usec=20000;
sMutex.lock();
if (lTunnelMgr->mSipSocket!=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<ServerAddr>::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;
}

171
coreapi/TunnelManager.hh Normal file
View file

@ -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 <list>
#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.
*<br>In case of success, the tunnel is automatically turned off. Otherwise, if no udp commmunication is feasible, tunnel mode is turned on.
*<br> 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<UdpMirrorClient> UdpMirrorClientList;
typedef std::list<RtpTransport*> 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 <ServerAddr> mServerAddrs;
UdpMirrorClientList mUdpMirrorClients;
UdpMirrorClientList::iterator mCurrentUdpMirrorClient;
TunnelClient* mTunnelClient;
void stopClient();
static Mutex sMutex;
bool mAutoDetectStarted;
RtpTransportList mTransports;
LinphoneRtpTransportFactories mTransportFactories;
};
/**
* @}
**/
}
#endif /*__TUNNEL_CLIENT_MANAGER_H__*/

View file

@ -0,0 +1,126 @@
/***************************************************************************
* 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_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;
}
}

View file

@ -0,0 +1,85 @@
/***************************************************************************
* 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;
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_auto_detect(LinphoneTunnelManager *tunnel);
/**
* LinphoneTunnelState describes the tunnel activation states.
*/
typedef enum _LinphoneTunnelState{
LinphoneTunnelDisabled, /**<The tunnel is always on */
LinphoneTunnelEnabled, /**<The tunnel is always off */
LinphoneTunnelAuto /**<The tunnel is active if needed */
}LinphoneTunnelState;
/**
* Set tunnel addresses.
**/
void linphone_tunnel_set_server_addresses(LinphoneTunnelManager *tunnel, const char *lists);
/**
* Get tunnel addresses.
**/
const char *linphone_tunnel_get_server_addresses(LinphoneTunnelManager *tunnel);
/**
* Set tunnel state.
**/
void linphone_tunnel_set_state(LinphoneTunnelManager *tunnel, LinphoneTunnelState state);
/**
* Get tunnel state.
**/
LinphoneTunnelState linphone_tunnel_get_state(LinphoneTunnelManager *tunnel);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -845,8 +845,11 @@ void linphone_call_init_media_streams(LinphoneCall *call){
audio_stream_enable_noise_gate(audiostream,enabled);
}
if (lc->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,7 @@ 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(SalSrtpCryptoAlgo crypto[],unsigned char tag) {
static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
int i;
for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
if (crypto[i].tag == tag) {
@ -1313,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);
}
}

View file

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

View file

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

View file

@ -20,6 +20,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphonecore_utils.h"
#include <ortp/zrtp.h>
#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();
}

View file

@ -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 */

View file

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

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphone.h"
#include "linphone_tunnel_manager.h"
typedef enum {
CAP_IGNORE,
@ -986,5 +987,88 @@ void linphone_gtk_show_parameters(void){
g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_port")),"value-changed",(GCallback)linphone_gtk_update_my_port,NULL);
g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_combo")),"changed",(GCallback)linphone_gtk_proto_changed,NULL);
if (linphone_core_tunnel_available(lc)){
gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_edit_button")), TRUE);
gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_label")), TRUE);
}
gtk_widget_show(pb);
}
void linphone_gtk_edit_tunnel_closed(GtkWidget *button){
GtkWidget *pb=gtk_widget_get_toplevel(button);
gtk_widget_destroy(pb);
}
#ifdef TUNNEL_ENABLED
static void tunnel_get_server_host_and_port(LinphoneTunnelManager *tunnel, char *host, int size, int *port){
char *colon;
char *addresses=(char*)ms_strdup(linphone_tunnel_get_server_addresses(tunnel));
char *str1=addresses;
char *address=strtok(str1," "); // Not thread safe
if (!address) return;
colon=strchr(address, ':');
if (!colon) return;
*colon++='\0';
*port=atoi(colon);
memcpy(host,address,size);
ms_free(addresses);
}
#endif
void linphone_gtk_edit_tunnel(GtkButton *button){
#ifdef TUNNEL_ENABLED
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *w=linphone_gtk_create_window("tunnel_config");
LinphoneTunnelManager *tunnel=linphone_tunnel_get(lc);
char host[50]={'\0'};
int port=0;
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);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port")), port);
if (state == LinphoneTunnelEnabled){
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);
gtk_widget_show(w);
#endif
}
void linphone_gtk_tunnel_ok(GtkButton *button){
#ifdef TUNNEL_ENABLED
// Save information to config file
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button));
char address[50]={'\0'};
LinphoneTunnelManager *tunnel=linphone_tunnel_get(lc);
gint port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port")));
gboolean enabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_enable")));
const char *host=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"host")));
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_core_update_tunnel(lc);
gtk_widget_destroy(w);
#endif
}
void linphone_gtk_tunnel_cancel(GtkButton *button){
}

202
gtk/tunnel_config.ui Normal file
View file

@ -0,0 +1,202 @@
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkAdjustment" id="adjustment1">
<property name="value">3600</property>
<property name="upper">100000</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkDialog" id="tunnel_config">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Linphone - Configure a SIP account</property>
<property name="window_position">center-on-parent</property>
<property name="icon">linphone2.png</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">2</property>
<child>
<object class="GtkFrame" id="frame15">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment15">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox11">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkTable" id="table6">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<child>
<object class="GtkLabel" id="label38">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Host</property>
<property name="justify">right</property>
</object>
</child>
<child>
<object class="GtkEntry" id="host">
<property name="width_request">275</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label39">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Port</property>
<property name="justify">right</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="radio_enable">
<property name="label" translatable="yes">Enable</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="radio_disable">
<property name="label" translatable="yes">Disable</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">radio_enable</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">adjustment1</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label42">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Configure tunnel</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button6">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_tunnel_ok"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button7">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_proxy_cancel"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">button6</action-widget>
<action-widget response="0">button7</action-widget>
</action-widgets>
</object>
</interface>

View file

@ -707,5 +707,17 @@ public interface LinphoneCore {
* @param path path to music file played to remote side when on hold.
*/
void setPlayFile(String path);
void tunnelEnable(boolean enable);
void tunnelAutoDetect();
void tunnelEnableLogs(boolean enable);
void tunnelCleanServers();
/**
* @param host 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 roundTripDelay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms
*/
void tunnelAddServerAndMirror(String host, int port, int udpMirrorPort, int roundTripDelay);
boolean isTunnelAvailable();
}

2
oRTP

@ -1 +1 @@
Subproject commit 758150c3cd0f5a3a7a087247d6ff2dd198435fe7
Subproject commit 729f35e54053154d92fe3eaf7bdb86bc10aec262