]> sjero.net Git - linphone/blob - coreapi/TunnelManager.cc
Merge branch 'master' of git.linphone.org:linphone into upnp
[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         addServer(ip,port);
106         mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
107 }
108
109 void TunnelManager::addServer(const char *ip, int port) {
110         mServerAddrs.push_back(ServerAddr(ip,port));
111         if (mTunnelClient) mTunnelClient->addServer(ip,port);
112 }
113
114 void TunnelManager::cleanServers() {
115         mServerAddrs.clear();
116
117         UdpMirrorClientList::iterator it;
118         mAutoDetectStarted=false;
119         for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
120                 UdpMirrorClient& s=*it++;
121                 s.stop();
122         }
123         mUdpMirrorClients.clear();
124         if (mTunnelClient) mTunnelClient->cleanServers();
125 }
126
127 void TunnelManager::reconnect(){
128         if (mTunnelClient)
129                 mTunnelClient->reconnect();
130 }
131
132 void TunnelManager::setCallback(StateCallback cb, void *userdata) {
133         mCallback=cb;
134         mCallbackData=userdata;
135 }
136
137 static void sCloseRtpTransport(RtpTransport *t, void *userData){
138         TunnelSocket *s=(TunnelSocket*)userData;
139         TunnelManager *manager=(TunnelManager*)s->getUserPointer();
140         manager->closeRtpTransport(t, s);
141 }
142 void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){
143         mTunnelClient->closeSocket(s);
144         ms_free(t);
145 }
146
147 static RtpTransport *sCreateRtpTransport(void* userData, int port){
148         return ((TunnelManager *) userData)->createRtpTransport(port);
149 }
150
151 RtpTransport *TunnelManager::createRtpTransport(int port){
152         TunnelSocket *socket=mTunnelClient->createSocket(port);
153         socket->setUserPointer(this);
154         RtpTransport *t=ms_new0(RtpTransport,1);
155         t->t_getsocket=NULL;
156         t->t_recvfrom=customRecvfrom;
157         t->t_sendto=customSendto;
158         t->t_close=sCloseRtpTransport;
159         t->data=socket;
160         return t;
161 }
162
163 void TunnelManager::start() {
164         if (!mTunnelClient) {
165                 mTunnelClient = new TunnelClient();
166                 mTunnelClient->setCallback((StateCallback)tunnelCallback,this);
167                 list<ServerAddr>::iterator it;
168                 for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){
169                         const ServerAddr &addr=*it;
170                         mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort);
171                 }
172                 mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str());
173         }
174         mTunnelClient->start();
175
176         if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
177 }
178
179 bool TunnelManager::isStarted() {
180         return mTunnelClient != 0 && mTunnelClient->isStarted();
181 }
182
183 bool TunnelManager::isReady() const {
184         return mTunnelClient && mTunnelClient->isReady();
185 }
186
187 int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
188         int size;
189         msgpullup(msg,-1);
190         size=msgdsize(msg);
191         ((TunnelSocket*)t->data)->sendto(msg->b_rptr,size,to,tolen);
192         return size;
193 }
194
195 int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
196         int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen);
197         if (err>0) return err;
198         return 0;
199 }
200
201
202 TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
203 ,mCore(lc)
204 ,mSipSocket(NULL)
205 ,mCallback(NULL)
206 ,mEnabled(false)
207 ,mTunnelClient(NULL)
208 ,mAutoDetectStarted(false)
209 ,mHttpProxyPort(0){
210
211         mExosipTransport.data=this;
212         mExosipTransport.recvfrom=eXosipRecvfrom;
213         mExosipTransport.sendto=eXosipSendto;
214         mExosipTransport.select=eXosipSelect;
215         linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
216         mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
217         mTransportFactories.audio_rtcp_func_data=this;
218         mTransportFactories.audio_rtp_func=sCreateRtpTransport;
219         mTransportFactories.audio_rtp_func_data=this;
220         mTransportFactories.video_rtcp_func=sCreateRtpTransport;
221         mTransportFactories.video_rtcp_func_data=this;
222         mTransportFactories.video_rtp_func=sCreateRtpTransport;
223         mTransportFactories.video_rtp_func_data=this;
224 }
225
226 TunnelManager::~TunnelManager(){
227         stopClient();
228 }
229
230 void TunnelManager::stopClient(){
231         eXosip_transport_hook_register(NULL);
232         if (mSipSocket != NULL){
233                 sMutex.lock();
234                 mTunnelClient->closeSocket(mSipSocket);
235                 mSipSocket = NULL;
236                 sMutex.unlock();
237         }
238         if (mTunnelClient){
239                 delete mTunnelClient;
240                 mTunnelClient=NULL;
241         }
242 }
243
244 void TunnelManager::processTunnelEvent(const Event &ev){
245         LinphoneProxyConfig* lProxy;
246         linphone_core_get_default_proxy(mCore, &lProxy);
247
248         if (mEnabled && mTunnelClient->isReady()){
249                 ms_message("Tunnel is up, registering now");
250                 linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall);
251                 linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
252                 eXosip_transport_hook_register(&mExosipTransport);
253                 //force transport to udp
254                 LCSipTransports lTransport;
255                 
256                 lTransport.udp_port=15060;
257                 lTransport.tcp_port=0;
258                 lTransport.tls_port=0;
259                 lTransport.dtls_port=0;
260                 
261                 linphone_core_set_sip_transports(mCore, &lTransport);
262                 //register
263                 if (lProxy) {
264                         linphone_proxy_config_done(lProxy);
265                 }
266         }else if (mEnabled && !mTunnelClient->isReady()){
267                 /* we got disconnected from the tunnel */
268                 if (lProxy && linphone_proxy_config_is_registered(lProxy)) {
269                         /*forces de-registration so that we register again when the tunnel is up*/
270                         linphone_proxy_config_edit(lProxy);
271                         linphone_core_iterate(mCore);
272                 }
273         }
274 }
275
276 void TunnelManager::waitUnRegistration(){
277         LinphoneProxyConfig* lProxy;
278         linphone_core_get_default_proxy(mCore, &lProxy);
279         if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) {
280                 int i=0;
281                 linphone_proxy_config_edit(lProxy);
282                 //make sure unregister is sent and authenticated
283                 do{
284                         linphone_core_iterate(mCore);
285                         ms_usleep(20000);
286                         if (i>100){
287                                 ms_message("tunnel: timeout for unregistration expired, giving up");
288                                 break;
289                         }
290                         i++;
291                 }while(linphone_proxy_config_get_state(lProxy)!=LinphoneRegistrationCleared);
292         }       
293 }
294
295 void TunnelManager::enable(bool isEnable) {
296         ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
297         if (isEnable && !mEnabled){
298                 mEnabled=true;
299                 //1 save transport and firewall policy
300                 linphone_core_get_sip_transports(mCore, &mRegularTransport);
301                 mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore);
302                 //2 unregister
303                 waitUnRegistration();
304                 //3 insert tunnel
305                 start();
306         }else if (!isEnable && mEnabled){
307                 //1 unregister
308                 waitUnRegistration();
309                 
310                 mEnabled=false;
311                 stopClient();
312                 
313                 linphone_core_set_rtp_transport_factories(mCore,NULL);
314
315                 eXosip_transport_hook_register(NULL);
316                 //Restore transport and firewall policy
317                 linphone_core_set_sip_transports(mCore, &mRegularTransport);
318                 linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy);
319                 //register
320                 LinphoneProxyConfig* lProxy;
321                 linphone_core_get_default_proxy(mCore, &lProxy);
322                 if (lProxy) {
323                         linphone_proxy_config_done(lProxy);
324                 }
325
326         }
327 }
328
329 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
330         Event ev;
331         ev.mType=TunnelEvent;
332         ev.mData.mConnected=connected;
333         zis->postEvent(ev);
334 }
335
336 void TunnelManager::onIterate(){
337         mMutex.lock();
338         while(!mEvq.empty()){
339                 Event ev=mEvq.front();
340                 mEvq.pop();
341                 mMutex.unlock();
342                 if (ev.mType==TunnelEvent)
343                         processTunnelEvent(ev);
344                 else if (ev.mType==UdpMirrorClientEvent){
345                         processUdpMirrorEvent(ev);
346                 }
347                 mMutex.lock();
348         }
349         mMutex.unlock();
350 }
351
352 /*invoked from linphone_core_iterate() */
353 void TunnelManager::sOnIterate(TunnelManager *zis){
354         zis->onIterate();
355 }
356
357 #ifdef ANDROID
358 extern void linphone_android_log_handler(int prio, const char *fmt, va_list args);
359 static void linphone_android_tunnel_log_handler(int lev, const char *fmt, va_list args) {
360         int prio;
361         switch(lev){
362         case TUNNEL_DEBUG:      prio = ANDROID_LOG_DEBUG;       break;
363         case TUNNEL_INFO:       prio = ANDROID_LOG_INFO;        break;
364         case TUNNEL_NOTICE:     prio = ANDROID_LOG_INFO;        break;
365         case TUNNEL_WARN:       prio = ANDROID_LOG_WARN;        break;
366         case TUNNEL_ERROR:      prio = ANDROID_LOG_ERROR;       break;
367         default:                prio = ANDROID_LOG_DEFAULT;     break;
368         }
369         linphone_android_log_handler(prio, fmt, args);
370 }
371 #endif /*ANDROID*/
372
373 void TunnelManager::enableLogs(bool value) {
374         enableLogs(value,NULL);
375 }
376
377 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
378         if (logHandler != NULL) SetLogHandler(logHandler);
379 #ifdef ANDROID
380         else SetLogHandler(linphone_android_tunnel_log_handler);
381 #else
382         else SetLogHandler(default_log_handler);
383 #endif
384
385         if (isEnabled) {
386                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
387         } else {
388                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
389         }
390 }
391         
392
393 bool TunnelManager::isEnabled() {
394         return mEnabled;
395 }
396
397 void TunnelManager::processUdpMirrorEvent(const Event &ev){
398         if (ev.mData.mHaveUdp) {
399                 LOGI("Tunnel is not required, disabling");
400                 enable(false);
401                 mAutoDetectStarted = false;
402         } else {
403                 mCurrentUdpMirrorClient++;
404                 if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) {
405                         // enable tunnel but also try backup server
406                         LOGI("Tunnel is required, enabling; Trying backup udp mirror");
407                         
408                         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
409                         lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
410                 } else {
411                         LOGI("Tunnel is required, enabling; no backup udp mirror available");
412                         mAutoDetectStarted = false;
413                 }
414                 enable(true);
415         }
416 }
417
418 void TunnelManager::postEvent(const Event &ev){
419         mMutex.lock();
420         mEvq.push(ev);
421         mMutex.unlock();
422 }
423
424 void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
425         TunnelManager* thiz = (TunnelManager*)data;
426         Event ev;
427         ev.mType=UdpMirrorClientEvent;
428         ev.mData.mHaveUdp=isUdpAvailable;
429         thiz->postEvent(ev);
430 }
431
432 void TunnelManager::autoDetect() {
433         // first check if udp mirrors was provisionned
434         if (mUdpMirrorClients.empty()) {
435                 LOGE("No UDP mirror server configured aborting auto detection");
436                 return;
437         }
438         if (mAutoDetectStarted) {
439                 LOGE("auto detection already in progress, restarting");
440                 (*mCurrentUdpMirrorClient).stop();
441         }
442         mAutoDetectStarted=true;
443         mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
444         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
445         lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
446         
447 }
448
449 void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
450         mHttpUserName=username?username:"";
451         mHttpPasswd=passwd?passwd:"";
452         if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd);
453 }
454
455 void TunnelManager::setHttpProxy(const char *host,int port, const char *username, const char *passwd){
456         mHttpUserName=username?username:"";
457         mHttpPasswd=passwd?passwd:"";
458         mHttpProxyPort=(port>0) ? port : 0;
459         mHttpProxyHost=host ? host : "";
460         if (mTunnelClient) mTunnelClient->setHttpProxy(host, port, username, passwd);
461 }
462
463 LinphoneCore *TunnelManager::getLinphoneCore(){
464         return mCore;
465 }