complex_sip_case_tester.c 14.9 KB
Newer Older
jehan's avatar
jehan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
	liblinphone_tester - liblinphone test suite
	Copyright (C) 2015  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/>.
*/


20
#include "linphone/core.h"
jehan's avatar
jehan committed
21
#include "liblinphone_tester.h"
22
#include "linphone/lpconfig.h"
Benjamin REIS's avatar
Benjamin REIS committed
23
#include "tester_utils.h"
jehan's avatar
jehan committed
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
static void dest_server_server_resolved(void *data, belle_sip_resolver_results_t *results) {
	belle_sip_object_ref(results);
	*(belle_sip_resolver_results_t **)data = results;
}

LinphoneAddress * linphone_core_manager_resolve(LinphoneCoreManager *mgr, const LinphoneAddress *source) {
	char ipstring [INET6_ADDRSTRLEN];
	belle_sip_resolver_results_t *results = NULL;
	const struct addrinfo *ai = NULL;
	LinphoneAddress *dest;
	int err;
	int port = linphone_address_get_port(source);
	
	sal_resolve_a(
				  linphone_core_get_sal(mgr->lc),
				  linphone_address_get_domain(source),
				  linphone_address_get_port(source),
				  AF_INET,
				  dest_server_server_resolved,
				  &results
				  );
	wait_for_until(mgr->lc, mgr->lc, (int*)&results, 1,2000);
	
	ai = belle_sip_resolver_results_get_addrinfos(results);
	err = bctbx_getnameinfo((struct sockaddr*)ai->ai_addr, ai->ai_addrlen, ipstring, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
	if (err != 0)
		ms_error("linphone_core_manager_resolve(): getnameinfo error %s", gai_strerror(err));
	dest = linphone_address_new(NULL);
	linphone_address_set_domain(dest, ipstring);
	if (port > 0)
		linphone_address_set_port(dest, port);
	
	return dest;
}
59

60
#if HAVE_SIPP
61 62 63

#include <netdb.h>

64 65
void check_rtcp(LinphoneCall *call) {
	MSTimeSpec ts;
66
	LinphoneCallStats *audio_stats, *video_stats;
67

68 69
	linphone_call_ref(call);
	liblinphone_tester_clock_start(&ts);
70

71
	do {
72 73 74
		audio_stats = linphone_call_get_audio_stats(call);
		video_stats = linphone_call_get_video_stats(call);
		if (linphone_call_stats_get_round_trip_delay(audio_stats) > 0.0 && (!linphone_call_log_video_enabled(linphone_call_get_call_log(call)) || linphone_call_stats_get_round_trip_delay(video_stats) > 0.0)) {
75 76
			break;
		}
77 78
		linphone_call_stats_unref(audio_stats);
		if (video_stats) linphone_call_stats_unref(video_stats);
79
		wait_for_until(linphone_call_get_core(call), NULL, NULL, 0, 20); /*just to sleep while iterating*/
80
	} while (!liblinphone_tester_clock_elapsed(&ts, 15000));
81

82 83
	audio_stats = linphone_call_get_audio_stats(call);
	BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(audio_stats), 0.0, float, "%f");
84
	if (linphone_call_log_video_enabled(linphone_call_get_call_log(call))) {
85 86 87
		video_stats = linphone_call_get_video_stats(call);
		BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(video_stats), 0.0, float, "%f");
		linphone_call_stats_unref(video_stats);
88
	}
89
	linphone_call_stats_unref(audio_stats);
90

91 92
	linphone_call_unref(call);
}
jehan's avatar
jehan committed
93

