linphone_tunnel.cc 10.5 KB
Newer Older
Guillaume Beraudo's avatar
Guillaume Beraudo committed
1
/***************************************************************************
jehan's avatar
jehan committed
2
 *            linphone_tunnel.cc
Guillaume Beraudo's avatar
Guillaume Beraudo committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 *  Fri Dec 9, 2011
 *  Copyright  2011  Belledonne Communications
 *  Author: Guillaume Beraudo
 *  Email: guillaume dot beraudo at linphone dot org
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "TunnelManager.hh"
27
#include "linphone_tunnel.h"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
28 29 30 31
#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"

Simon Morlat's avatar
Simon Morlat committed
32 33 34 35
LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){
	return lc->tunnel;
}

Yann Diorcet's avatar
Yann Diorcet committed
36 37 38
struct _LinphoneTunnel {
	belledonnecomm::TunnelManager *manager;
	MSList *config_list;
39
	bool_t auto_detect_enabled;
Yann Diorcet's avatar
Yann Diorcet committed
40 41
};

42
extern "C" LinphoneTunnel* linphone_core_tunnel_new(LinphoneCore *lc){
Yann Diorcet's avatar
Yann Diorcet committed
43 44
	LinphoneTunnel* tunnel = ms_new0(LinphoneTunnel, 1);
	tunnel->manager = new belledonnecomm::TunnelManager(lc);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
45 46 47
	return tunnel;
}

48
static inline belledonnecomm::TunnelManager *bcTunnel(LinphoneTunnel *tunnel){
Yann Diorcet's avatar
Yann Diorcet committed
49
	return tunnel->manager;
Guillaume Beraudo's avatar
Guillaume Beraudo committed
50 51
}

Simon Morlat's avatar
Simon Morlat committed
52
static inline _LpConfig *config(LinphoneTunnel *tunnel){
Yann Diorcet's avatar
Yann Diorcet committed
53
	return tunnel->manager->getLinphoneCore()->config;
Simon Morlat's avatar
Simon Morlat committed
54 55
}

56
void linphone_tunnel_destroy(LinphoneTunnel *tunnel){
Yann Diorcet's avatar
Yann Diorcet committed
57
	delete tunnel->manager;
58 59 60

	ms_list_free_with_data(tunnel->config_list, (void (*)(void *))linphone_tunnel_config_destroy);

Yann Diorcet's avatar
Yann Diorcet committed
61
	ms_free(tunnel);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
62 63
}

Yann Diorcet's avatar
Yann Diorcet committed
64 65
static char *linphone_tunnel_config_to_string(const LinphoneTunnelConfig *tunnel_config) {
	char *str = NULL;
66 67 68 69 70 71 72 73 74 75 76 77 78
	const char *host = linphone_tunnel_config_get_host(tunnel_config);
	if(host != NULL) {
		if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) != -1) {
			str = ms_strdup_printf("%s:%d:%d:%d",
								   linphone_tunnel_config_get_host(tunnel_config),
								   linphone_tunnel_config_get_port(tunnel_config),
								   linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config),
								   linphone_tunnel_config_get_delay(tunnel_config));
		} else {
			str = ms_strdup_printf("%s:%d",
								   linphone_tunnel_config_get_host(tunnel_config),
								   linphone_tunnel_config_get_port(tunnel_config));
		}
Yann Diorcet's avatar
Yann Diorcet committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
	}
	return str;
}

static LinphoneTunnelConfig *linphone_tunnel_config_from_string(const char *str) {
	LinphoneTunnelConfig *tunnel_config = NULL;
	char * dstr = ms_strdup(str);
	const char *host = NULL;
	int port = -1;
	int remote_udp_mirror_port = -1;
	int delay = -1;
	int pos = 0;
	char *pch;
	pch = strtok(dstr, ":");
	while(pch != NULL) {
		switch(pos) {
		case 0:
			host = pch;
			break;
		case 1:
			port = atoi(pch);
			break;
		case 2:
			remote_udp_mirror_port = atoi(pch);
			break;
		case 3:
			delay = atoi(pch);
106
			break;
Yann Diorcet's avatar
Yann Diorcet committed
107 108 109 110
		default:
			// Abort
			pos = 0;
			break;
111

Yann Diorcet's avatar
Yann Diorcet committed
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
		}
		++pos;
		pch = strtok(NULL, ":");
	}
	if(pos >= 2) {
		tunnel_config = linphone_tunnel_config_new();
		linphone_tunnel_config_set_host(tunnel_config, host);
		linphone_tunnel_config_set_port(tunnel_config, port);
	}
	if(pos >= 3) {
		linphone_tunnel_config_set_remote_udp_mirror_port(tunnel_config, remote_udp_mirror_port);
	}
	if(pos == 4) {
		linphone_tunnel_config_set_delay(tunnel_config, delay);
	}
127
	ms_free(dstr);
Yann Diorcet's avatar
Yann Diorcet committed
128
	return tunnel_config;
Guillaume Beraudo's avatar
Guillaume Beraudo committed
129 130
}

Yann Diorcet's avatar
Yann Diorcet committed
131 132

static void linphone_tunnel_save_config(LinphoneTunnel *tunnel) {
133
	MSList *elem = NULL;
Yann Diorcet's avatar
Yann Diorcet committed
134
	char *tmp = NULL, *old_tmp = NULL, *tc_str = NULL;
135
	for(elem = tunnel->config_list; elem != NULL; elem = elem->next) {
Yann Diorcet's avatar
Yann Diorcet committed
136 137
		LinphoneTunnelConfig *tunnel_config = (LinphoneTunnelConfig *)elem->data;
		tc_str = linphone_tunnel_config_to_string(tunnel_config);
138 139 140 141 142 143 144 145 146
		if(tc_str != NULL) {
			if(tmp != NULL) {
				old_tmp = tmp;
				tmp = ms_strdup_printf("%s %s", old_tmp, tc_str);
				ms_free(old_tmp);
				ms_free(tc_str);
			} else {
				tmp = tc_str;
			}
Yann Diorcet's avatar
Yann Diorcet committed
147 148 149 150 151 152 153 154 155 156
		}
	}
	lp_config_set_string(config(tunnel), "tunnel", "server_addresses", tmp);
	if(tmp != NULL) {
		ms_free(tmp);
	}
}


static void linphone_tunnel_add_server_intern(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config) {
157
	if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) == -1) {
158
		bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config),
159
			linphone_tunnel_config_get_port(tunnel_config));
Yann Diorcet's avatar
Yann Diorcet committed
160
	} else {
161 162 163
		bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config),
			linphone_tunnel_config_get_port(tunnel_config),
			linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config),
164
			linphone_tunnel_config_get_delay(tunnel_config));
Yann Diorcet's avatar
Yann Diorcet committed
165 166
	}
	tunnel->config_list = ms_list_append(tunnel->config_list, tunnel_config);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
167 168
}

Yann Diorcet's avatar
Yann Diorcet committed
169 170 171

static void linphone_tunnel_load_config(LinphoneTunnel *tunnel){
	const char * confaddress = lp_config_get_string(config(tunnel), "tunnel", "server_addresses", NULL);
Simon Morlat's avatar
Simon Morlat committed
172
	char *tmp;
Yann Diorcet's avatar
Yann Diorcet committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	const char *it;
	LinphoneTunnelConfig *tunnel_config;
	int adv;
	if(confaddress != NULL) {
		tmp = ms_strdup(confaddress);
		it = confaddress;
		while(confaddress[0] != '\0') {
			int ret = sscanf(it,"%s%n", tmp, &adv);
			if (ret >= 1){
				it += adv;
				tunnel_config = linphone_tunnel_config_from_string(tmp);
				if(tunnel_config != NULL) {
					linphone_tunnel_add_server_intern(tunnel, tunnel_config);
				} else {
					ms_error("Tunnel server address incorrectly specified from config file: %s", tmp);
				}
			} else break;
		}
		ms_free(tmp);
	}
Simon Morlat's avatar
Simon Morlat committed
193 194
}

Yann Diorcet's avatar
Yann Diorcet committed
195 196 197 198 199 200 201 202 203
static void linphone_tunnel_refresh_config(LinphoneTunnel *tunnel) {
	MSList *old_list = tunnel->config_list;
	tunnel->config_list = NULL;
	bcTunnel(tunnel)->cleanServers();
	while(old_list != NULL) {
		LinphoneTunnelConfig *tunnel_config = (LinphoneTunnelConfig *)old_list->data;
		linphone_tunnel_add_server_intern(tunnel, tunnel_config);
		old_list = old_list->next;
	}
Simon Morlat's avatar
Simon Morlat committed
204 205
}

Yann Diorcet's avatar
Yann Diorcet committed
206 207 208
void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config) {
	linphone_tunnel_add_server_intern(tunnel, tunnel_config);
	linphone_tunnel_save_config(tunnel);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
209 210
}

Yann Diorcet's avatar
Yann Diorcet committed
211 212 213 214
void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config) {
	MSList *elem = ms_list_find(tunnel->config_list, tunnel_config);
	if(elem != NULL) {
		tunnel->config_list = ms_list_remove(tunnel->config_list, tunnel_config);
215
		linphone_tunnel_config_destroy(tunnel_config);
Yann Diorcet's avatar
Yann Diorcet committed
216 217
		linphone_tunnel_refresh_config(tunnel);
		linphone_tunnel_save_config(tunnel);
218
	}
Simon Morlat's avatar
Simon Morlat committed
219 220
}

Yann Diorcet's avatar
Yann Diorcet committed
221 222
const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){
	return tunnel->config_list;
Guillaume Beraudo's avatar
Guillaume Beraudo committed
223 224
}

225
void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){
Guillaume Beraudo's avatar
Guillaume Beraudo committed
226
	bcTunnel(tunnel)->cleanServers();
227

Yann Diorcet's avatar
Yann Diorcet committed
228
	/* Free the list */
