X-Git-Url: http://sjero.net/git/?p=linphone;a=blobdiff_plain;f=coreapi%2FTunnelManager.cc;h=409f9c42a83635c41ba6ff2890b7166aae46d9f6;hp=186575c473f55a88d79546189f9392efdbffd13e;hb=5f0d5793b7e65a518076de6f8e253770503f8824;hpb=5bee4a0690a03b03b7ddeca73ccf5adb5e7d733c diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index 186575c4..409f9c42 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -23,31 +23,24 @@ #include #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){ @@ -66,26 +59,12 @@ int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, stru 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;iaddServer(ip,port); } @@ -155,29 +142,29 @@ void TunnelManager::setCallback(StateCallback cb, void *userdata) { 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; } @@ -185,11 +172,12 @@ void TunnelManager::start() { if (!mTunnelClient) { mTunnelClient = new TunnelClient(); mTunnelClient->setCallback((StateCallback)tunnelCallback,this); - std::list::iterator it; + list::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(); @@ -201,7 +189,7 @@ bool TunnelManager::isStarted() { } bool TunnelManager::isReady() const { - return mTunnelClient && mTunnelClient->isReady(); + return mTunnelClient && mTunnelClient->isReady() && mReady; } int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){ @@ -225,13 +213,14 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mCallback(NULL) ,mEnabled(false) ,mTunnelClient(NULL) -,mAutoDetectStarted(false) { +,mAutoDetectStarted(false) +,mReady(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; @@ -261,27 +250,29 @@ void TunnelManager::stopClient(){ } } -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); } + mReady=true; }else if (mEnabled && !mTunnelClient->isReady()){ /* we got disconnected from the tunnel */ if (lProxy && linphone_proxy_config_is_registered(lProxy)) { @@ -289,46 +280,56 @@ void TunnelManager::processTunnelEvent(){ linphone_proxy_config_edit(lProxy); linphone_core_iterate(mCore); } + mReady=false; } } +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); - } - - //make sure unregister is sent - linphone_core_iterate(mCore); + waitUnRegistration(); + mEnabled=false; + stopClient(); + mReady=false; 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); } @@ -337,19 +338,36 @@ void TunnelManager::enable(bool isEnable) { } 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; @@ -357,9 +375,9 @@ static void linphone_android_log_handler(int lev, const char *fmt, va_list args) 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*/ @@ -370,7 +388,7 @@ void TunnelManager::enableLogs(bool value) { 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 @@ -386,26 +404,40 @@ void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) { 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() { @@ -421,12 +453,22 @@ 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(){