]> sjero.net Git - linphone/blob - coreapi/TunnelManager.cc
- do not register outside of tunnel when tunnel is activated but not yet connected.
[linphone] / coreapi / TunnelManager.cc
1 /*
2  *  C Implementation: tunnel
3  *
4  * Description: 
5  *
6  *
7  * Author: Simon Morlat <simon.morlat@linphone.org>, (C) 2009
8  *
9  * Copyright (C) 2010  Belledonne Comunications, Grenoble, France
10  *
11  */
12
13
14 #include "TunnelManager.hh"
15
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"
21
22 #ifdef ANDROID
23 #include <android/log.h>
24 #endif
25
26
27 using namespace belledonnecomm;
28 using namespace ::std;
29
30 Mutex TunnelManager::sMutex;
31
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;
34         
35         sMutex.lock();
36         if (lTunnelMgr->mSipSocket==NULL){
37                 sMutex.unlock();
38                 return len;
39         }
40         lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
41         sMutex.unlock();
42         //ignore the error in all cases, retransmissions might be successful.
43         return len;
44 }
45
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;
48         int err;
49         sMutex.lock();
50         if (lTunnelMgr->mSipSocket==NULL){
51                 sMutex.unlock();
52                 return 0;//let ignore the error
53         }
54         err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen);
55         sMutex.unlock();
56         return err;
57 }
58
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();
66
67                 FD_ZERO(s1);
68                 gettimeofday(&begin,NULL);
69                 do{
70                         struct timeval abit;
71
72                         abit.tv_sec=0;
73                         abit.tv_usec=20000;
74                         sMutex.lock();
75                         if (lTunnelMgr->mSipSocket!=NULL){
76                                 if (lTunnelMgr->mSipSocket->hasData()) {
77                                         sMutex.unlock();
78                                         /* we make exosip believe that it has udp data to read*/
79                                         FD_SET(udp_fd,s1);
80                                         return 1;
81                                 }
82                         }
83                         sMutex.unlock();
84                         gettimeofday(&cur,NULL);
85                         if (cur.tv_sec-begin.tv_sec>tv->tv_sec) {
86                                 FD_SET(controlfd,s1);
87                                 FD_SET(udp_fd,s1);
88                                 return 0;
89                         }
90                         FD_ZERO(s1);
91                         FD_SET(controlfd,s1);
92                         if (select(max_fds,s1,s2,s3,&abit)==1) {
93                                 return 1;
94                         }
95                 }while(1);
96                 
97         }else{
98                 /*select called from other places, only the control fd is present */
99                 return select(max_fds,s1,s2,s3,tv);
100         }
101 }
102
103
104 void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
105         if (ip == NULL) {
106                 ip = "";
107                 ms_warning("Adding tunnel server with empty ip, it will not work!");
108         }
109         addServer(ip,port);
110         mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
111 }
112
113 void TunnelManager::addServer(const char *ip, int port) {
114         if (ip == NULL) {
115                 ip = "";
116                 ms_warning("Adding tunnel server with empty ip, it will not work!");
117         }
118         mServerAddrs.push_back(ServerAddr(ip,port));
119         if (mTunnelClient) mTunnelClient->addServer(ip,port);
120 }
121
122 void TunnelManager::cleanServers() {
123         mServerAddrs.clear();
124
125         UdpMirrorClientList::iterator it;
126         mAutoDetectStarted=false;
127         for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
128                 UdpMirrorClient& s=*it++;
129                 s.stop();
130         }
131         mUdpMirrorClients.clear();
132         if (mTunnelClient) mTunnelClient->cleanServers();
133 }
134
135 void TunnelManager::reconnect(){
136         if (mTunnelClient)
137                 mTunnelClient->reconnect();
138 }
139
140 void TunnelManager::setCallback(StateCallback cb, void *userdata) {
141         mCallback=cb;
142         mCallbackData=userdata;
143 }
144
145 static void sCloseRtpTransport(RtpTransport *t, void *userData){
146         TunnelSocket *s=(TunnelSocket*)userData;
147         TunnelManager *manager=(TunnelManager*)s->getUserPointer();
148         manager->closeRtpTransport(t, s);
149 }
150 void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){
151         mTunnelClient->closeSocket(s);
152         ms_free(t);
153 }
154
155 static RtpTransport *sCreateRtpTransport(void* userData, int port){
156         return ((TunnelManager *) userData)->createRtpTransport(port);
157 }
158
159 RtpTransport *TunnelManager::createRtpTransport(int port){
160         TunnelSocket *socket=mTunnelClient->createSocket(port);
161         socket->setUserPointer(this);
162         RtpTransport *t=ms_new0(RtpTransport,1);
163         t->t_getsocket=NULL;
164         t->t_recvfrom=customRecvfrom;
165         t->t_sendto=customSendto;
166         t->t_close=sCloseRtpTransport;
167         t->data=socket;
168         return t;
169 }
170
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);
179                 }
180                 mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str());
181         }
182         mTunnelClient->start();
183
184         if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
185 }
186
187 bool TunnelManager::isStarted() {
188         return mTunnelClient != 0 && mTunnelClient->isStarted();
189 }
190
191 bool TunnelManager::isReady() const {
192         return mTunnelClient && mTunnelClient->isReady() && mReady;
193 }
194
195 int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
196         int size;
197         msgpullup(msg,-1);
198         size=msgdsize(msg);
199         ((TunnelSocket*)t->data)->sendto(msg->b_rptr,size,to,tolen);
200         return size;
201 }
202
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;
206         return 0;
207 }
208
209
210 TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
211 ,mCore(lc)
212 ,mSipSocket(NULL)
213 ,mCallback(NULL)
214 ,mEnabled(false)
215 ,mTunnelClient(NULL)
216 ,mAutoDetectStarted(false)
217 ,mReady(false)
218 ,mHttpProxyPort(0){
219
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;
233 }
234
235 TunnelManager::~TunnelManager(){
236         stopClient();
237 }
238
239 void TunnelManager::stopClient(){
240         eXosip_transport_hook_register(NULL);
241         if (mSipSocket != NULL){
242                 sMutex.lock();
243                 mTunnelClient->closeSocket(mSipSocket);
244                 mSipSocket = NULL;
245                 sMutex.unlock();
246         }
247         if (mTunnelClient){
248                 delete mTunnelClient;
249                 mTunnelClient=NULL;
250         }
251 }
252
253 void TunnelManager::processTunnelEvent(const Event &ev){
254         LinphoneProxyConfig* lProxy;
255         linphone_core_get_default_proxy(mCore, &lProxy);
256
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;
264                 
265                 lTransport.udp_port=(0xDFFF&random())+1024;
266                 lTransport.tcp_port=0;
267                 lTransport.tls_port=0;
268                 lTransport.dtls_port=0;
269                 
270                 linphone_core_set_sip_transports(mCore, &lTransport);
271                 //register
272                 if (lProxy) {
273                         linphone_proxy_config_done(lProxy);
274                 }
275                 mReady=true;
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);
282                 }
283                 mReady=false;
284         }
285 }
286
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) {
291                 int i=0;
292                 linphone_proxy_config_edit(lProxy);
293                 //make sure unregister is sent and authenticated
294                 do{
295                         linphone_core_iterate(mCore);
296                         ms_usleep(20000);
297                         if (i>100){
298                                 ms_message("tunnel: timeout for unregistration expired, giving up");
299                                 break;
300                         }
301                         i++;
302                 }while(linphone_proxy_config_get_state(lProxy)!=LinphoneRegistrationCleared);
303         }       
304 }
305
306 void TunnelManager::enable(bool isEnable) {
307         ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
308         if (isEnable && !mEnabled){
309                 mEnabled=true;
310                 //1 save transport and firewall policy
311                 linphone_core_get_sip_transports(mCore, &mRegularTransport);
312                 mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore);
313                 //2 unregister
314                 waitUnRegistration();
315                 //3 insert tunnel
316                 start();
317         }else if (!isEnable && mEnabled){
318                 //1 unregister
319                 waitUnRegistration();
320                 
321                 mEnabled=false;
322                 stopClient();
323                 mReady=false;
324                 linphone_core_set_rtp_transport_factories(mCore,NULL);
325
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);
330                 //register
331                 LinphoneProxyConfig* lProxy;
332                 linphone_core_get_default_proxy(mCore, &lProxy);
333                 if (lProxy) {
334                         linphone_proxy_config_done(lProxy);
335                 }
336
337         }
338 }
339
340 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
341         Event ev;
342         ev.mType=TunnelEvent;
343         ev.mData.mConnected=connected;
344         zis->postEvent(ev);
345 }
346
347 void TunnelManager::onIterate(){
348         mMutex.lock();
349         while(!mEvq.empty()){
350                 Event ev=mEvq.front();
351                 mEvq.pop();
352                 mMutex.unlock();
353                 if (ev.mType==TunnelEvent)
354                         processTunnelEvent(ev);
355                 else if (ev.mType==UdpMirrorClientEvent){
356                         processUdpMirrorEvent(ev);
357                 }
358                 mMutex.lock();
359         }
360         mMutex.unlock();
361 }
362
363 /*invoked from linphone_core_iterate() */
364 void TunnelManager::sOnIterate(TunnelManager *zis){
365         zis->onIterate();
366 }
367
368 #ifdef ANDROID
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) {
371         int prio;
372         switch(lev){
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;
379         }
380         linphone_android_log_handler(prio, fmt, args);
381 }
382 #endif /*ANDROID*/
383
384 void TunnelManager::enableLogs(bool value) {
385         enableLogs(value,NULL);
386 }
387
388 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
389         if (logHandler != NULL) SetLogHandler(logHandler);
390 #ifdef ANDROID
391         else SetLogHandler(linphone_android_tunnel_log_handler);
392 #else
393         else SetLogHandler(default_log_handler);
394 #endif
395
396         if (isEnabled) {
397                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
398         } else {
399                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
400         }
401 }
402         
403
404 bool TunnelManager::isEnabled() {
405         return mEnabled;
406 }
407
408 void TunnelManager::processUdpMirrorEvent(const Event &ev){
409         if (ev.mData.mHaveUdp) {
410                 LOGI("Tunnel is not required, disabling");
411                 enable(false);
412                 mAutoDetectStarted = false;
413         } else {
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");
418                         
419                         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
420                         lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
421                 } else {
422                         LOGI("Tunnel is required, enabling; no backup udp mirror available");
423                         mAutoDetectStarted = false;
424                 }
425                 enable(true);
426         }
427 }
428
429 void TunnelManager::postEvent(const Event &ev){
430         mMutex.lock();
431         mEvq.push(ev);
432         mMutex.unlock();
433 }
434
435 void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
436         TunnelManager* thiz = (TunnelManager*)data;
437         Event ev;
438         ev.mType=UdpMirrorClientEvent;
439         ev.mData.mHaveUdp=isUdpAvailable;
440         thiz->postEvent(ev);
441 }
442
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");
447                 return;
448         }
449         if (mAutoDetectStarted) {
450                 LOGE("auto detection already in progress, restarting");
451                 (*mCurrentUdpMirrorClient).stop();
452         }
453         mAutoDetectStarted=true;
454         mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
455         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
456         lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
457         
458 }
459
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);
464 }
465
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);
472 }
473
474 LinphoneCore *TunnelManager::getLinphoneCore(){
475         return mCore;
476 }