]> sjero.net Git - linphone/blob - coreapi/TunnelManager.cc
ignore tunnel transmissions errors (usually when not ready) for SIP
[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 (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         mStateChanged=false;
216         linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
217         mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
218         mTransportFactories.audio_rtcp_func_data=this;
219         mTransportFactories.audio_rtp_func=sCreateRtpTransport;
220         mTransportFactories.audio_rtp_func_data=this;
221         mTransportFactories.video_rtcp_func=sCreateRtpTransport;
222         mTransportFactories.video_rtcp_func_data=this;
223         mTransportFactories.video_rtp_func=sCreateRtpTransport;
224         mTransportFactories.video_rtp_func_data=this;
225 }
226
227 TunnelManager::~TunnelManager(){
228         stopClient();
229 }
230
231 void TunnelManager::stopClient(){
232         eXosip_transport_hook_register(NULL);
233         if (mSipSocket != NULL){
234                 sMutex.lock();
235                 mTunnelClient->closeSocket(mSipSocket);
236                 mSipSocket = NULL;
237                 sMutex.unlock();
238         }
239         if (mTunnelClient){
240                 delete mTunnelClient;
241                 mTunnelClient=NULL;
242         }
243 }
244
245 void TunnelManager::processTunnelEvent(){
246         LinphoneProxyConfig* lProxy;
247         linphone_core_get_default_proxy(mCore, &lProxy);
248
249         if (mEnabled && mTunnelClient->isReady()){
250                 ms_message("Tunnel is up, registering now");            
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 
300                 linphone_core_get_sip_transports(mCore, &mRegularTransport);
301                 //2 unregister
302                 waitUnRegistration();
303                 //3 insert tunnel
304                 start();
305         }else if (!isEnable && mEnabled){
306                 //1 unregister
307                 waitUnRegistration();
308                 
309                 mEnabled=false;
310                 stopClient();
311                 
312                 linphone_core_set_rtp_transport_factories(mCore,NULL);
313
314                 eXosip_transport_hook_register(NULL);
315                 //Restore transport
316                 linphone_core_set_sip_transports(mCore, &mRegularTransport);
317                 //register
318                 LinphoneProxyConfig* lProxy;
319                 linphone_core_get_default_proxy(mCore, &lProxy);
320                 if (lProxy) {
321                         linphone_proxy_config_done(lProxy);
322                 }
323
324         }
325 }
326
327 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
328         zis->mStateChanged=true;
329 }
330
331 /*invoked from linphone_core_iterate() */
332 void TunnelManager::sOnIterate(TunnelManager *zis){
333         if (zis->mStateChanged){
334                 zis->mStateChanged=false;
335                 zis->processTunnelEvent();
336         }
337 }
338
339 #ifdef ANDROID
340 static void linphone_android_log_handler(int lev, const char *fmt, va_list args){
341         int prio;
342         switch(lev){
343         case TUNNEL_DEBUG:      prio = ANDROID_LOG_DEBUG;       break;
344         case TUNNEL_INFO:       prio = ANDROID_LOG_INFO;        break;
345         case TUNNEL_NOTICE:     prio = ANDROID_LOG_INFO;        break;
346         case TUNNEL_WARN:       prio = ANDROID_LOG_WARN;        break;
347         case TUNNEL_ERROR:      prio = ANDROID_LOG_ERROR;       break;
348         default:                        prio = ANDROID_LOG_DEFAULT;     break;
349         }
350         __android_log_vprint(prio, LOG_DOMAIN, fmt, args);
351 }
352 #endif /*ANDROID*/
353
354 void TunnelManager::enableLogs(bool value) {
355         enableLogs(value,NULL);
356 }
357
358 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
359         if (logHandler != NULL) SetLogHandler(logHandler);
360 #ifdef ANDROID
361         else SetLogHandler(linphone_android_log_handler);
362 #else
363         else SetLogHandler(default_log_handler);
364 #endif
365
366         if (isEnabled) {
367                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
368         } else {
369                 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
370         }
371 }
372         
373
374 bool TunnelManager::isEnabled() {
375         return mEnabled;
376 }
377 void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
378         TunnelManager* thiz = (TunnelManager*)data;
379         if (isUdpAvailable) {
380                 LOGI("Tunnel is not required, disabling");
381                 thiz->enable(false);
382                 thiz->mAutoDetectStarted = false;
383         } else {
384                 if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
385                         //1 enable tunnable but also try backup server
386                         LOGI("Tunnel is required, enabling; Trying backup udp mirror");
387                         
388                         UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
389                         lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
390                 } else {
391                         LOGI("Tunnel is required, enabling; no backup udp mirror available");
392                         thiz->mAutoDetectStarted = false;
393                 }
394                 thiz->enable(true);
395         }
396         return;
397 }
398
399 void TunnelManager::autoDetect() {
400         // first check if udp mirrors was provisionned
401         if (mUdpMirrorClients.empty()) {
402                 LOGE("No UDP mirror server configured aborting auto detection");
403                 return;
404         }
405         if (mAutoDetectStarted) {
406                 LOGE("auto detection already in progress, restarting");
407                 (*mCurrentUdpMirrorClient).stop();
408         }
409         mAutoDetectStarted=true;
410         mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
411         UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
412         lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
413         
414 }
415
416 void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
417         mHttpUserName=username?username:"";
418         mHttpPasswd=passwd?passwd:"";
419         if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd);
420 }
421
422 void TunnelManager::setHttpProxy(const char *host,int port, const char *username, const char *passwd){
423         mHttpUserName=username?username:"";
424         mHttpPasswd=passwd?passwd:"";
425         mHttpProxyPort=(port>0) ? port : 0;
426         mHttpProxyHost=host ? host : "";
427         if (mTunnelClient) mTunnelClient->setHttpProxy(host, port, username, passwd);
428 }
429
430 LinphoneCore *TunnelManager::getLinphoneCore(){
431         return mCore;
432 }