2 * C Implementation: tunnel
7 * Author: Simon Morlat <simon.morlat@linphone.org>, (C) 2009
9 * Copyright (C) 2010 Belledonne Comunications, Grenoble, France
14 #include "TunnelManager.hh"
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"
23 #include <android/log.h>
36 using namespace belledonnecomm;
38 Mutex TunnelManager::sMutex;
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;
44 if (lTunnelMgr->mSipSocket==NULL){
46 return len;//let ignore the error
48 err=lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
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;
57 if (lTunnelMgr->mSipSocket==NULL){
59 return 0;//let ignore the error
61 err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen);
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*/
72 int udp_fd=eXosip_get_udp_socket();
76 Find the udp fd and the control fd
78 for(i=0;i<max_fds;++i){
79 if (FD_ISSET(i,s1) && i!=udp_fd){
85 ms_error("Could not find control fd !");
89 gettimeofday(&begin,NULL);
96 if (lTunnelMgr->mSipSocket!=NULL){
97 if (lTunnelMgr->mSipSocket->hasData()) {
99 /* we make exosip believe that it has udp data to read*/
105 gettimeofday(&cur,NULL);
106 if (cur.tv_sec-begin.tv_sec>tv->tv_sec) {
107 FD_SET(controlfd,s1);
112 FD_SET(controlfd,s1);
113 if (select(max_fds,s1,s2,s3,&abit)==1) {
119 /*select called from other places, only the control fd is present */
120 return select(max_fds,s1,s2,s3,tv);
125 void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
127 mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
130 void TunnelManager::addServer(const char *ip, int port) {
131 mServerAddrs.push_back(ServerAddr(ip,port));
132 if (mTunnelClient) mTunnelClient->addServer(ip,port);
135 void TunnelManager::cleanServers() {
136 mServerAddrs.clear();
138 UdpMirrorClientList::iterator it;
139 mAutoDetectStarted=false;
140 for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
141 UdpMirrorClient& s=*it++;
144 mUdpMirrorClients.clear();
145 if (mTunnelClient) mTunnelClient->cleanServers();
148 void TunnelManager::reconnect(){
150 mTunnelClient->reconnect();
153 void TunnelManager::setCallback(StateCallback cb, void *userdata) {
155 mCallbackData=userdata;
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);
163 void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){
164 mTunnelClient->closeSocket(s);
168 static RtpTransport *sCreateRtpTransport(void* userData, int port){
169 return ((TunnelManager::TunnelManager *) userData)->createRtpTransport(port);
172 RtpTransport *TunnelManager::createRtpTransport(int port){
173 TunnelSocket *socket=mTunnelClient->createSocket(port);
174 socket->setUserPointer(this);
175 RtpTransport *t=ms_new0(RtpTransport,1);
177 t->t_recvfrom=customRecvfrom;
178 t->t_sendto=customSendto;
179 t->t_close=sCloseRtpTransport;
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);
194 mTunnelClient->start();
196 if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
199 bool TunnelManager::isStarted() {
200 return mTunnelClient != 0 && mTunnelClient->isStarted();
203 bool TunnelManager::isReady() const {
204 return mTunnelClient && mTunnelClient->isReady();
207 int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
211 ((TunnelSocket*)t->data)->sendto(msg->b_rptr,size,to,tolen);
215 int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
216 int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen);
217 if (err>0) return err;
222 TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
228 ,mAutoDetectStarted(false) {
230 mExosipTransport.data=this;
231 mExosipTransport.recvfrom=eXosipRecvfrom;
232 mExosipTransport.sendto=eXosipSendto;
233 mExosipTransport.select=eXosipSelect;
235 linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
236 mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
237 mTransportFactories.audio_rtcp_func_data=this;
238 mTransportFactories.audio_rtp_func=sCreateRtpTransport;
239 mTransportFactories.audio_rtp_func_data=this;
240 mTransportFactories.video_rtcp_func=sCreateRtpTransport;
241 mTransportFactories.video_rtcp_func_data=this;
242 mTransportFactories.video_rtp_func=sCreateRtpTransport;
243 mTransportFactories.video_rtp_func_data=this;
246 TunnelManager::~TunnelManager(){
250 void TunnelManager::stopClient(){
251 eXosip_transport_hook_register(NULL);
252 if (mSipSocket != NULL){
254 mTunnelClient->closeSocket(mSipSocket);
259 delete mTunnelClient;
264 void TunnelManager::processTunnelEvent(){
265 LinphoneProxyConfig* lProxy;
266 linphone_core_get_default_proxy(mCore, &lProxy);
268 if (mEnabled && mTunnelClient->isReady()){
269 ms_message("Tunnel is up, registering now");
270 linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
271 eXosip_transport_hook_register(&mExosipTransport);
272 //force transport to udp
273 LCSipTransports lTransport;
275 lTransport.udp_port=15060;
276 lTransport.tcp_port=0;
277 lTransport.tls_port=0;
278 lTransport.dtls_port=0;
280 linphone_core_set_sip_transports(mCore, &lTransport);
283 linphone_proxy_config_done(lProxy);
285 }else if (mEnabled && !mTunnelClient->isReady()){
286 /* we got disconnected from the tunnel */
287 if (lProxy && linphone_proxy_config_is_registered(lProxy)) {
288 /*forces de-registration so that we register again when the tunnel is up*/
289 linphone_proxy_config_edit(lProxy);
290 linphone_core_iterate(mCore);
295 void TunnelManager::enable(bool isEnable) {
296 ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
297 if (isEnable && !mEnabled){
300 linphone_core_get_sip_transports(mCore, &mRegularTransport);
302 LinphoneProxyConfig* lProxy;
303 linphone_core_get_default_proxy(mCore, &lProxy);
305 linphone_proxy_config_edit(lProxy);
306 //make sure unregister is sent
307 linphone_core_iterate(mCore);
311 }else if (!isEnable && mEnabled){
315 LinphoneProxyConfig* lProxy;
316 linphone_core_get_default_proxy(mCore, &lProxy);
318 linphone_proxy_config_edit(lProxy);
319 //make sure unregister is sent
320 linphone_core_iterate(mCore);
323 //make sure unregister is sent
324 linphone_core_iterate(mCore);
326 linphone_core_set_rtp_transport_factories(mCore,NULL);
328 eXosip_transport_hook_register(NULL);
330 linphone_core_set_sip_transports(mCore, &mRegularTransport);
333 linphone_proxy_config_done(lProxy);
339 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
340 zis->mStateChanged=true;
343 /*invoked from linphone_core_iterate() */
344 void TunnelManager::sOnIterate(TunnelManager *zis){
345 if (zis->mStateChanged){
346 zis->mStateChanged=false;
347 zis->processTunnelEvent();
352 static void linphone_android_log_handler(int lev, const char *fmt, va_list args){
355 case TUNNEL_DEBUG: prio = ANDROID_LOG_DEBUG; break;
356 case TUNNEL_INFO: prio = ANDROID_LOG_INFO; break;
357 case TUNNEL_NOTICE: prio = ANDROID_LOG_INFO; break;
358 case TUNNEL_WARN: prio = ANDROID_LOG_WARN; break;
359 case TUNNEL_ERROR: prio = ANDROID_LOG_ERROR; break;
360 default: prio = ANDROID_LOG_DEFAULT; break;
362 __android_log_vprint(prio, LOG_DOMAIN, fmt, args);
366 void TunnelManager::enableLogs(bool value) {
367 enableLogs(value,NULL);
370 void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
371 if (logHandler != NULL) SetLogHandler(logHandler);
373 else SetLogHandler(linphone_android_log_handler);
375 else SetLogHandler(default_log_handler);
379 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN|TUNNEL_INFO);
381 SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN);
386 bool TunnelManager::isEnabled() {
389 void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
390 TunnelManager* thiz = (TunnelManager*)data;
391 if (isUdpAvailable) {
392 LOGI("Tunnel is not required, disabling");
394 thiz->mAutoDetectStarted = false;
396 if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
397 //1 enable tunnable but also try backup server
398 LOGI("Tunnel is required, enabling; Trying backup udp mirror");
400 UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
401 lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
403 LOGI("Tunnel is required, enabling; no backup udp mirror available");
404 thiz->mAutoDetectStarted = false;
411 void TunnelManager::autoDetect() {
412 // first check if udp mirrors was provisionned
413 if (mUdpMirrorClients.empty()) {
414 LOGE("No UDP mirror server configured aborting auto detection");
417 if (mAutoDetectStarted) {
418 LOGE("auto detection already in progress, restarting");
419 (*mCurrentUdpMirrorClient).stop();
421 mAutoDetectStarted=true;
422 mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
423 UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
424 lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
428 void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) {
429 mTunnelClient->setHttpProxyAuthInfo(username,passwd);
432 LinphoneCore *TunnelManager::getLinphoneCore(){