94
FILE *sip_start(const char *senario, const char* dest_username, const char *passwd, LinphoneAddress* dest_addres) {
jehan's avatar
jehan committed
95 96 97
	char *dest;
	char *command;
	FILE *file;
jehan's avatar
jehan committed
98
	char local_ip[64];
jehan's avatar
jehan committed
99 100 101 102
	if (linphone_address_get_port(dest_addres)>0)
		dest = ms_strdup_printf("%s:%i",linphone_address_get_domain(dest_addres),linphone_address_get_port(dest_addres));
	else
		dest = ms_strdup_printf("%s",linphone_address_get_domain(dest_addres));
jehan's avatar
jehan committed
103 104
	
	linphone_core_get_local_ip_for(AF_INET, linphone_address_get_domain(dest_addres), local_ip);
105
	//until errors logs are handled correctly and stop breaks output, they will be DISABLED
jehan's avatar
jehan committed
106
	command = ms_strdup_printf(SIPP_COMMAND" -sf %s -s %s %s -i %s -trace_err -trace_msg -rtp_echo -m 1 -d 1000 -ap %s 2>/dev/null",senario
107 108
								,dest_username
								,dest
jehan's avatar
jehan committed
109
							    ,local_ip
110
								,(passwd?passwd:"none"));
111

112
	ms_message("Starting sipp command [%s]",command);
jehan's avatar
jehan committed
113 114 115 116 117
	file = popen(command, "r");
	ms_free(command);
	ms_free(dest);
	return file;
}
118

119

120 121 122 123 124
static FILE *sip_start_recv(const char *senario) {
	char *command;
	FILE *file;

	//until errors logs are handled correctly and stop breaks output, they will be DISABLED
125
	command = ms_strdup_printf(SIPP_COMMAND" -sf %s -trace_err -trace_msg -rtp_echo -m 1 -d 1000 2>/dev/null",senario);
126

127
	ms_message("Starting sipp command [%s]",command);
128 129 130 131
	file = popen(command, "r");
	ms_free(command);
	return file;
}
132

133 134
static void sip_update_within_icoming_reinvite_with_no_sdp(void) {
	LinphoneCoreManager *mgr;
jehan's avatar
jehan committed
135
	char *identity_char;
jehan's avatar
jehan committed
136 137
	char *scen;
	FILE * sipp_out;
138

jehan's avatar
jehan committed
139 140 141 142 143 144 145
	/*currently we use direct connection because sipp do not properly set ACK request uri*/
	mgr= linphone_core_manager_new2( "empty_rc", FALSE);
	mgr->identity= linphone_core_get_primary_contact_parsed(mgr->lc);
	linphone_address_set_username(mgr->identity,"marie");
	identity_char=linphone_address_as_string(mgr->identity);
	linphone_core_set_primary_contact(mgr->lc,identity_char);
	linphone_core_iterate(mgr->lc);
jehan's avatar
jehan committed
146
	scen = bc_tester_res("sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml");
147
	sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity),NULL, mgr->identity);
jehan's avatar
jehan committed
148 149

	if (sipp_out) {
jehan's avatar
jehan committed
150
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
151 152 153 154 155
		if (linphone_core_get_current_call(mgr->lc)) {
			linphone_call_accept(linphone_core_get_current_call(mgr->lc));
			BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2));
			BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
		}
jehan's avatar
jehan committed
156
		pclose(sipp_out);
jehan's avatar
jehan committed
157
	}
jehan's avatar
jehan committed
158
	linphone_core_manager_destroy(mgr);
jehan's avatar
jehan committed
159 160
}

161
static void call_with_audio_mline_before_video_in_sdp(void) {
162 163 164 165 166
	LinphoneCoreManager *mgr;
	char *identity_char;
	char *scen;
	FILE * sipp_out;
	LinphoneCall *call = NULL;
167

168 169 170 171 172 173
	/*currently we use direct connection because sipp do not properly set ACK request uri*/
	mgr= linphone_core_manager_new2( "empty_rc", FALSE);
	mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
	linphone_address_set_username(mgr->identity,"marie");
	identity_char = linphone_address_as_string(mgr->identity);
	linphone_core_set_primary_contact(mgr->lc,identity_char);
174

175
	linphone_core_iterate(mgr->lc);
176

177
	scen = bc_tester_res("sipp/call_with_audio_mline_before_video_in_sdp.xml");
jehan's avatar
jehan committed
178
	
179
	sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL,  mgr->identity);
180 181 182

	if (sipp_out) {
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
183
		call = linphone_core_get_current_call(mgr->lc);
184 185
		BC_ASSERT_PTR_NOT_NULL(call);
		if (call) {
186
			linphone_call_accept(call);
187
			BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
188 189 190
			BC_ASSERT_EQUAL(_linphone_call_get_main_audio_stream_index(call), 0, int, "%d");
			BC_ASSERT_EQUAL(_linphone_call_get_main_video_stream_index(call), 1, int, "%d");
			BC_ASSERT_TRUE(_linphone_call_get_main_text_stream_index(call) > 1);
191 192 193 194
			BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));

			check_rtcp(call);
		}
