]> sjero.net Git - linphone/blob - coreapi/TunnelManager.cc
Merge branch 'master' into tunnel
[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 #ifdef recvfrom 
27 #undef recvfrom
28 #endif
29 #ifdef sendto 
30 #undef sendto
31 #endif
32 #ifdef select 
33 #undef select
34 #endif
35
36 using namespace belledonnecomm;
37
38 Mutex TunnelManager::sMutex;
39
40 int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){
41         TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
42         int err;
43         sMutex.lock();
44         if (lTunnelMgr->mSipSocket==NULL){
45                 sMutex.unlock();
46                 return len;//let ignore the error
47         }
48         err=lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
49         sMutex.unlock();
50         return err;
51 }
52
53 int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){
54         TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
55         int err;
56         sMutex.lock();
57         if (lTunnelMgr->mSipSocket==NULL){
58                 sMutex.unlock();
59                 return 0;//let ignore the error
60         }
61         err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen);
62         sMutex.unlock();
63         return err;
64 }
65
66 int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){
67         struct timeval begin,cur;
68         TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
69         if (tv!=0 && tv->tv_sec){
70                 /*this is the select from udp.c, the one that is interesting to us*/
71                 int i;
72                 int udp_fd=eXosip_get_udp_socket();
73                 int controlfd=-1;
74
75                 /*
76                         Find the udp fd and the control fd
77                 */
78                 for(i=0;i<max_fds;++i){
79                         if (FD_ISSET(i,s1) && i!=udp_fd){
80                                 controlfd=i;
81                                 break;
82                         }
83                 }
84                 if (controlfd==-1){
85                         ms_error("Could not find control fd !");
86                         return -1;
87                 }
88                 FD_ZERO(s1);            
89                 gettimeofday(&begin,NULL);
90                 do{
91                         struct timeval abit;
92
93                         abit.tv_sec=0;
94                         abit.tv_usec=20000;
95                         sMutex.lock();
96                         if (lTunnelMgr->mSipSocket!=NULL){
97                                 if (lTunnelMgr->mSipSocket->hasData()) {
98                                         sMutex.unlock();
99                                         /* we make exosip believe that it has udp data to read*/
100                                         FD_SET(udp_fd,s1);
101                                         return 1;
102                                 }
103                         }
104                         sMutex.unlock();
105                         gettimeofday(&cur,NULL);
106                         if (cur.tv_sec-begin.tv_sec>tv->tv_sec) {
107                                 FD_SET(controlfd,s1);
108                                 FD_SET(udp_fd,s1);
109                                 return 0;
110                         }
111                         FD_ZERO(s1);
112                         FD_SET(controlfd,s1);
113                         if (select(max_fds,s1,s2,s3,&abit)==1) {
114                                 return 1;
115                         }
116                 }while(1);
117                 
118         }else{
119                 /*select called from other places, only the control fd is present */
120                 return select(max_fds,s1,s2,s3,tv);
121         }
122 }
123
124
125 void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
126         addServer(ip,port);
127         mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
128 }
129
130 void TunnelManager::addServer(const char *ip, int port) {
131         mServerAddrs.push_back(ServerAddr(ip,port));
132         if (mTunnelClient) mTunnelClient->addServer(ip,port);
133 }
134
135 void TunnelManager::cleanServers() {
136         mServerAddrs.clear();
137
138         UdpMirrorClientList::iterator it;
139         mAutoDetectStarted=false;
140         for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
141                 UdpMirrorClient& s=*it++;
142                 s.stop();
143         }
144         mUdpMirrorClients.clear();
145         if (mTunnelClient) mTunnelClient->cleanServers();
146 }
147
148 void TunnelManager::reconnect(){
149         if (mTunnelClient)
150                 mTunnelClient->reconnect();
151 }
152
153 void TunnelManager::setCallback(StateCallback cb, void *userdata) {
154         mCallback=cb;
155         mCallbackData=userdata;
156 }
157
158 static void sCloseRtpTransport(RtpTransport *t, void *userData){
159         TunnelSocket *s=(TunnelSocket*)userData;
160         TunnelManager::TunnelManager *manager=(TunnelManager::TunnelManager*)s->getUserPointer();
161         manager->closeRtpTransport(t, s);
162 }
163 void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){
164         mTunnelClient->closeSocket(s);
165         ms_free(t);
166 }
167
168 static RtpTransport *sCreateRtpTransport(void* userData, int port){
169         return ((TunnelManager::TunnelManager *) userData)->createRtpTransport(port);
170 }
171
172 RtpTransport *TunnelManager::createRtpTransport(int port){
173         TunnelSocket *socket=mTunnelClient->createSocket(port);
174         socket->setUserPointer(this);
175         RtpTransport *t=ms_new0(RtpTransport,1);
176         t->t_getsocket=NULL;
177         t->t_recvfrom=customRecvfrom;
178         t->t_sendto=customSendto;
179         t->t_close=sCloseRtpTransport;
180         t->data=socket;
181         return t;
182 }
183
184 void TunnelManager::start() {
185         if (!mTunnelClient) {
186                 mTunnelClient = new TunnelClient();
187                 mTunnelClient->setCallback((StateCallback)tunnelCallback,this);
188                 std::list<ServerAddr>::iterator it;
189                 for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){
190                         const ServerAddr &addr=*it;
191                         mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort);
192                 }
193                 if(!mHttpUserName.empty()) {
194                         mTunnelClient->setHttpProxyAuthInfo(mHttpUserName.c_str(), mHttpPasswd.c_str());
195                 }
196         }
197         mTunnelClient->start();
198
199         if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
200 }
201
202 bool TunnelManager::isStarted() {
203         return mTunnelClient != 0 && mTunnelClient->isStarted();
204 }
205
206 bool TunnelManager::isReady() const {
207         return mTunnelClient && mTunnelClient->isReady();
208 }
209
210 int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
211         int size;
212         msgpullup(msg,-1);
213         size=msgdsize(msg);
214         ((TunnelSocket*)t->data)->sendto(msg->b_rptr,size,to,tolen);
215         return size;
216 }
217
218 int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
219         int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen);
220         if (err>0) return err;
221         return 0;
222 }
223
224
225 TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
226 ,mCore(lc)
227 ,mSipSocket(NULL)
228 ,mCallback(NULL)
229 ,mEnabled(false)
230 ,mTunnelClient(NULL)
231 ,mAutoDetectStarted(false) {
232
233         mExosipTransport.data=this;
234         mExosipTransport.recvfrom=eXosipRecvfrom;
235         mExosipTransport.sendto=eXosipSendto;
236         mExosipTransport.select=eXosipSelect;
237         mStateChanged=false;
238         linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
239         mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
240         mTransportFactories.audio_rtcp_func_data=this;
241         mTransportFactories.audio_rtp_func=sCreateRtpTransport;
242         mTransportFactories.audio_rtp_func_data=this;
243         mTransportFactories.video_rtcp_func=sCreateRtpTransport;
244         mTransportFactories.video_rtcp_func_data=this;
245         mTransportFactories.video_rtp_func=sCreateRtpTransport;
246         mTransportFactories.video_rtp_func_data=this;
247 }
248
249 TunnelManager::~TunnelManager(){
250         stopClient();
251 }
252
253 void TunnelManager::stopClient(){
254         eXosip_transport_hook_register(NULL);
255         if (mSipSocket != NULL){
256                 sMutex.lock();
257                 mTunnelClient->closeSocket(mSipSocket);
258                 mSipSocket = NULL;
259                 sMutex.unlock();
260         }
261         if (mTunnelClient){
262                 delete mTunnelClient;
263                 mTunnelClient=NULL;
264         }
265 }
266
267 void TunnelManager::processTunnelEvent(){
268         LinphoneProxyConfig* lProxy;
269         linphone_core_get_default_proxy(mCore, &lProxy);
270
271         if (mEnabled && mTunnelClient->isReady()){
272                 ms_message("Tunnel is up, registering now");            
273                 linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
274                 eXosip_transport_hook_register(&mExosipTransport);
275                 //force transport to udp
276                 LCSipTransports lTransport;
277                 
278                 lTransport.udp_port=15060;
279                 lTransport.tcp_port=0;
280                 lTransport.tls_port=0;
281                 lTransport.dtls_port=0;
282                 
283                 linphone_core_set_sip_transports(mCore, &lTransport);           
284                 //register
285                 if (lProxy) {
286                         linphone_proxy_config_done(lProxy);
287                 }
288         }else if (mEnabled && !mTunnelClient->isReady()){
289                 /* we got disconnected from the tunnel */
290                 if (lProxy && linphone_proxy_config_is_registered(lProxy)) {
291                         /*forces de-registration so that we register again when the tunnel is up*/
292                         linphone_proxy_config_edit(lProxy);
293                         linphone_core_iterate(mCore);
294                 }
295         }
296 }
297
298 void TunnelManager::enable(bool isEnable) {
299         ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
300         if (isEnable && !mEnabled){
301                 mEnabled=true;
302                 //1 save transport 
303                 linphone_core_get_sip_transports(mCore, &mRegularTransport);
304                 //2 unregister
305                 LinphoneProxyConfig* lProxy;
306                 linphone_core_get_default_proxy(mCore, &lProxy);
307                 if (lProxy) {
308                         linphone_proxy_config_edit(lProxy);
309                         //make sure unregister is sent
310                         linphone_core_iterate(mCore); 
311                 }
312                 //3 insert tunnel
313                 start();
314         }else if (!isEnable && mEnabled){
315                 mEnabled=false;
316                 stopClient();
317                 //1 unregister
318                 LinphoneProxyConfig* lProxy;
319                 linphone_core_get_default_proxy(mCore, &lProxy);
320                 if (lProxy) {
321                         linphone_proxy_config_edit(lProxy);
322                         //make sure unregister is sent
323                         linphone_core_iterate(mCore); 
324                 }
325                 
326                 //make sure unregister is sent
327                 linphone_core_iterate(mCore); 
328                 
329                 linphone_core_set_rtp_transport_factories(mCore,NULL);
330
331                 eXosip_transport_hook_register(NULL);
332                 //Restore transport
333                 linphone_core_set_sip_transports(mCore, &mRegularTransport);
334                 //register
335                 if (lProxy) {
336                         linphone_proxy_config_done(lProxy);
337                 }
338
339         }
340 }
341
342 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
343         zis->mStateChanged=true;
344 }
345
346 /*invoked from linphone_core_iterate() */
347 void TunnelManager::sOnIterate(TunnelManager *zis){
348         if (zis->mStateChanged){
349                 zis->mStateChanged=false;
350                 zis->processTunnelEvent();
351         }
352 }
353
354 #ifdef ANDROID
355 static void linphone_android_log_handler(int lev, const char *fmt, va_list args){
356         int prio;
357         switch(lev){
358         case TUNNEL_DEBUG:      prio = ANDROID_LOG_DEBUG;       break;
359         case TUNNEL_INFO:       prio = ANDROID_LOG_INFO;        break;
360         case TUNNEL_NOTICE:     prio = ANDROID_LOG_INFO;        break;
361         case TUNNEL_WARN:       prio = ANDROID_LOG_WARN;        break;
362         case TUNNEL_ERROR:      prio = ANDROID_LOG_ERROR;       break;
363         default:                        prio = ANDROID_LOG_DEFAULT;     break;
364         }
365         __android_log_vprint(prio, LOG_DOMAIN, fmt, args);
366 }
367 #endif /*ANDROID*/
368
369 void TunnelManager::enableLogs(bool value) {
370         enableLogs(value,NULL);
371 }
372
373 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
374         if (logHandler != NULL) SetLogHandler(logHandler);
375 #ifdef ANDROID
376         else SetLogHandler(linphone_android_log_handler);
377 #else
378         else SetLogHandler(default_log_handler);
379 #endif
380
381         if (isEnabled) {
382                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
383         } else {
384                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
385         }
386 }
387         
388
389 bool TunnelManager::isEnabled() {
390         return mEnabled;
391 }
392 void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
393         TunnelManager* thiz = (TunnelManager*)data;
394         if (isUdpAvailable) {
395                 LOGI("Tunnel is not required, disabling");
396                 thiz->enable(false);
397                 thiz->mAutoDetectStarted = false;
398         } else {
399                 if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
400                         //1 enable tunnable but also try backup server
401                         LOGI("Tunnel is required, enabling; Trying backup udp mirror");
402                         
403                         UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
404                         lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
405                 } else {
406                         LOGI("Tunnel is required, enabling; no backup udp mirror available");
407                         thiz->mAutoDetectStarted = false;
408                 }
409                 thiz->enable(true);
410         }
411         return;
412 }
413
414 void TunnelManager::autoDetect() {
415         // first check if udp mirrors was provisionned
416         if (mUdpMirrorClients.empty()) {
417                 LOGE("No UDP mirror server configured aborting auto detection");
418                 return;
419         }
420         if (mAutoDetectStarted) {
421                 LOGE("auto detection already in progress, restarting");
422                 (*mCurrentUdpMirrorClient).stop();
423         }
424         mAutoDetectStarted=true;
425         mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
426         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
427         lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
428         
429 }
430
431 void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
432         mHttpUserName=username?username:"";
433         mHttpPasswd=passwd?passwd:"";
434         if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd);
435 }
436
437 LinphoneCore *TunnelManager::getLinphoneCore(){
438         return mCore;
439 }