229 230 231
	ms_list_free_with_data(tunnel->config_list, (void (*)(void *))linphone_tunnel_config_destroy);
	tunnel->config_list = NULL;

Yann Diorcet's avatar
Yann Diorcet committed
232
	linphone_tunnel_save_config(tunnel);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
233 234
}

235
void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){
236
	tunnel->auto_detect_enabled = FALSE;
Simon Morlat's avatar
Simon Morlat committed
237
	lp_config_set_int(config(tunnel),"tunnel","enabled",(int)enabled);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
238 239 240
	bcTunnel(tunnel)->enable(enabled);
}

241
bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){
Guillaume Beraudo's avatar
Guillaume Beraudo committed
242 243 244
	return bcTunnel(tunnel)->isEnabled();
}

245 246 247 248
bool_t linphone_tunnel_connected(LinphoneTunnel *tunnel){
	return bcTunnel(tunnel)->isReady();
}

Simon Morlat's avatar
Simon Morlat committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
static OrtpLogFunc tunnelOrtpLogHandler=NULL;

/*
#define TUNNEL_DEBUG (1)
#define TUNNEL_INFO  (1<<1)
#define TUNNEL_NOTICE (1<<2)
#define TUNNEL_WARN  (1<<3)
#define TUNNEL_ERROR (1<<4)
#define TUNNEL_ALERT (1<<5)
#define TUNNEL_FATAL (1<<6)
*/

