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