195

196 197 198 199 200 201
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
		pclose(sipp_out);
	}
	linphone_core_manager_destroy(mgr);
}

202
static void call_with_video_mline_before_audio_in_sdp(void) {
203 204 205 206 207
	LinphoneCoreManager *mgr;
	char *identity_char;
	char *scen;
	FILE * sipp_out;
	LinphoneCall *call = NULL;
208

209 210
	/*currently we use direct connection because sipp do not properly set ACK request uri*/
	mgr= linphone_core_manager_new2( "empty_rc", FALSE);
211
	mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
212
	linphone_address_set_username(mgr->identity,"marie");
213
	identity_char = linphone_address_as_string(mgr->identity);
214
	linphone_core_set_primary_contact(mgr->lc,identity_char);
215

216
	linphone_core_iterate(mgr->lc);
217

218
	scen = bc_tester_res("sipp/call_with_video_mline_before_audio_in_sdp.xml");
219

220
	sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL, mgr->identity);
221 222 223

	if (sipp_out) {
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
224
		call = linphone_core_get_current_call(mgr->lc);
225 226
		BC_ASSERT_PTR_NOT_NULL(call);
		if (call) {
227
			linphone_call_accept(call);
228
			BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
229 230 231
			BC_ASSERT_EQUAL(_linphone_call_get_main_audio_stream_index(call), 1, int, "%d");
			BC_ASSERT_EQUAL(_linphone_call_get_main_video_stream_index(call), 0, int, "%d");
			BC_ASSERT_TRUE(_linphone_call_get_main_text_stream_index(call) > 1);
232 233 234 235
			BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));

			check_rtcp(call);
		}
236

237 238 239 240 241 242
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
		pclose(sipp_out);
	}
	linphone_core_manager_destroy(mgr);
}

243
static void call_with_multiple_audio_mline_in_sdp(void) {
244 245 246 247 248
	LinphoneCoreManager *mgr;
	char *identity_char;
	char *scen;
	FILE * sipp_out;
	LinphoneCall *call = NULL;
249

250 251 252 253 254 255
	/*currently we use direct connection because sipp do not properly set ACK request uri*/
	mgr= linphone_core_manager_new2( "empty_rc", FALSE);
	mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
	linphone_address_set_username(mgr->identity,"marie");
	identity_char = linphone_address_as_string(mgr->identity);
	linphone_core_set_primary_contact(mgr->lc,identity_char);
256

257
	linphone_core_iterate(mgr->lc);
258

259
	scen = bc_tester_res("sipp/call_with_multiple_audio_mline_in_sdp.xml");
260

261
	sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL, mgr->identity);
262 263 264

	if (sipp_out) {
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
265
		call = linphone_core_get_current_call(mgr->lc);
266 267
		BC_ASSERT_PTR_NOT_NULL(call);
		if (call) {
268
			linphone_call_accept(call);
269
			BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
270 271 272
			BC_ASSERT_EQUAL(_linphone_call_get_main_audio_stream_index(call), 0, int, "%d");
			BC_ASSERT_EQUAL(_linphone_call_get_main_video_stream_index(call), 2, int, "%d");
			BC_ASSERT_TRUE(_linphone_call_get_main_text_stream_index(call) > 2);
273 274 275 276
			BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));

			check_rtcp(call);
		}
277

278 279 280 281 282 283
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
		pclose(sipp_out);
	}
	linphone_core_manager_destroy(mgr);
}

284
static void call_with_multiple_video_mline_in_sdp(void) {
285 286 287 288 289
	LinphoneCoreManager *mgr;
	char *identity_char;
	char *scen;
	FILE * sipp_out;
	LinphoneCall *call = NULL;
290

291 292 293 294 295 296
	/*currently we use direct connection because sipp do not properly set ACK request uri*/
	mgr= linphone_core_manager_new2( "empty_rc", FALSE);
	mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
	linphone_address_set_username(mgr->identity,"marie");
	identity_char = linphone_address_as_string(mgr->identity);
	linphone_core_set_primary_contact(mgr->lc,identity_char);
297

298
	linphone_core_iterate(mgr->lc);
299

300
	scen = bc_tester_res("sipp/call_with_multiple_video_mline_in_sdp.xml");
301

302
	sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL, mgr->identity);
