linphone_tunnel.cc 11.6 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"

32
LinphoneTunnel* linphone_core_get_tunnel(const LinphoneCore *lc){
33 34 35
	return lc->tunnel;
}

36 37 38 39 40
struct _LinphoneTunnel {
	belledonnecomm::TunnelManager *manager;
	MSList *config_list;
};

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

47
belledonnecomm::TunnelManager *bcTunnel(const LinphoneTunnel *tunnel){
48
	return tunnel->manager;
Guillaume Beraudo's avatar
Guillaume Beraudo committed
49 50
}

51
static inline _LpConfig *config(const LinphoneTunnel *tunnel){
52
	return tunnel->manager->getLinphoneCore()->config;
53 54
}

55
void linphone_tunnel_destroy(LinphoneTunnel *tunnel){
56
	delete tunnel->manager;
57 58 59

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

60
	ms_free(tunnel);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
61 62
}

63 64
static char *linphone_tunnel_config_to_string(const LinphoneTunnelConfig *tunnel_config) {
	char *str = NULL;
65 66 67 68 69 70 71 72 73 74 75 76 77
	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));
		}
78 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
	}
	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);
105
			break;
106 107 108 109
		default:
			// Abort
			pos = 0;
			break;
110

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
		}
		++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);
	}
126
	ms_free(dstr);
127
	return tunnel_config;
Guillaume Beraudo's avatar
Guillaume Beraudo committed
128 129
}

130

131
static void linphone_tunnel_save_config(const LinphoneTunnel *tunnel) {
132
	MSList *elem = NULL;
133
	char *tmp = NULL, *old_tmp = NULL, *tc_str = NULL;
134
	for(elem = tunnel->config_list; elem != NULL; elem = elem->next) {
135 136
		LinphoneTunnelConfig *tunnel_config = (LinphoneTunnelConfig *)elem->data;
		tc_str = linphone_tunnel_config_to_string(tunnel_config);
137 138 139 140 141 142 143 144 145
		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;
			}
146 147 148 149 150 151 152 153 154 155
		}
	}
	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) {
156
	if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) == -1) {
157
		bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config),
158
			linphone_tunnel_config_get_port(tunnel_config));
159
	} else {
160 161 162
		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),
163
			linphone_tunnel_config_get_delay(tunnel_config));
164
	}
165
	tunnel->config_list = ms_list_append(tunnel->config_list, linphone_tunnel_config_ref(tunnel_config));
Guillaume Beraudo's avatar
Guillaume Beraudo committed
166 167
}

168 169 170

static void linphone_tunnel_load_config(LinphoneTunnel *tunnel){
	const char * confaddress = lp_config_get_string(config(tunnel), "tunnel", "server_addresses", NULL);
171
	char *tmp;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
	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);
	}
192 193
}

194 195 196 197 198 199 200 201 202
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;
	}
203 204
}

205 206 207
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
208 209
}

210 211 212 213
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);
214
		linphone_tunnel_config_unref(tunnel_config);
215 216
		linphone_tunnel_refresh_config(tunnel);
		linphone_tunnel_save_config(tunnel);
217
	}
218 219
}

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

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

227
	/* Free the list */
228 229 230
	ms_list_free_with_data(tunnel->config_list, (void (*)(void *))linphone_tunnel_config_destroy);
	tunnel->config_list = NULL;

231
	linphone_tunnel_save_config(tunnel);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
232 233
}

234
void linphone_tunnel_set_mode(LinphoneTunnel *tunnel, LinphoneTunnelMode mode){
235
	lp_config_set_string(config(tunnel),"tunnel","mode", linphone_tunnel_mode_to_string(mode));
236
	bcTunnel(tunnel)->setMode(mode);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
237 238
}

239 240
LinphoneTunnelMode linphone_tunnel_get_mode(const LinphoneTunnel *tunnel){
	return bcTunnel(tunnel)->getMode();
Guillaume Beraudo's avatar
Guillaume Beraudo committed
241 242
}

243
bool_t linphone_tunnel_connected(const LinphoneTunnel *tunnel){
244
	return bcTunnel(tunnel)->isConnected();
245 246
}

247 248 249 250
bool_t linphone_tunnel_get_activated(const LinphoneTunnel *tunnel){
	return bcTunnel(tunnel)->isActivated();
}

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 292 293
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
294 295
}

296 297 298
void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){
	tunnelOrtpLogHandler=logHandler;
	bcTunnel(tunnel)->enableLogs(enabled, tunnelLogHandler);
299 300
}

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

305 306
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);
307 308 309 310 311 312 313 314 315 316 317
	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);
318 319
}

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

324
void linphone_tunnel_enable_sip(LinphoneTunnel *tunnel, bool_t enable) {
325
	bcTunnel(tunnel)->tunnelizeSipPackets(enable);
326
	lp_config_set_int(config(tunnel), "tunnel", "sip", (enable ? TRUE : FALSE));
327 328
}

329
bool_t linphone_tunnel_sip_enabled(const LinphoneTunnel *tunnel) {
330 331 332
	return bcTunnel(tunnel)->tunnelizeSipPacketsEnabled() ? TRUE : FALSE;
}

333 334 335 336
static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){
	ortp_logv(level,fmt,args);
}

337

338
/**
339 340
 * Startup tunnel using configuration.
 * Called internally from linphonecore at startup.
341
 */
342
void linphone_tunnel_configure(LinphoneTunnel *tunnel){
343
	LinphoneTunnelMode mode = linphone_tunnel_mode_from_string(lp_config_get_string(config(tunnel), "tunnel", "mode", NULL));
344
	bool_t tunnelizeSIPPackets = (bool_t)lp_config_get_int(config(tunnel), "tunnel", "sip", TRUE);
345
	linphone_tunnel_enable_logs_with_handler(tunnel,TRUE,my_ortp_logv);
346
	linphone_tunnel_load_config(tunnel);
347
	linphone_tunnel_enable_sip(tunnel, tunnelizeSIPPackets);
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
	linphone_tunnel_set_mode(tunnel, mode);
}

/* Deprecated functions */
void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled) {
	if(enabled) linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeEnable);
	else linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeDisable);
}

bool_t linphone_tunnel_enabled(const LinphoneTunnel *tunnel) {
	return linphone_tunnel_get_mode(tunnel) == LinphoneTunnelModeEnable;
}

void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel) {
	linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeAuto);
}

bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) {
	return linphone_tunnel_get_mode(tunnel) == LinphoneTunnelModeAuto;
367
}