2 * C Implementation: tunnel
7 * Author: Simon Morlat <simon.morlat@linphone.org>, (C) 2009
9 * Copyright (C) 2010 Belledonne Comunications, Grenoble, France
14 #include "TunnelManager.hh"
16 #include "ortp/rtpsession.h"
17 #include "linphonecore.h"
18 #include "linphonecore_utils.h"
19 #include "eXosip2/eXosip_transport_hook.h"
20 #include "tunnel/udp_mirror.hh"
23 #include <android/log.h>
27 using namespace belledonnecomm;
28 using namespace ::std;
30 Mutex TunnelManager::sMutex;
32 int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){
33 TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
36 if (lTunnelMgr->mSipSocket==NULL){
40 lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
42 //ignore the error in all cases, retransmissions might be successful.
46 int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){
47 TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
50 if (lTunnelMgr->mSipSocket==NULL){
52 return 0;//let ignore the error
54 err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen);
59 int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){
60 struct timeval begin,cur;
61 TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
62 if (s1 && tv!=0 && tv->tv_sec){
63 /*this is the select from udp.c, the one that is interesting to us*/
64 NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket();
65 NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd();
68 gettimeofday(&begin,NULL);
75 if (lTunnelMgr->mSipSocket!=NULL){
76 if (lTunnelMgr->mSipSocket->hasData()) {
78 /* we make exosip believe that it has udp data to read*/
84 gettimeofday(&cur,NULL);
85 if (cur.tv_sec-begin.tv_sec>tv->tv_sec) {
92 if (select(max_fds,s1,s2,s3,&abit)==1) {
98 /*select called from other places, only the control fd is present */
99 return select(max_fds,s1,s2,s3,tv);
104 void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
107 ms_warning("Adding tunnel server with empty ip, it will not work!");
110 mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
113 void TunnelManager::addServer(const char *ip, int port) {
116 ms_warning("Adding tunnel server with empty ip, it will not work!");
118 mServerAddrs.push_back(ServerAddr(ip,port));
119 if (mTunnelClient) mTunnelClient->addServer(ip,port);
122 void TunnelManager::cleanServers() {
123 mServerAddrs.clear();
125 UdpMirrorClientList::iterator it;
126 mAutoDetectStarted=false;
127 for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
128 UdpMirrorClient& s=*it++;
131 mUdpMirrorClients.clear();
132 if (mTunnelClient) mTunnelClient->cleanServers();
135 void TunnelManager::reconnect(){
137 mTunnelClient->reconnect();
140 void TunnelManager::setCallback(StateCallback cb, void *userdata) {
142 mCallbackData=userdata;
145 static void sCloseRtpTransport(RtpTransport *t, void *userData){
146 TunnelSocket *s=(TunnelSocket*)userData;
147 TunnelManager *manager=(TunnelManager*)s->getUserPointer();
148 manager->closeRtpTransport(t, s);
150 void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){
151 mTunnelClient->closeSocket(s);
155 static RtpTransport *sCreateRtpTransport(void* userData, int port){
156 return ((TunnelManager *) userData)->createRtpTransport(port);
159 RtpTransport *TunnelManager::createRtpTransport(int port){
160 TunnelSocket *socket=mTunnelClient->createSocket(port);
161 socket->setUserPointer(this);
162 RtpTransport *t=ms_new0(RtpTransport,1);
164 t->t_recvfrom=customRecvfrom;
165 t->t_sendto=customSendto;
166 t->t_close=sCloseRtpTransport;
171 void TunnelManager::start() {
172 if (!mTunnelClient) {
173 mTunnelClient = new TunnelClient();
174 mTunnelClient->setCallback((StateCallback)tunnelCallback,this);
175 list<ServerAddr>::iterator it;
176 for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){
177 const ServerAddr &addr=*it;
178 mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort);
180 mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str());
182 mTunnelClient->start();
184 if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
187 bool TunnelManager::isStarted() {
188 return mTunnelClient != 0 && mTunnelClient->isStarted();
191 bool TunnelManager::isReady() const {
192 return mTunnelClient && mTunnelClient->isReady() && mReady;
195 int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
199 ((TunnelSocket*)t->data)->sendto(msg->b_rptr,size,to,tolen);
203 int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
204 int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen);
205 if (err>0) return err;
210 TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
216 ,mAutoDetectStarted(false)
220 mExosipTransport.data=this;
221 mExosipTransport.recvfrom=eXosipRecvfrom;
222 mExosipTransport.sendto=eXosipSendto;
223 mExosipTransport.select=eXosipSelect;
224 linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
225 mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
226 mTransportFactories.audio_rtcp_func_data=this;
227 mTransportFactories.audio_rtp_func=sCreateRtpTransport;
228 mTransportFactories.audio_rtp_func_data=this;
229 mTransportFactories.video_rtcp_func=sCreateRtpTransport;
230 mTransportFactories.video_rtcp_func_data=this;
231 mTransportFactories.video_rtp_func=sCreateRtpTransport;
232 mTransportFactories.video_rtp_func_data=this;
235 TunnelManager::~TunnelManager(){
239 void TunnelManager::stopClient(){
240 eXosip_transport_hook_register(NULL);
241 if (mSipSocket != NULL){
243 mTunnelClient->closeSocket(mSipSocket);
248 delete mTunnelClient;
253 void TunnelManager::processTunnelEvent(const Event &ev){
254 LinphoneProxyConfig* lProxy;
255 linphone_core_get_default_proxy(mCore, &lProxy);
257 if (mEnabled && mTunnelClient->isReady()){
258 ms_message("Tunnel is up, registering now");
259 linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall);
260 linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
261 eXosip_transport_hook_register(&mExosipTransport);
262 //force transport to udp
263 LCSipTransports lTransport;
265 lTransport.udp_port=(0xDFFF&random())+1024;
266 lTransport.tcp_port=0;
267 lTransport.tls_port=0;
268 lTransport.dtls_port=0;
270 linphone_core_set_sip_transports(mCore, &lTransport);
273 linphone_proxy_config_done(lProxy);
276 }else if (mEnabled && !mTunnelClient->isReady()){
277 /* we got disconnected from the tunnel */
278 if (lProxy && linphone_proxy_config_is_registered(lProxy)) {
279 /*forces de-registration so that we register again when the tunnel is up*/
280 linphone_proxy_config_edit(lProxy);
281 linphone_core_iterate(mCore);
287 void TunnelManager::waitUnRegistration(){
288 LinphoneProxyConfig* lProxy;
289 linphone_core_get_default_proxy(mCore, &lProxy);
290 if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) {
292 linphone_proxy_config_edit(lProxy);
293 //make sure unregister is sent and authenticated
295 linphone_core_iterate(mCore);
298 ms_message("tunnel: timeout for unregistration expired, giving up");
302 }while(linphone_proxy_config_get_state(lProxy)!=LinphoneRegistrationCleared);
306 void TunnelManager::enable(bool isEnable) {
307 ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
308 if (isEnable && !mEnabled){
310 //1 save transport and firewall policy
311 linphone_core_get_sip_transports(mCore, &mRegularTransport);
312 mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore);
314 waitUnRegistration();
317 }else if (!isEnable && mEnabled){
319 waitUnRegistration();
324 linphone_core_set_rtp_transport_factories(mCore,NULL);
326 eXosip_transport_hook_register(NULL);
327 //Restore transport and firewall policy
328 linphone_core_set_sip_transports(mCore, &mRegularTransport);
329 linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy);
331 LinphoneProxyConfig* lProxy;
332 linphone_core_get_default_proxy(mCore, &lProxy);
334 linphone_proxy_config_done(lProxy);
340 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
342 ev.mType=TunnelEvent;
343 ev.mData.mConnected=connected;
347 void TunnelManager::onIterate(){
349 while(!mEvq.empty()){
350 Event ev=mEvq.front();
353 if (ev.mType==TunnelEvent)
354 processTunnelEvent(ev);
355 else if (ev.mType==UdpMirrorClientEvent){
356 processUdpMirrorEvent(ev);
363 /*invoked from linphone_core_iterate() */
364 void TunnelManager::sOnIterate(TunnelManager *zis){
369 extern void linphone_android_log_handler(int prio, const char *fmt, va_list args);
370 static void linphone_android_tunnel_log_handler(int lev, const char *fmt, va_list args) {
373 case TUNNEL_DEBUG: prio = ANDROID_LOG_DEBUG; break;
374 case TUNNEL_INFO: prio = ANDROID_LOG_INFO; break;
375 case TUNNEL_NOTICE: prio = ANDROID_LOG_INFO; break;
376 case TUNNEL_WARN: prio = ANDROID_LOG_WARN; break;
377 case TUNNEL_ERROR: prio = ANDROID_LOG_ERROR; break;
378 default: prio = ANDROID_LOG_DEFAULT; break;
380 linphone_android_log_handler(prio, fmt, args);
384 void TunnelManager::enableLogs(bool value) {
385 enableLogs(value,NULL);
388 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
389 if (logHandler != NULL) SetLogHandler(logHandler);
391 else SetLogHandler(linphone_android_tunnel_log_handler);
393 else SetLogHandler(default_log_handler);
397 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
399 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
404 bool TunnelManager::isEnabled() {
408 void TunnelManager::processUdpMirrorEvent(const Event &ev){
409 if (ev.mData.mHaveUdp) {
410 LOGI("Tunnel is not required, disabling");
412 mAutoDetectStarted = false;
414 mCurrentUdpMirrorClient++;
415 if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) {
416 // enable tunnel but also try backup server
417 LOGI("Tunnel is required, enabling; Trying backup udp mirror");
419 UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
420 lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
422 LOGI("Tunnel is required, enabling; no backup udp mirror available");
423 mAutoDetectStarted = false;
429 void TunnelManager::postEvent(const Event &ev){
435 void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
436 TunnelManager* thiz = (TunnelManager*)data;
438 ev.mType=UdpMirrorClientEvent;
439 ev.mData.mHaveUdp=isUdpAvailable;
443 void TunnelManager::autoDetect() {
444 // first check if udp mirrors was provisionned
445 if (mUdpMirrorClients.empty()) {
446 LOGE("No UDP mirror server configured aborting auto detection");
449 if (mAutoDetectStarted) {
450 LOGE("auto detection already in progress, restarting");
451 (*mCurrentUdpMirrorClient).stop();
453 mAutoDetectStarted=true;
454 mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
455 UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
456 lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
460 void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
461 mHttpUserName=username?username:"";
462 mHttpPasswd=passwd?passwd:"";
463 if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd);
466 void TunnelManager::setHttpProxy(const char *host,int port, const char *username, const char *passwd){
467 mHttpUserName=username?username:"";
468 mHttpPasswd=passwd?passwd:"";
469 mHttpProxyPort=(port>0) ? port : 0;
470 mHttpProxyHost=host ? host : "";
471 if (mTunnelClient) mTunnelClient->setHttpProxy(host, port, username, passwd);
474 LinphoneCore *TunnelManager::getLinphoneCore(){