303 304 305

	if (sipp_out) {
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
306
		call = linphone_core_get_current_call(mgr->lc);
307 308
		BC_ASSERT_PTR_NOT_NULL(call);
		if (call) {
309
			linphone_call_accept(call);
310
			BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
311 312 313
			BC_ASSERT_EQUAL(_linphone_call_get_main_audio_stream_index(call), 0, int, "%d");
			BC_ASSERT_EQUAL(_linphone_call_get_main_video_stream_index(call), 1, int, "%d");
			BC_ASSERT_TRUE(_linphone_call_get_main_text_stream_index(call) > 3);
314 315 316 317
			BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));

			check_rtcp(call);
		}
318

319 320 321 322 323 324
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
		pclose(sipp_out);
	}
	linphone_core_manager_destroy(mgr);
}

325

326
static void call_invite_200ok_without_contact_header(void) {
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	LinphoneCoreManager *mgr;
	char *identity_char;
	char *scen;
	FILE * sipp_out;
	LinphoneCall *call = NULL;

	/*currently we use direct connection because sipp do not properly set ACK request uri*/
	mgr= linphone_core_manager_new2("empty_rc", FALSE);
	mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
	linphone_address_set_username(mgr->identity,"marie");
	identity_char = linphone_address_as_string(mgr->identity);
	linphone_core_set_primary_contact(mgr->lc,identity_char);

	linphone_core_iterate(mgr->lc);

	scen = bc_tester_res("sipp/call_invite_200ok_without_contact_header.xml");

	sipp_out = sip_start_recv(scen);

	if (sipp_out) {
		call = linphone_core_invite(mgr->lc, "sipp@127.0.0.1");
		BC_ASSERT_PTR_NOT_NULL(call);
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallOutgoingInit, 1));
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1));
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallOutgoingRinging, 1));
352 353 354 355
		/*assert that the call never gets connected nor terminated*/
		BC_ASSERT_FALSE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallConnected, 1));
		BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneCallEnd, 0, int, "%d");
		BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneCallError, 0, int, "%d");
356
		linphone_call_terminate(call);
357 358
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
		BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallReleased, 1));
359 360 361 362
		pclose(sipp_out);
	}
	linphone_core_manager_destroy(mgr);
}
363

364

jehan's avatar
jehan committed
365
static test_t tests[] = {
366 367 368 369 370 371
	TEST_NO_TAG("SIP UPDATE within incoming reinvite without sdp", sip_update_within_icoming_reinvite_with_no_sdp),
	TEST_NO_TAG("Call with audio mline before video in sdp", call_with_audio_mline_before_video_in_sdp),
	TEST_NO_TAG("Call with video mline before audio in sdp", call_with_video_mline_before_audio_in_sdp),
	TEST_NO_TAG("Call with multiple audio mline in sdp", call_with_multiple_audio_mline_in_sdp),
	TEST_NO_TAG("Call with multiple video mline in sdp", call_with_multiple_video_mline_in_sdp),
	TEST_NO_TAG("Call invite 200ok without contact header", call_invite_200ok_without_contact_header)
jehan's avatar
jehan committed
372
};
373
#endif
jehan's avatar
jehan committed
374

375 376 377 378 379 380 381 382 383 384 385
static bool_t previous_liblinphonetester_ipv6;
static void before_each(void) {
	previous_liblinphonetester_ipv6=liblinphonetester_ipv6;
	liblinphonetester_ipv6=FALSE; /*sipp  do not support ipv6 and remote port*/
	liblinphone_tester_before_each();
}
static void after_each(void) {
	liblinphonetester_ipv6=previous_liblinphonetester_ipv6;
	liblinphone_tester_after_each();
}

jehan's avatar
jehan committed
386
test_suite_t complex_sip_call_test_suite = {
387
	"Complex SIP Case",
Sylvain Berfini's avatar
Sylvain Berfini committed
388 389
	NULL,
	NULL,
390 391
	before_each,
	after_each,
392
#if HAVE_SIPP
jehan's avatar
jehan committed
393 394
	sizeof(tests) / sizeof(tests[0]),
	tests
395 396 397 398
#else
	0,
	NULL
#endif
jehan's avatar
jehan committed
399
};