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