]> sjero.net Git - linphone/blob - coreapi/TunnelManager.cc
d1020b1b2782f6d431fefa607771a1ea4bd05173
[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();
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 ,mHttpProxyPort(0){
218
219         mExosipTransport.data=this;
220         mExosipTransport.recvfrom=eXosipRecvfrom;
221         mExosipTransport.sendto=eXosipSendto;
222         mExosipTransport.select=eXosipSelect;
223         linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
224         mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
225         mTransportFactories.audio_rtcp_func_data=this;
226         mTransportFactories.audio_rtp_func=sCreateRtpTransport;
227         mTransportFactories.audio_rtp_func_data=this;
228         mTransportFactories.video_rtcp_func=sCreateRtpTransport;
229         mTransportFactories.video_rtcp_func_data=this;
230         mTransportFactories.video_rtp_func=sCreateRtpTransport;
231         mTransportFactories.video_rtp_func_data=this;
232 }
233
234 TunnelManager::~TunnelManager(){
235         stopClient();
236 }
237
238 void TunnelManager::stopClient(){
239         eXosip_transport_hook_register(NULL);
240         if (mSipSocket != NULL){
241                 sMutex.lock();
242                 mTunnelClient->closeSocket(mSipSocket);
243                 mSipSocket = NULL;
244                 sMutex.unlock();
245         }
246         if (mTunnelClient){
247                 delete mTunnelClient;
248                 mTunnelClient=NULL;
249         }
250 }
251
252 void TunnelManager::processTunnelEvent(const Event &ev){
253         LinphoneProxyConfig* lProxy;
254         linphone_core_get_default_proxy(mCore, &lProxy);
255
256         if (mEnabled && mTunnelClient->isReady()){
257                 ms_message("Tunnel is up, registering now");
258                 linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall);
259                 linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
260                 eXosip_transport_hook_register(&mExosipTransport);
261                 //force transport to udp
262                 LCSipTransports lTransport;
263                 
264                 lTransport.udp_port=(0xDFFF&random())+1024;
265                 lTransport.tcp_port=0;
266                 lTransport.tls_port=0;
267                 lTransport.dtls_port=0;
268                 
269                 linphone_core_set_sip_transports(mCore, &lTransport);
270                 //register
271                 if (lProxy) {
272                         linphone_proxy_config_done(lProxy);
273                 }
274         }else if (mEnabled && !mTunnelClient->isReady()){
275                 /* we got disconnected from the tunnel */
276                 if (lProxy && linphone_proxy_config_is_registered(lProxy)) {
277                         /*forces de-registration so that we register again when the tunnel is up*/
278                         linphone_proxy_config_edit(lProxy);
279                         linphone_core_iterate(mCore);
280                 }
281         }
282 }
283
284 void TunnelManager::waitUnRegistration(){
285         LinphoneProxyConfig* lProxy;
286         linphone_core_get_default_proxy(mCore, &lProxy);
287         if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) {
288                 int i=0;
289                 linphone_proxy_config_edit(lProxy);
290                 //make sure unregister is sent and authenticated
291                 do{
292                         linphone_core_iterate(mCore);
293                         ms_usleep(20000);
294                         if (i>100){
295                                 ms_message("tunnel: timeout for unregistration expired, giving up");
296                                 break;
297                         }
298                         i++;
299                 }while(linphone_proxy_config_get_state(lProxy)!=LinphoneRegistrationCleared);
300         }       
301 }
302
303 void TunnelManager::enable(bool isEnable) {
304         ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
305         if (isEnable && !mEnabled){
306                 mEnabled=true;
307                 //1 save transport and firewall policy
308                 linphone_core_get_sip_transports(mCore, &mRegularTransport);
309                 mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore);
310                 //2 unregister
311                 waitUnRegistration();
312                 //3 insert tunnel
313                 start();
314         }else if (!isEnable && mEnabled){
315                 //1 unregister
316                 waitUnRegistration();
317                 
318                 mEnabled=false;
319                 stopClient();
320                 
321                 linphone_core_set_rtp_transport_factories(mCore,NULL);
322
323                 eXosip_transport_hook_register(NULL);
324                 //Restore transport and firewall policy
325                 linphone_core_set_sip_transports(mCore, &mRegularTransport);
326                 linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy);
327                 //register
328                 LinphoneProxyConfig* lProxy;
329                 linphone_core_get_default_proxy(mCore, &lProxy);
330                 if (lProxy) {
331                         linphone_proxy_config_done(lProxy);
332                 }
333
334         }
335 }
336
337 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
338         Event ev;
339         ev.mType=TunnelEvent;
340         ev.mData.mConnected=connected;
341         zis->postEvent(ev);
342 }
343
344 void TunnelManager::onIterate(){
345         mMutex.lock();
346         while(!mEvq.empty()){
347                 Event ev=mEvq.front();
348                 mEvq.pop();
349                 mMutex.unlock();
350                 if (ev.mType==TunnelEvent)
351                         processTunnelEvent(ev);
352                 else if (ev.mType==UdpMirrorClientEvent){
353                         processUdpMirrorEvent(ev);
354                 }
355                 mMutex.lock();
356         }
357         mMutex.unlock();
358 }
359
360 /*invoked from linphone_core_iterate() */
361 void TunnelManager::sOnIterate(TunnelManager *zis){
362         zis->onIterate();
363 }
364
365 #ifdef ANDROID
366 extern void linphone_android_log_handler(int prio, const char *fmt, va_list args);
367 static void linphone_android_tunnel_log_handler(int lev, const char *fmt, va_list args) {
368         int prio;
369         switch(lev){
370         case TUNNEL_DEBUG:      prio = ANDROID_LOG_DEBUG;       break;
371         case TUNNEL_INFO:       prio = ANDROID_LOG_INFO;        break;
372         case TUNNEL_NOTICE:     prio = ANDROID_LOG_INFO;        break;
373         case TUNNEL_WARN:       prio = ANDROID_LOG_WARN;        break;
374         case TUNNEL_ERROR:      prio = ANDROID_LOG_ERROR;       break;
375         default:                prio = ANDROID_LOG_DEFAULT;     break;
376         }
377         linphone_android_log_handler(prio, fmt, args);
378 }
379 #endif /*ANDROID*/
380
381 void TunnelManager::enableLogs(bool value) {
382         enableLogs(value,NULL);
383 }
384
385 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
386         if (logHandler != NULL) SetLogHandler(logHandler);
387 #ifdef ANDROID
388         else SetLogHandler(linphone_android_tunnel_log_handler);
389 #else
390         else SetLogHandler(default_log_handler);
391 #endif
392
393         if (isEnabled) {
394                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
395         } else {
396                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
397         }
398 }
399         
400
401 bool TunnelManager::isEnabled() {
402         return mEnabled;
403 }
404
405 void TunnelManager::processUdpMirrorEvent(const Event &ev){
406         if (ev.mData.mHaveUdp) {
407                 LOGI("Tunnel is not required, disabling");
408                 enable(false);
409                 mAutoDetectStarted = false;
410         } else {
411                 mCurrentUdpMirrorClient++;
412                 if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) {
413                         // enable tunnel but also try backup server
414                         LOGI("Tunnel is required, enabling; Trying backup udp mirror");
415                         
416                         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
417                         lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
418                 } else {
419                         LOGI("Tunnel is required, enabling; no backup udp mirror available");
420                         mAutoDetectStarted = false;
421                 }
422                 enable(true);
423         }
424 }
425
426 void TunnelManager::postEvent(const Event &ev){
427         mMutex.lock();
428         mEvq.push(ev);
429         mMutex.unlock();
430 }
431
432 void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
433         TunnelManager* thiz = (TunnelManager*)data;
434         Event ev;
435         ev.mType=UdpMirrorClientEvent;
436         ev.mData.mHaveUdp=isUdpAvailable;
437         thiz->postEvent(ev);
438 }
439
440 void TunnelManager::autoDetect() {
441         // first check if udp mirrors was provisionned
442         if (mUdpMirrorClients.empty()) {
443                 LOGE("No UDP mirror server configured aborting auto detection");
444                 return;
445         }
446         if (mAutoDetectStarted) {
447                 LOGE("auto detection already in progress, restarting");
448                 (*mCurrentUdpMirrorClient).stop();
449         }
450         mAutoDetectStarted=true;
451         mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
452         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
453         lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
454         
455 }
456
457 void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
458         mHttpUserName=username?username:"";
459         mHttpPasswd=passwd?passwd:"";
460         if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd);
461 }
462
463 void TunnelManager::setHttpProxy(const char *host,int port, const char *username, const char *passwd){
464         mHttpUserName=username?username:"";
465         mHttpPasswd=passwd?passwd:"";
466         mHttpProxyPort=(port>0) ? port : 0;
467         mHttpProxyHost=host ? host : "";
468         if (mTunnelClient) mTunnelClient->setHttpProxy(host, port, username, passwd);
469 }
470
471 LinphoneCore *TunnelManager::getLinphoneCore(){
472         return mCore;
473 }