tunnel_tester.c 13.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
	liblinphone_tester - liblinphone test suite
	Copyright (C) 2013  Belledonne Communications SARL

	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, see <http://www.gnu.org/licenses/>.
*/

#include <sys/types.h>
#include <sys/stat.h>
21 22
#include "linphone/core.h"
#include "linphone/lpconfig.h"
23
#include "liblinphone_tester.h"
Benjamin REIS's avatar
Benjamin REIS committed
24
#include "tester_utils.h"
25

26
/* Retrieve the public IP from a given hostname */
jehan's avatar
jehan committed
27
int get_ip_from_hostname(const char * tunnel_hostname, char *ip, size_t ip_size){
28
	struct addrinfo hints;
jehan's avatar
jehan committed
29
	struct addrinfo *res = NULL;
30 31 32 33 34 35
	int err;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	if ((err = getaddrinfo(tunnel_hostname, NULL, &hints, &res))){
		ms_error("error while retrieving IP from %s: %s", tunnel_hostname, gai_strerror(err));
jehan's avatar
jehan committed
36
		return err;
37 38
	}

jehan's avatar
jehan committed
39
	bctbx_addrinfo_to_ip_address(res, ip, ip_size, NULL);
40
	freeaddrinfo(res);
jehan's avatar
jehan committed
41
	return err;
42
}
43
static char* get_public_contact_ip(LinphoneCore* lc)  {
44
	const LinphoneAddress * contact = linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(lc));
45
	BC_ASSERT_PTR_NOT_NULL(contact);
46
	return ms_strdup(linphone_address_get_domain(contact));
47
}
jehan's avatar
jehan committed
48 49


50
static void call_with_tunnel_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption, bool_t with_video_and_ice, bool_t dual_socket) {
51
	if (linphone_core_tunnel_available()){
52 53
		LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc");
		LinphoneCoreManager *marie = linphone_core_manager_new( "marie_rc");
54
		LinphoneCall *pauline_call, *marie_call;
55 56 57
		LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(pauline->lc);
		LinphoneAddress *server_addr = linphone_address_new(linphone_proxy_config_get_server_addr(proxy));
		LinphoneAddress *route = linphone_address_new(linphone_proxy_config_get_route(proxy));
jehan's avatar
jehan committed
58
		char  tunnel_ip[64];
59
		char *public_ip, *public_ip2=NULL;
jehan's avatar
jehan committed
60
		BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip)));
jehan's avatar
jehan committed
61 62
		linphone_core_remove_supported_tag(pauline->lc,"gruu"); /*with gruu, we have no access to the "public IP from contact*/
		linphone_core_remove_supported_tag(marie->lc,"gruu");
Benjamin REIS's avatar
Benjamin REIS committed
63

64
		BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,1));
65
		public_ip = get_public_contact_ip(pauline->lc);
66
		BC_ASSERT_STRING_NOT_EQUAL(public_ip, tunnel_ip);
67 68

		linphone_core_set_media_encryption(pauline->lc, encryption);
69

70 71 72 73 74
		if (with_video_and_ice){
			/*we want to test that tunnel is able to work with long SIP message, above mtu.
			 * Enable ICE and many codec to make the SIP message bigger*/
			linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce);
			linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce);
75
			linphone_core_enable_payload_type(pauline->lc,
76
				linphone_core_find_payload_type(pauline->lc, "speex", 32000, 1), TRUE);
77
			linphone_core_enable_payload_type(pauline->lc,
78
				linphone_core_find_payload_type(pauline->lc, "speex", 16000, 1), TRUE);
79
			linphone_core_enable_payload_type(pauline->lc,
80 81
				linphone_core_find_payload_type(pauline->lc, "G722", 8000, 1), TRUE);
		}
82

