#include <android/log.h>
#endif
-#ifdef recvfrom
-#undef recvfrom
-#endif
-#ifdef sendto
-#undef sendto
-#endif
-#ifdef select
-#undef select
-#endif
using namespace belledonnecomm;
+using namespace ::std;
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
+ return len;
}
- err=lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
+ lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
sMutex.unlock();
- return err;
+ //ignore the error in all cases, retransmissions might be successful.
+ return len;
}
int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){
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){
+ if (s1 && tv!=0 && tv->tv_sec){
/*this is the select from udp.c, the one that is interesting to us*/
- unsigned int i;
- 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);
+ NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket();
+ NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd();
+
+ FD_ZERO(s1);
gettimeofday(&begin,NULL);
do{
struct timeval abit;
void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
+ if (ip == NULL) {
+ ip = "";
+ ms_warning("Adding tunnel server with empty ip, it will not work!");
+ }
addServer(ip,port);
mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
}
void TunnelManager::addServer(const char *ip, int port) {
+ if (ip == NULL) {
+ ip = "";
+ ms_warning("Adding tunnel server with empty ip, it will not work!");
+ }
mServerAddrs.push_back(ServerAddr(ip,port));
if (mTunnelClient) mTunnelClient->addServer(ip,port);
}
mCallbackData=userdata;
}
-static void sCloseRtpTransport(void *userData, RtpTransport *t){
- ((TunnelManager::TunnelManager *) userData)->closeRtpTransport(t);
+static void sCloseRtpTransport(RtpTransport *t, void *userData){
+ TunnelSocket *s=(TunnelSocket*)userData;
+ TunnelManager *manager=(TunnelManager*)s->getUserPointer();
+ manager->closeRtpTransport(t, s);
}
-void TunnelManager::closeRtpTransport(RtpTransport *t){
- TunnelSocket *socket=(TunnelSocket *) t->data;
- mTransports.remove(t);
- mTunnelClient->closeSocket(socket);
+void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){
+ mTunnelClient->closeSocket(s);
ms_free(t);
}
static RtpTransport *sCreateRtpTransport(void* userData, int port){
- return ((TunnelManager::TunnelManager *) userData)->createRtpTransport(port);
+ return ((TunnelManager *) userData)->createRtpTransport(port);
}
RtpTransport *TunnelManager::createRtpTransport(int port){
+ TunnelSocket *socket=mTunnelClient->createSocket(port);
+ socket->setUserPointer(this);
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);
+ t->t_close=sCloseRtpTransport;
+ t->data=socket;
return t;
}
if (!mTunnelClient) {
mTunnelClient = new TunnelClient();
mTunnelClient->setCallback((StateCallback)tunnelCallback,this);
- std::list<ServerAddr>::iterator it;
+ 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->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str());
}
mTunnelClient->start();
,mCallback(NULL)
,mEnabled(false)
,mTunnelClient(NULL)
-,mAutoDetectStarted(false) {
+,mAutoDetectStarted(false)
+,mHttpProxyPort(0){
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;
}
}
-void TunnelManager::processTunnelEvent(){
+void TunnelManager::processTunnelEvent(const Event &ev){
LinphoneProxyConfig* lProxy;
linphone_core_get_default_proxy(mCore, &lProxy);
if (mEnabled && mTunnelClient->isReady()){
- ms_message("Tunnel is up, registering now");
+ ms_message("Tunnel is up, registering now");
+ linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall);
linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
eXosip_transport_hook_register(&mExosipTransport);
//force transport to udp
LCSipTransports lTransport;
- lTransport.udp_port=15060;
+ lTransport.udp_port=(0xDFFF&random())+1024;
lTransport.tcp_port=0;
lTransport.tls_port=0;
lTransport.dtls_port=0;
- linphone_core_set_sip_transports(mCore, &lTransport);
+ linphone_core_set_sip_transports(mCore, &lTransport);
//register
if (lProxy) {
linphone_proxy_config_done(lProxy);
}
}
+void TunnelManager::waitUnRegistration(){
+ LinphoneProxyConfig* lProxy;
+ linphone_core_get_default_proxy(mCore, &lProxy);
+ if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) {
+ int i=0;
+ linphone_proxy_config_edit(lProxy);
+ //make sure unregister is sent and authenticated
+ do{
+ linphone_core_iterate(mCore);
+ ms_usleep(20000);
+ if (i>100){
+ ms_message("tunnel: timeout for unregistration expired, giving up");
+ break;
+ }
+ i++;
+ }while(linphone_proxy_config_get_state(lProxy)!=LinphoneRegistrationCleared);
+ }
+}
+
void TunnelManager::enable(bool isEnable) {
ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
if (isEnable && !mEnabled){
mEnabled=true;
- //1 save transport
+ //1 save transport and firewall policy
linphone_core_get_sip_transports(mCore, &mRegularTransport);
+ mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore);
//2 unregister
- LinphoneProxyConfig* lProxy;
- linphone_core_get_default_proxy(mCore, &lProxy);
- if (lProxy) {
- linphone_proxy_config_edit(lProxy);
- //make sure unregister is sent
- linphone_core_iterate(mCore);
- }
+ waitUnRegistration();
//3 insert tunnel
start();
}else if (!isEnable && mEnabled){
- 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);
- }
+ waitUnRegistration();
- //make sure unregister is sent
- linphone_core_iterate(mCore);
+ mEnabled=false;
+ stopClient();
linphone_core_set_rtp_transport_factories(mCore,NULL);
eXosip_transport_hook_register(NULL);
- //Restore transport
+ //Restore transport and firewall policy
linphone_core_set_sip_transports(mCore, &mRegularTransport);
+ linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy);
//register
+ LinphoneProxyConfig* lProxy;
+ linphone_core_get_default_proxy(mCore, &lProxy);
if (lProxy) {
linphone_proxy_config_done(lProxy);
}
}
void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
- zis->mStateChanged=true;
+ Event ev;
+ ev.mType=TunnelEvent;
+ ev.mData.mConnected=connected;
+ zis->postEvent(ev);
+}
+
+void TunnelManager::onIterate(){
+ mMutex.lock();
+ while(!mEvq.empty()){
+ Event ev=mEvq.front();
+ mEvq.pop();
+ mMutex.unlock();
+ if (ev.mType==TunnelEvent)
+ processTunnelEvent(ev);
+ else if (ev.mType==UdpMirrorClientEvent){
+ processUdpMirrorEvent(ev);
+ }
+ mMutex.lock();
+ }
+ mMutex.unlock();
}
/*invoked from linphone_core_iterate() */
void TunnelManager::sOnIterate(TunnelManager *zis){
- if (zis->mStateChanged){
- zis->mStateChanged=false;
- zis->processTunnelEvent();
- }
+ zis->onIterate();
}
#ifdef ANDROID
-static void linphone_android_log_handler(int lev, const char *fmt, va_list args){
+extern void linphone_android_log_handler(int prio, const char *fmt, va_list args);
+static void linphone_android_tunnel_log_handler(int lev, const char *fmt, va_list args) {
int prio;
switch(lev){
case TUNNEL_DEBUG: prio = ANDROID_LOG_DEBUG; 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;
+ default: prio = ANDROID_LOG_DEFAULT; break;
}
- __android_log_vprint(prio, LOG_DOMAIN, fmt, args);
+ linphone_android_log_handler(prio, fmt, args);
}
#endif /*ANDROID*/
void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
if (logHandler != NULL) SetLogHandler(logHandler);
#ifdef ANDROID
- else SetLogHandler(linphone_android_log_handler);
+ else SetLogHandler(linphone_android_tunnel_log_handler);
#else
else SetLogHandler(default_log_handler);
#endif
bool TunnelManager::isEnabled() {
return mEnabled;
}
-void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
- TunnelManager* thiz = (TunnelManager*)data;
- if (isUdpAvailable) {
+
+void TunnelManager::processUdpMirrorEvent(const Event &ev){
+ if (ev.mData.mHaveUdp) {
LOGI("Tunnel is not required, disabling");
- thiz->enable(false);
- thiz->mAutoDetectStarted = false;
+ enable(false);
+ mAutoDetectStarted = false;
} else {
- if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
- //1 enable tunnable but also try backup server
+ mCurrentUdpMirrorClient++;
+ if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) {
+ // enable tunnel but also try backup server
LOGI("Tunnel is required, enabling; Trying backup udp mirror");
- UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
- lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
+ UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
+ lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
} else {
LOGI("Tunnel is required, enabling; no backup udp mirror available");
- thiz->mAutoDetectStarted = false;
+ mAutoDetectStarted = false;
}
- thiz->enable(true);
+ enable(true);
}
- return;
+}
+
+void TunnelManager::postEvent(const Event &ev){
+ mMutex.lock();
+ mEvq.push(ev);
+ mMutex.unlock();
+}
+
+void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
+ TunnelManager* thiz = (TunnelManager*)data;
+ Event ev;
+ ev.mType=UdpMirrorClientEvent;
+ ev.mData.mHaveUdp=isUdpAvailable;
+ thiz->postEvent(ev);
}
void TunnelManager::autoDetect() {
mAutoDetectStarted=true;
mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
- lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
+ lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
}
void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
- mTunnelClient->setHttpProxyAuthInfo(username,passwd);
+ mHttpUserName=username?username:"";
+ mHttpPasswd=passwd?passwd:"";
+ if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd);
+}
+
+void TunnelManager::setHttpProxy(const char *host,int port, const char *username, const char *passwd){
+ mHttpUserName=username?username:"";
+ mHttpPasswd=passwd?passwd:"";
+ mHttpProxyPort=(port>0) ? port : 0;
+ mHttpProxyHost=host ? host : "";
+ if (mTunnelClient) mTunnelClient->setHttpProxy(host, port, username, passwd);
}
LinphoneCore *TunnelManager::getLinphoneCore(){