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