83
		if (tunnel_mode != LinphoneTunnelModeDisable){
84 85 86
			LinphoneTunnel *tunnel = linphone_core_get_tunnel(pauline->lc);
			LinphoneTunnelConfig *config = linphone_tunnel_config_new();

87
			linphone_tunnel_config_set_host(config, "tunnel.linphone.org");
88
			linphone_tunnel_config_set_port(config, 443);
89 90 91 92 93 94 95 96 97 98 99 100
			if (!dual_socket) {
				linphone_tunnel_config_set_host(config, "tunnel.linphone.org");
				linphone_tunnel_config_set_port(config, 443);
				linphone_tunnel_config_set_remote_udp_mirror_port(config, 12345);
			} else {
				linphone_tunnel_config_set_host(config, "94.23.19.176");
				linphone_tunnel_config_set_port(config, 4443);
				linphone_tunnel_config_set_host2(config, "188.165.40.171");
				linphone_tunnel_config_set_port2(config, 4443);
				linphone_tunnel_config_set_remote_udp_mirror_port(config, -1);
				linphone_tunnel_enable_dual_mode(tunnel, TRUE);
			}
101
			linphone_tunnel_add_server(tunnel, config);
102 103
			linphone_tunnel_set_mode(tunnel, tunnel_mode);
			linphone_tunnel_enable_sip(tunnel, with_sip);
104
			linphone_tunnel_config_unref(config);
105

106 107
			/*
			 * Enabling the tunnel with sip cause another REGISTER to be made.
108
			 * In automatic mode, the udp test should conclude (assuming we have a normal network), that no
109
			 * tunnel is needed. Thus the number of registrations should stay to 1.
110
			 * The library is missing a notification of "tunnel connectivity test finished" to enable the
111 112
			 * full testing of the automatic mode.
			 */
113

114
			if (tunnel_mode == LinphoneTunnelModeEnable && with_sip) {
115
				BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,2));
116 117 118 119 120 121 122
				/* Ensure that we did use the tunnel. If so, we should see contact changed from:
				Contact: <sip:pauline@192.168.0.201>;.[...]
				To:
				Contact: <sip:pauline@91.121.209.194:43867>;[....] (91.121.209.194 must be tunnel.liphone.org)
				*/
				ms_free(public_ip);
				public_ip = get_public_contact_ip(pauline->lc);
123 124 125 126 127
				if (!dual_socket) {
					BC_ASSERT_STRING_EQUAL(public_ip, tunnel_ip);
				} else {
					BC_ASSERT_STRING_EQUAL(public_ip, "94.23.19.176");
				}
128 129
			} else {
				public_ip2 = get_public_contact_ip(pauline->lc);
130
				BC_ASSERT_STRING_EQUAL(public_ip, public_ip2);
131
			}
132 133
		}

134
		BC_ASSERT_TRUE(call(pauline,marie));
135
		pauline_call=linphone_core_get_current_call(pauline->lc);
136
		BC_ASSERT_PTR_NOT_NULL(pauline_call);
137
		if (pauline_call!=NULL){
138 139
			BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(pauline_call)),
				encryption, int, "%d");
140
		}
141 142 143
		if (tunnel_mode == LinphoneTunnelModeEnable && with_sip){
			/* make sure the call from pauline arrived from the tunnel by checking the contact address*/
			marie_call = linphone_core_get_current_call(marie->lc);
144
			BC_ASSERT_PTR_NOT_NULL(marie_call);
145 146
			if (marie_call){
				const char *remote_contact = linphone_call_get_remote_contact(marie_call);
147
				BC_ASSERT_PTR_NOT_NULL(remote_contact);
148 149
				if (remote_contact){
					LinphoneAddress *tmp = linphone_address_new(remote_contact);
150
					BC_ASSERT_PTR_NOT_NULL(tmp);
151
					if (tmp){
152 153 154 155 156
						if (!dual_socket) {
							BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(tmp), tunnel_ip);
						} else {
							BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(tmp), "94.23.19.176");
						}
Simon Morlat's avatar
Simon Morlat committed
157
						linphone_address_unref(tmp);
158 159 160 161
					}
				}
			}
		}
Simon Morlat's avatar
Simon Morlat committed
162
#ifdef VIDEO_ENABLED
163
		if (with_video_and_ice){
164
			BC_ASSERT_TRUE(request_video(pauline, marie, TRUE));
165
		}