static void tunnelLogHandler(int level, const char *fmt, va_list l){
	if (tunnelOrtpLogHandler){
		OrtpLogLevel ortp_level=ORTP_DEBUG;
		switch(level){
			case TUNNEL_DEBUG:
				ortp_level=ORTP_DEBUG;
			break;
			case TUNNEL_INFO:
				ortp_level=ORTP_MESSAGE;
			break;
			case TUNNEL_NOTICE:
				ortp_level=ORTP_MESSAGE;
			break;
			case TUNNEL_WARN:
				ortp_level=ORTP_WARNING;
			break;
			case TUNNEL_ERROR:
				ortp_level=ORTP_ERROR;
			break;
			case TUNNEL_ALERT:
				ortp_level=ORTP_ERROR;
			break;
			case TUNNEL_FATAL:
				ortp_level=ORTP_FATAL;
			break;
			default:
				ms_fatal("Unexepcted tunnel log %i: %s",level,fmt);
			break;
		}
		tunnelOrtpLogHandler(ortp_level,fmt,l);
	}
Guillaume Beraudo's avatar
Guillaume Beraudo committed
292 293
}

Simon Morlat's avatar
Simon Morlat committed
294 295 296
void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){
	tunnelOrtpLogHandler=logHandler;
	bcTunnel(tunnel)->enableLogs(enabled, tunnelLogHandler);
297 298
}

299
void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char* username,const char* passwd){
300 301 302
	bcTunnel(tunnel)->setHttpProxyAuthInfo(username, passwd);
}

Simon Morlat's avatar
Simon Morlat committed
303 304
void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){
	bcTunnel(tunnel)->setHttpProxy(host, port, username, passwd);
305 306 307 308 309 310 311 312 313 314 315
	lp_config_set_string(config(tunnel),"tunnel","http_proxy_host",host);
	lp_config_set_int(config(tunnel),"tunnel","http_proxy_port",port);
	lp_config_set_string(config(tunnel),"tunnel","http_proxy_username",username);
	lp_config_set_string(config(tunnel),"tunnel","http_proxy_password",passwd);
}

void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd){
	if (host) *host=lp_config_get_string(config(tunnel),"tunnel","http_proxy_host",NULL);
	if (port) *port=lp_config_get_int(config(tunnel),"tunnel","http_proxy_port",0);
	if (username) *username=lp_config_get_string(config(tunnel),"tunnel","http_proxy_username",NULL);
	if (passwd) *passwd=lp_config_get_string(config(tunnel),"tunnel","http_proxy_password",NULL);
Simon Morlat's avatar
Simon Morlat committed
316 317
}

318
void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){
319 320 321
	bcTunnel(tunnel)->reconnect();
}

322
void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){
323
	tunnel->auto_detect_enabled = TRUE;
Guillaume Beraudo's avatar
Guillaume Beraudo committed
324 325 326
	bcTunnel(tunnel)->autoDetect();
}

327 328 329 330
bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) {
	return tunnel->auto_detect_enabled;
}

Simon Morlat's avatar
Simon Morlat committed
331 332 333 334
static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){
	ortp_logv(level,fmt,args);
}

335
/**
Simon Morlat's avatar
Simon Morlat committed
336 337
 * Startup tunnel using configuration.
 * Called internally from linphonecore at startup.
338
 */
Simon Morlat's avatar
Simon Morlat committed
339 340 341
void linphone_tunnel_configure(LinphoneTunnel *tunnel){
	bool_t enabled=(bool_t)lp_config_get_int(config(tunnel),"tunnel","enabled",FALSE);
	linphone_tunnel_enable_logs_with_handler(tunnel,TRUE,my_ortp_logv);
Yann Diorcet's avatar
Yann Diorcet committed
342
	linphone_tunnel_load_config(tunnel);
343 344 345
	linphone_tunnel_enable(tunnel, enabled);
}