]> sjero.net Git - linphone/blob - coreapi/TunnelManager.cc
Wizard merged
[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                 NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket();
72                 NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd();
73
74                 FD_ZERO(s1);            
75                 gettimeofday(&begin,NULL);
76                 do{
77                         struct timeval abit;
78
79                         abit.tv_sec=0;
80                         abit.tv_usec=20000;
81                         sMutex.lock();
82                         if (lTunnelMgr->mSipSocket!=NULL){
83                                 if (lTunnelMgr->mSipSocket->hasData()) {
84                                         sMutex.unlock();
85                                         /* we make exosip believe that it has udp data to read*/
86                                         FD_SET(udp_fd,s1);
87                                         return 1;
88                                 }
89                         }
90                         sMutex.unlock();
91                         gettimeofday(&cur,NULL);
92                         if (cur.tv_sec-begin.tv_sec>tv->tv_sec) {
93                                 FD_SET(controlfd,s1);
94                                 FD_SET(udp_fd,s1);
95                                 return 0;
96                         }
97                         FD_ZERO(s1);
98                         FD_SET(controlfd,s1);
99                         if (select(max_fds,s1,s2,s3,&abit)==1) {
100                                 return 1;
101                         }
102                 }while(1);
103                 
104         }else{
105                 /*select called from other places, only the control fd is present */
106                 return select(max_fds,s1,s2,s3,tv);
107         }
108 }
109
110
111 void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
112         addServer(ip,port);
113         mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
114 }
115
116 void TunnelManager::addServer(const char *ip, int port) {
117         mServerAddrs.push_back(ServerAddr(ip,port));
118         if (mTunnelClient) mTunnelClient->addServer(ip,port);
119 }
120
121 void TunnelManager::cleanServers() {
122         mServerAddrs.clear();
123
124         UdpMirrorClientList::iterator it;
125         mAutoDetectStarted=false;
126         for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
127                 UdpMirrorClient& s=*it++;
128                 s.stop();
129         }
130         mUdpMirrorClients.clear();
131         if (mTunnelClient) mTunnelClient->cleanServers();
132 }
133
134 void TunnelManager::reconnect(){
135         if (mTunnelClient)
136                 mTunnelClient->reconnect();
137 }
138
139 void TunnelManager::setCallback(StateCallback cb, void *userdata) {
140         mCallback=cb;
141         mCallbackData=userdata;
142 }
143
144 static void sCloseRtpTransport(RtpTransport *t, void *userData){
145         TunnelSocket *s=(TunnelSocket*)userData;
146         TunnelManager *manager=(TunnelManager*)s->getUserPointer();
147         manager->closeRtpTransport(t, s);
148 }
149 void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){
150         mTunnelClient->closeSocket(s);
151         ms_free(t);
152 }
153
154 static RtpTransport *sCreateRtpTransport(void* userData, int port){
155         return ((TunnelManager *) userData)->createRtpTransport(port);
156 }
157
158 RtpTransport *TunnelManager::createRtpTransport(int port){
159         TunnelSocket *socket=mTunnelClient->createSocket(port);
160         socket->setUserPointer(this);
161         RtpTransport *t=ms_new0(RtpTransport,1);
162         t->t_getsocket=NULL;
163         t->t_recvfrom=customRecvfrom;
164         t->t_sendto=customSendto;
165         t->t_close=sCloseRtpTransport;
166         t->data=socket;
167         return t;
168 }
169
170 void TunnelManager::start() {
171         if (!mTunnelClient) {
172                 mTunnelClient = new TunnelClient();
173                 mTunnelClient->setCallback((StateCallback)tunnelCallback,this);
174                 std::list<ServerAddr>::iterator it;
175                 for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){
176                         const ServerAddr &addr=*it;
177                         mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort);
178                 }
179                 if(!mHttpUserName.empty()) {
180                         mTunnelClient->setHttpProxyAuthInfo(mHttpUserName.c_str(), mHttpPasswd.c_str());
181                 }
182         }
183         mTunnelClient->start();
184
185         if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
186 }
187
188 bool TunnelManager::isStarted() {
189         return mTunnelClient != 0 && mTunnelClient->isStarted();
190 }
191
192 bool TunnelManager::isReady() const {
193         return mTunnelClient && mTunnelClient->isReady();
194 }
195
196 int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
197         int size;
198         msgpullup(msg,-1);
199         size=msgdsize(msg);
200         ((TunnelSocket*)t->data)->sendto(msg->b_rptr,size,to,tolen);
201         return size;
202 }
203
204 int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
205         int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen);
206         if (err>0) return err;
207         return 0;
208 }
209
210
211 TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
212 ,mCore(lc)
213 ,mSipSocket(NULL)
214 ,mCallback(NULL)
215 ,mEnabled(false)
216 ,mTunnelClient(NULL)
217 ,mAutoDetectStarted(false) {
218
219         mExosipTransport.data=this;
220         mExosipTransport.recvfrom=eXosipRecvfrom;
221         mExosipTransport.sendto=eXosipSendto;
222         mExosipTransport.select=eXosipSelect;
223         mStateChanged=false;
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(){
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_rtp_transport_factories(mCore,&mTransportFactories);
260                 eXosip_transport_hook_register(&mExosipTransport);
261                 //force transport to udp
262                 LCSipTransports lTransport;
263                 
264                 lTransport.udp_port=15060;
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::enable(bool isEnable) {
285         ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
286         if (isEnable && !mEnabled){
287                 mEnabled=true;
288                 //1 save transport 
289                 linphone_core_get_sip_transports(mCore, &mRegularTransport);
290                 //2 unregister
291                 LinphoneProxyConfig* lProxy;
292                 linphone_core_get_default_proxy(mCore, &lProxy);
293                 if (lProxy) {
294                         linphone_proxy_config_edit(lProxy);
295                         //make sure unregister is sent
296                         linphone_core_iterate(mCore); 
297                 }
298                 //3 insert tunnel
299                 start();
300         }else if (!isEnable && mEnabled){
301                 mEnabled=false;
302                 stopClient();
303                 //1 unregister
304                 LinphoneProxyConfig* lProxy;
305                 linphone_core_get_default_proxy(mCore, &lProxy);
306                 if (lProxy) {
307                         linphone_proxy_config_edit(lProxy);
308                         //make sure unregister is sent
309                         linphone_core_iterate(mCore); 
310                 }
311                 
312                 //make sure unregister is sent
313                 linphone_core_iterate(mCore); 
314                 
315                 linphone_core_set_rtp_transport_factories(mCore,NULL);
316
317                 eXosip_transport_hook_register(NULL);
318                 //Restore transport
319                 linphone_core_set_sip_transports(mCore, &mRegularTransport);
320                 //register
321                 if (lProxy) {
322                         linphone_proxy_config_done(lProxy);
323                 }
324
325         }
326 }
327
328 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
329         zis->mStateChanged=true;
330 }
331
332 /*invoked from linphone_core_iterate() */
333 void TunnelManager::sOnIterate(TunnelManager *zis){
334         if (zis->mStateChanged){
335                 zis->mStateChanged=false;
336                 zis->processTunnelEvent();
337         }
338 }
339
340 #ifdef ANDROID
341 static void linphone_android_log_handler(int lev, const char *fmt, va_list args){
342         int prio;
343         switch(lev){
344         case TUNNEL_DEBUG:      prio = ANDROID_LOG_DEBUG;       break;
345         case TUNNEL_INFO:       prio = ANDROID_LOG_INFO;        break;
346         case TUNNEL_NOTICE:     prio = ANDROID_LOG_INFO;        break;
347         case TUNNEL_WARN:       prio = ANDROID_LOG_WARN;        break;
348         case TUNNEL_ERROR:      prio = ANDROID_LOG_ERROR;       break;
349         default:                        prio = ANDROID_LOG_DEFAULT;     break;
350         }
351         __android_log_vprint(prio, LOG_DOMAIN, fmt, args);
352 }
353 #endif /*ANDROID*/
354
355 void TunnelManager::enableLogs(bool value) {
356         enableLogs(value,NULL);
357 }
358
359 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
360         if (logHandler != NULL) SetLogHandler(logHandler);
361 #ifdef ANDROID
362         else SetLogHandler(linphone_android_log_handler);
363 #else
364         else SetLogHandler(default_log_handler);
365 #endif
366
367         if (isEnabled) {
368                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
369         } else {
370                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
371         }
372 }
373         
374
375 bool TunnelManager::isEnabled() {
376         return mEnabled;
377 }
378 void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
379         TunnelManager* thiz = (TunnelManager*)data;
380         if (isUdpAvailable) {
381                 LOGI("Tunnel is not required, disabling");
382                 thiz->enable(false);
383                 thiz->mAutoDetectStarted = false;
384         } else {
385                 if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
386                         //1 enable tunnable but also try backup server
387                         LOGI("Tunnel is required, enabling; Trying backup udp mirror");
388                         
389                         UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
390                         lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
391                 } else {
392                         LOGI("Tunnel is required, enabling; no backup udp mirror available");
393                         thiz->mAutoDetectStarted = false;
394                 }
395                 thiz->enable(true);
396         }
397         return;
398 }
399
400 void TunnelManager::autoDetect() {
401         // first check if udp mirrors was provisionned
402         if (mUdpMirrorClients.empty()) {
403                 LOGE("No UDP mirror server configured aborting auto detection");
404                 return;
405         }
406         if (mAutoDetectStarted) {
407                 LOGE("auto detection already in progress, restarting");
408                 (*mCurrentUdpMirrorClient).stop();
409         }
410         mAutoDetectStarted=true;
411         mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
412         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
413         lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
414         
415 }
416
417 void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
418         mHttpUserName=username?username:"";
419         mHttpPasswd=passwd?passwd:"";
420         if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd);
421 }
422
423 LinphoneCore *TunnelManager::getLinphoneCore(){
424         return mCore;
425 }