Simon Morlat's avatar
Simon Morlat committed
166
#endif
167 168
		end_call(pauline,marie);

169
		ms_free(public_ip);
170
		if(public_ip2 != NULL) ms_free(public_ip2);
Simon Morlat's avatar
Simon Morlat committed
171 172
		linphone_address_unref(server_addr);
		linphone_address_unref(route);
173 174 175 176 177 178 179
		linphone_core_manager_destroy(pauline);
		linphone_core_manager_destroy(marie);
	}else{
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
	}
}

jehan's avatar
jehan committed
180

181
static void call_with_tunnel(void) {
182
	call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, FALSE, FALSE);
183 184 185
}

static void call_with_tunnel_srtp(void) {
186
	call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionSRTP, FALSE, FALSE);
187 188 189
}

static void call_with_tunnel_without_sip(void) {
190
	call_with_tunnel_base(LinphoneTunnelModeEnable, FALSE, LinphoneMediaEncryptionNone, FALSE, FALSE);
191 192 193
}

static void call_with_tunnel_auto(void) {
194
	call_with_tunnel_base(LinphoneTunnelModeAuto, TRUE, LinphoneMediaEncryptionNone, FALSE, FALSE);
195 196
}

197
static void call_with_tunnel_auto_without_sip_with_srtp(void) {
198
	call_with_tunnel_base(LinphoneTunnelModeAuto, FALSE, LinphoneMediaEncryptionSRTP, FALSE, FALSE);
199 200
}

jehan's avatar
jehan committed
201
#ifdef VIDEO_ENABLED
202 203 204

static void full_tunnel_video_ice_call(void){
	if (linphone_core_tunnel_available()){
205
		call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, TRUE, FALSE);
206 207 208 209
	}else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}

jehan's avatar
jehan committed
210
static void tunnel_srtp_video_ice_call(void) {
jehan's avatar
jehan committed
211 212 213 214
	if (linphone_core_tunnel_available())
		call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
jehan's avatar
jehan committed
215 216
}
static void tunnel_zrtp_video_ice_call(void) {
jehan's avatar
jehan committed
217 218 219 220
	if (linphone_core_tunnel_available())
		call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
jehan's avatar
jehan committed
221
}
jehan's avatar
jehan committed
222 223

static void tunnel_dtls_video_ice_call(void) {
224
	if (linphone_core_tunnel_available())
jehan's avatar
jehan committed
225
		call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
226
	else
jehan's avatar
jehan committed
227 228 229
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}

jehan's avatar
jehan committed
230
static void tunnel_video_ice_call(void) {
jehan's avatar
jehan committed
231 232 233 234
	if (linphone_core_tunnel_available())
		call_base(LinphoneMediaEncryptionNone,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
jehan's avatar
jehan committed
235 236 237 238
}
#endif

static void tunnel_srtp_ice_call(void) {
jehan's avatar
jehan committed
239 240 241 242
	if (linphone_core_tunnel_available())
		call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
jehan's avatar
jehan committed
243 244 245
}

static void tunnel_zrtp_ice_call(void) {
jehan's avatar
jehan committed
246 247 248 249
	if (linphone_core_tunnel_available())
		call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
jehan's avatar
jehan committed
250 251 252
}

static void tunnel_ice_call(void) {
jehan's avatar
jehan committed
253 254 255 256
	if (linphone_core_tunnel_available())
		call_base(LinphoneMediaEncryptionNone,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
jehan's avatar
jehan committed
257
}
258 259 260 261 262

static void register_on_second_tunnel(void) {
	if (linphone_core_tunnel_available()) {
		LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc");
		LinphoneTunnel *tunnel = linphone_core_get_tunnel(pauline->lc);
263 264
		LinphoneTunnelConfig *config1 = linphone_tunnel_config_new();
		LinphoneTunnelConfig *config2 = linphone_tunnel_config_new();
jehan's avatar
jehan committed
265
		char tunnel_ip[64];
266
		char* public_ip;
Benjamin REIS's avatar
Benjamin REIS committed
267

jehan's avatar
jehan committed
268
		BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip)));
269 270 271
		linphone_tunnel_simulate_udp_loss(tunnel, TRUE);

		// add a first tunnel config with an invalid port
272 273 274 275
		linphone_tunnel_config_set_host(config1, "sip3.linphone.org");
		linphone_tunnel_config_set_port(config1, 4141);
		linphone_tunnel_config_set_remote_udp_mirror_port(config1, 54321);
		linphone_tunnel_add_server(tunnel, config1);
276 277

		// then a proper server
278 279 280 281
		linphone_tunnel_config_set_host(config2, "tunnel.linphone.org");
		linphone_tunnel_config_set_port(config2, 443);
		linphone_tunnel_config_set_remote_udp_mirror_port(config2, 12345);
		linphone_tunnel_add_server(tunnel, config2);
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

		linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeAuto);
		linphone_tunnel_enable_sip(tunnel, TRUE);

		reset_counters(&pauline->stat);

		linphone_core_refresh_registers(pauline->lc);
		// we should expect 2 registers: since tunnel autodetection takes several seconds, a first
		// register will be made, then tunnel will be configured and another register will be fired up
		BC_ASSERT_TRUE(wait_for(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk,2));

		public_ip = get_public_contact_ip(pauline->lc);
		BC_ASSERT_STRING_EQUAL(public_ip, tunnel_ip);
		ms_free(public_ip);

297 298
		linphone_tunnel_config_unref(config1);
		linphone_tunnel_config_unref(config2);
299 300 301 302 303 304
		linphone_core_manager_destroy(pauline);
	} else {
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
	}
}

305 306 307 308 309 310 311 312 313 314 315 316 317 318
static void dual_socket_mode(void) {
	if (linphone_core_tunnel_available())
		call_with_tunnel_base(LinphoneTunnelModeEnable, FALSE, LinphoneMediaEncryptionNone, FALSE, TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}

static void dual_socket_mode_with_sip(void) {
	if (linphone_core_tunnel_available())
		call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, FALSE, TRUE);
	else
		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}

319
test_t tunnel_tests[] = {
320 321 322 323 324 325 326 327
	TEST_NO_TAG("Simple", call_with_tunnel),
	TEST_NO_TAG("With SRTP", call_with_tunnel_srtp),
	TEST_NO_TAG("Without SIP", call_with_tunnel_without_sip),
	TEST_NO_TAG("In automatic mode", call_with_tunnel_auto),
	TEST_NO_TAG("In automatic mode with SRTP without SIP", call_with_tunnel_auto_without_sip_with_srtp),
	TEST_NO_TAG("Ice call", tunnel_ice_call),
	TEST_NO_TAG("SRTP ice call", tunnel_srtp_ice_call),
	TEST_NO_TAG("ZRTP ice call", tunnel_zrtp_ice_call),
jehan's avatar
jehan committed
328
#ifdef VIDEO_ENABLED
329 330 331 332 333
	TEST_NO_TAG("Ice video call", tunnel_video_ice_call),
	TEST_NO_TAG("With SIP - ice video call", full_tunnel_video_ice_call),
	TEST_NO_TAG("SRTP ice video call", tunnel_srtp_video_ice_call),
	TEST_NO_TAG("DTLS ice video call", tunnel_dtls_video_ice_call),
	TEST_NO_TAG("ZRTP ice video call", tunnel_zrtp_video_ice_call),
jehan's avatar
jehan committed
334
#endif
335
	TEST_NO_TAG("Register on second tunnel", register_on_second_tunnel),
336 337
	TEST_NO_TAG("Dual socket mode", dual_socket_mode),
	TEST_NO_TAG("Dual socket mode with SIP", dual_socket_mode_with_sip),
338 339
};

340
test_suite_t tunnel_test_suite = {"Tunnel", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
341
								  sizeof(tunnel_tests) / sizeof(tunnel_tests[0]), tunnel_tests};