tester.c 25 KB
Newer Older
1
 /*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 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 <stdio.h>
#include "linphonecore.h"
#include "private.h"
#include "liblinphone_tester.h"
23 24 25 26 27 28 29 30

#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wstrict-prototypes"

#include "CUnit/TestRun.h"
#include "CUnit/Automated.h"
31 32 33
#if HAVE_CU_CURSES
#include "CUnit/CUCurses.h"
#endif
34 35 36
#ifdef HAVE_GTK
#include <gtk/gtk.h>
#endif
37 38 39 40 41

#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic pop
#endif

Ghislain MARY's avatar
Ghislain MARY committed
42 43 44
#if _WIN32
#define unlink _unlink
#endif
45

46 47
static bool_t liblinphone_tester_ipv6_enabled=FALSE;
static int liblinphone_tester_keep_accounts_flag = 0;
48
static int liblinphone_tester_keep_record_files = FALSE;
49
static int liblinphone_tester_leak_detector_disabled = FALSE;
50
int manager_count = 0;
51
int leaked_objects_count = 0;
Simon Morlat's avatar
Simon Morlat committed
52 53
const MSAudioDiffParams audio_cmp_params = {10,2000};

54 55 56 57 58 59
const char* test_domain="sipopen.example.org";
const char* auth_domain="sip.example.org";
const char* test_username="liblinphone_tester";
const char* test_password="secret";
const char* test_route="sip2.linphone.org";
const char *userhostsfile = "tester_hosts";
Gautier Pelloux-Prayer's avatar
Gautier Pelloux-Prayer committed
60

61 62
const char *liblinphone_tester_mire_id="Mire: Mire (synthetic moving picture)";

63
static void network_reachable(LinphoneCore *lc, bool_t reachable) {
64 65 66 67 68 69 70 71
	stats* counters;
	ms_message("Network reachable [%s]",reachable?"TRUE":"FALSE");
	counters = get_stats(lc);
	if (reachable)
		counters->number_of_NetworkReachableTrue++;
	else
		counters->number_of_NetworkReachableFalse++;
}
72 73 74 75 76 77 78 79 80 81 82 83
void liblinphone_tester_clock_start(MSTimeSpec *start){
	ms_get_cur_time(start);
}

bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms){
	MSTimeSpec current;
	ms_get_cur_time(&current);
	if ((((current.tv_sec-start->tv_sec)*1000LL) + ((current.tv_nsec-start->tv_nsec)/1000000LL))>=value_ms)
		return TRUE;
	return FALSE;
}

84 85 86 87
void liblinphone_tester_enable_ipv6(bool_t enabled){
	liblinphone_tester_ipv6_enabled=enabled;
}

88 89
LinphoneAddress * create_linphone_address(const char * domain) {
	LinphoneAddress *addr = linphone_address_new(NULL);
90
	BC_ASSERT_PTR_NOT_NULL_FATAL(addr);
91
	linphone_address_set_username(addr,test_username);
92
	BC_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr));
93 94
	if (!domain) domain= test_route;
	linphone_address_set_domain(addr,domain);
95
	BC_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr));
96 97
	linphone_address_set_display_name(addr, NULL);
	linphone_address_set_display_name(addr, "Mr Tester");
98
	BC_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr));
99 100 101 102 103 104
	return addr;
}

static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
	stats* counters;
	ms_message("Auth info requested  for user id [%s] at realm [%s]\n"
105 106
			   ,username
			   ,realm);
107 108 109 110 111
	counters = get_stats(lc);
	counters->number_of_auth_info_requested++;
}

void reset_counters( stats* counters) {
112
	if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message);
113
	if (counters->last_received_info_message) linphone_info_message_destroy(counters->last_received_info_message);
114 115 116
	memset(counters,0,sizeof(stats));
}

117
LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) {
118
	LinphoneCore* lc;
119 120 121 122 123 124 125
	LpConfig* config = NULL;
	char *filepath         = NULL;
	char *ringpath         = NULL;
	char *ringbackpath     = NULL;
	char *rootcapath       = NULL;
	char *dnsuserhostspath = NULL;
	char *nowebcampath     = NULL;
126 127 128 129

	if (path==NULL) path=".";

	if (file){
130
		filepath = ms_strdup_printf("%s/%s", path, file);
131 132 133
		if (ortp_file_exist(filepath) != 0) {
			ms_fatal("Could not find file %s in path %s, did you configured resources directory correctly?", file, path);
		}
134
		config = lp_config_new_with_factory(NULL,filepath);
135 136 137
	}


138 139 140 141 142 143
	// setup dynamic-path assets
	ringpath         = ms_strdup_printf("%s/sounds/oldphone.wav",path);
	ringbackpath     = ms_strdup_printf("%s/sounds/ringback.wav", path);
	nowebcampath     = ms_strdup_printf("%s/images/nowebcamCIF.jpg", path);
	rootcapath       = ms_strdup_printf("%s/certificates/cn/cafile.pem", path);
	dnsuserhostspath = ms_strdup_printf( "%s/%s", path, userhostsfile);
144 145


146 147 148 149 150 151
	if( config != NULL ) {
		lp_config_set_string(config, "sound", "remote_ring", ringbackpath);
		lp_config_set_string(config, "sound", "local_ring" , ringpath);
		lp_config_set_string(config, "sip",   "root_ca"    , rootcapath);
		lc = linphone_core_new_with_config(v_table, config, user_data);
	} else {
152
		lc = linphone_core_new(v_table,NULL,(filepath!=NULL&&filepath[0]!='\0') ? filepath : NULL, user_data);
153 154 155 156 157

		linphone_core_set_ring(lc, ringpath);
		linphone_core_set_ringback(lc, ringbackpath);
		linphone_core_set_root_ca(lc,rootcapath);
	}
158

159 160
	sal_enable_test_features(lc->sal,TRUE);
	sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath);
161
	linphone_core_set_static_picture(lc,nowebcampath);
162

163
	linphone_core_enable_ipv6(lc, liblinphone_tester_ipv6_enabled);
164 165 166 167 168 169 170 171 172 173 174

	ms_free(ringpath);
	ms_free(ringbackpath);
	ms_free(nowebcampath);
	ms_free(rootcapath);
	ms_free(dnsuserhostspath);

	if( filepath ) ms_free(filepath);

	if( config ) lp_config_unref(config);

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
	return lc;
}


bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout) {
	MSList* lcs=NULL;
	bool_t result;
	if (lc_1)
		lcs=ms_list_append(lcs,lc_1);
	if (lc_2)
		lcs=ms_list_append(lcs,lc_2);
	result=wait_for_list(lcs,counter,value,timout);
	ms_list_free(lcs);
	return result;
}

bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) {
192
	return wait_for_until(lc_1, lc_2,counter,value,10000);
193 194 195 196
}

bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) {
	MSList* iterator;
197
	MSTimeSpec start;
198

199 200 201
	liblinphone_tester_clock_start(&start);
	while ((counter==NULL || *counter<value) && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
		for (iterator=lcs;iterator!=NULL;iterator=iterator->next) {
202 203 204 205 206
#ifdef HAVE_GTK
			gdk_threads_enter();
			gtk_main_iteration_do(FALSE);
			gdk_threads_leave();
#endif
207 208
			linphone_core_iterate((LinphoneCore*)(iterator->data));
		}
Ghislain MARY's avatar
Ghislain MARY committed
209
#ifdef LINPHONE_WINDOWS_DESKTOP
210 211 212 213 214 215 216 217
		{
			MSG msg;
			while (PeekMessage(&msg, NULL, 0, 0,1)){
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
#endif
218
		ms_usleep(20000);
219 220 221 222 223 224 225 226 227 228
	}
	if(counter && *counter<value) return FALSE;
	else return TRUE;
}

static void set_codec_enable(LinphoneCore* lc,const char* type,int rate,bool_t enable) {
	MSList* codecs=ms_list_copy(linphone_core_get_audio_codecs(lc));
	MSList* codecs_it;
	PayloadType* pt;
	for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) {
229
		linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0);
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	}
	if((pt = linphone_core_find_payload_type(lc,type,rate,1))) {
		linphone_core_enable_payload_type(lc,pt, enable);
	}
	ms_list_free(codecs);
}

static void enable_codec(LinphoneCore* lc,const char* type,int rate) {
	set_codec_enable(lc,type,rate,TRUE);
}
stats * get_stats(LinphoneCore *lc){
	LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc);
	return &manager->stat;
}

LinphoneCoreManager *get_manager(LinphoneCore *lc){
	LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc);
	return manager;
}

250 251 252
bool_t transport_supported(LinphoneTransportType transport) {
	Sal *sal = sal_init();
	bool_t supported = sal_transport_available(sal,(SalTransport)transport);
253
	if (!supported) ms_message("TLS transport not supported, falling back to TCP if possible otherwise skipping test.");
254
	sal_uninit(sal);
255 256 257
	return supported;
}

258
void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file) {
259
	char *rc_path = NULL;
jehan's avatar
jehan committed
260
	char *hellopath = bc_tester_res("sounds/hello8000.wav");
jehan's avatar
jehan committed
261
	mgr->number_of_cunit_error_at_creation = CU_get_number_of_failures();
262 263 264 265 266 267 268 269 270 271 272 273 274 275
	mgr->v_table.registration_state_changed=registration_state_changed;
	mgr->v_table.auth_info_requested=auth_info_requested;
	mgr->v_table.call_state_changed=call_state_changed;
	mgr->v_table.text_received=text_message_received;
	mgr->v_table.message_received=message_received;
	mgr->v_table.is_composing_received=is_composing_received;
	mgr->v_table.new_subscription_requested=new_subscription_requested;
	mgr->v_table.notify_presence_received=notify_presence_received;
	mgr->v_table.transfer_state_changed=linphone_transfer_state_changed;
	mgr->v_table.info_received=info_message_received;
	mgr->v_table.subscription_state_changed=linphone_subscription_state_change;
	mgr->v_table.notify_received=linphone_notify_received;
	mgr->v_table.publish_state_changed=linphone_publish_state_changed;
	mgr->v_table.configuring_status=linphone_configuration_status;
jehan's avatar
jehan committed
276
	mgr->v_table.call_encryption_changed=linphone_call_encryption_changed;
277
	mgr->v_table.network_reachable=network_reachable;
278
	mgr->v_table.dtmf_received=dtmf_received;
279
	mgr->v_table.call_stats_updated=call_stats_updated;
280 281 282

	reset_counters(&mgr->stat);
	if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file);
283
	mgr->lc=configure_lc_from(&mgr->v_table, bc_tester_get_resource_dir_prefix(), rc_path, mgr);
284
	linphone_core_manager_check_accounts(mgr);
285

286 287
	manager_count++;

Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
288
#if TARGET_OS_IPHONE
289 290
	linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device");
	linphone_core_set_ringback(mgr->lc, NULL);
291 292
#elif __QNX__
	linphone_core_set_playback_device(mgr->lc, "QSA: voice");
293 294
#endif

295 296 297 298 299 300 301
#ifdef VIDEO_ENABLED
	{
		MSWebCam *cam;

		cam = ms_web_cam_manager_get_cam(ms_web_cam_manager_get(), "Mire: Mire (synthetic moving picture)");

		if (cam == NULL) {
Simon Morlat's avatar
Simon Morlat committed
302 303 304 305 306
			MSWebCamDesc *desc = ms_mire_webcam_desc_get();
			if (desc){
				cam=ms_web_cam_new(desc);
				ms_web_cam_manager_add_cam(ms_web_cam_manager_get(), cam);
			}
307 308 309 310
		}
	}
#endif

jehan's avatar
jehan committed
311

312 313
	linphone_core_set_play_file(mgr->lc,hellopath); /*is also used when in pause*/
	ms_free(hellopath);
314

315
	if( manager_count >= 2){
316
		char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",bc_tester_get_writable_dir_prefix(),mgr->lc);
317
		ms_message("Manager for '%s' using files", rc_file ? rc_file : "--");
318
		linphone_core_set_use_files(mgr->lc, TRUE);
319 320
		linphone_core_set_record_file(mgr->lc,recordpath);
		ms_free(recordpath);
321
	}
322

323
	linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix());
324 325
	/*for now, we need the periodical updates facility to compute bandwidth measurements correctly during tests*/
	lp_config_set_int(linphone_core_get_config(mgr->lc), "misc", "send_call_stats_periodical_updates", 1);
326

327 328
	if (rc_path) ms_free(rc_path);
}
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
329

330
void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies) {
331 332
	LinphoneProxyConfig* proxy;
	int proxy_count;
333

334
	/*BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count, int, "%d");*/
335
	if (check_for_proxies) /**/
336 337 338
		proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc));
	else
		proxy_count=0;
339

340 341 342
	if (proxy_count){
#define REGISTER_TIMEOUT 20 /* seconds */
		int success = wait_for_until(mgr->lc,NULL,&mgr->stat.number_of_LinphoneRegistrationOk,
Guillaume BIENKOWSKI's avatar
Typo  
Guillaume BIENKOWSKI committed
343
									proxy_count,(REGISTER_TIMEOUT * 1000 * proxy_count));
344 345 346 347
		if( !success ){
			ms_error("Did not register after %d seconds for %d proxies", REGISTER_TIMEOUT, proxy_count);
		}
	}
348
	BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count, int, "%d");
349 350
	enable_codec(mgr->lc,"PCMU",8000);

351
	proxy = linphone_core_get_default_proxy_config(mgr->lc);
352
	if (proxy) {
353
		mgr->identity = linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
354 355 356 357 358
		linphone_address_clean(mgr->identity);
	}
}

LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) {
359 360 361
	LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
	linphone_core_manager_init(manager, rc_file);
	linphone_core_manager_start(manager, TRUE);
362 363 364 365
	return manager;
}

LinphoneCoreManager* linphone_core_manager_new2( const char* rc_file, int check_for_proxies) {
366 367 368
	LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
	linphone_core_manager_init(manager, rc_file);
	linphone_core_manager_start(manager, check_for_proxies);
369
	return manager;
370 371 372 373 374 375 376 377 378
}

void linphone_core_manager_stop(LinphoneCoreManager *mgr){
	if (mgr->lc) {
		linphone_core_destroy(mgr->lc);
		mgr->lc=NULL;
	}
}

379
void linphone_core_manager_uninit(LinphoneCoreManager *mgr) {
380 381 382
	if (mgr->stat.last_received_chat_message) {
		linphone_chat_message_unref(mgr->stat.last_received_chat_message);
	}
383
	if (mgr->stat.last_received_info_message) linphone_info_message_destroy(mgr->stat.last_received_info_message);
Simon Morlat's avatar
Simon Morlat committed
384 385
	if (mgr->lc){
		const char *record_file=linphone_core_get_record_file(mgr->lc);
386
		int unterminated_calls;
387

388
		if (!liblinphone_tester_keep_record_files && record_file){
jehan's avatar
jehan committed
389
			if ((CU_get_number_of_failures()-mgr->number_of_cunit_error_at_creation)>0) {
Simon Morlat's avatar
Simon Morlat committed
390 391 392 393
				ms_message ("Test has failed, keeping recorded file [%s]",record_file);
			} else {
				unlink(record_file);
			}
394
		}
395 396 397
		BC_ASSERT_EQUAL((unterminated_calls=ms_list_size(mgr->lc->calls)), 0, int, "%i");
		if (unterminated_calls != 0) {
			ms_error("There are still %d calls pending, please terminates them before invoking linphone_core_manager_destroy().", unterminated_calls);
398
		}
Simon Morlat's avatar
Simon Morlat committed
399
		linphone_core_destroy(mgr->lc);
400
	}
401 402 403
	if (mgr->identity) {
		linphone_address_destroy(mgr->identity);
	}
404
	
405
	manager_count--;
406
}
407

408 409
void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
	linphone_core_manager_uninit(mgr);
410 411 412
	ms_free(mgr);
}

413 414 415 416 417 418 419 420
int liblinphone_tester_ipv6_available(void){
	struct addrinfo *ai=belle_sip_ip_address_to_addrinfo(AF_INET6,"2a01:e00::2",53);
	if (ai){
		struct sockaddr_storage ss;
		struct addrinfo src;
		socklen_t slen=sizeof(ss);
		char localip[128];
		int port=0;
421
		belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444);
422 423 424 425 426 427 428 429 430
		src.ai_addr=(struct sockaddr*) &ss;
		src.ai_addrlen=slen;
		belle_sip_addrinfo_to_ip(&src,localip, sizeof(localip),&port);
		freeaddrinfo(ai);
		return strcmp(localip,"::1")!=0;
	}
	return FALSE;
}

431 432 433 434
void liblinphone_tester_keep_accounts( int keep ){
	liblinphone_tester_keep_accounts_flag = keep;
}

435 436 437 438
void liblinphone_tester_keep_recorded_files(int keep){
	liblinphone_tester_keep_record_files = keep;
}

439 440 441 442
void liblinphone_tester_disable_leak_detector(int disabled){
	liblinphone_tester_leak_detector_disabled = disabled;
}

443 444 445
void liblinphone_tester_clear_accounts(void){
	account_manager_destroy();
}
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463

void liblinphone_tester_add_suites() {
	bc_tester_add_suite(&setup_test_suite);
	bc_tester_add_suite(&register_test_suite);
	bc_tester_add_suite(&offeranswer_test_suite);
	bc_tester_add_suite(&call_test_suite);
	bc_tester_add_suite(&multi_call_test_suite);
	bc_tester_add_suite(&message_test_suite);
	bc_tester_add_suite(&presence_test_suite);
#ifdef UPNP
	bc_tester_add_suite(&upnp_test_suite);
#endif
	bc_tester_add_suite(&stun_test_suite);
	bc_tester_add_suite(&event_test_suite);
	bc_tester_add_suite(&flexisip_test_suite);
	bc_tester_add_suite(&remote_provisioning_test_suite);
	bc_tester_add_suite(&quality_reporting_test_suite);
	bc_tester_add_suite(&log_collection_test_suite);
464
	bc_tester_add_suite(&tunnel_test_suite);
465 466 467 468 469 470
	bc_tester_add_suite(&player_test_suite);
	bc_tester_add_suite(&dtmf_test_suite);
#if defined(VIDEO_ENABLED) && defined(HAVE_GTK)
	bc_tester_add_suite(&video_test_suite);
#endif
	bc_tester_add_suite(&multicast_call_test_suite);
471
	bc_tester_add_suite(&proxy_config_test_suite);
jehan's avatar
jehan committed
472 473 474
#if HAVE_SIPP
	bc_tester_add_suite(&complex_sip_call_test_suite);
#endif
475
}
476

Simon Morlat's avatar
Simon Morlat committed
477
static int linphone_core_manager_get_max_audio_bw_base(const int array[],int array_size) {
478 479 480 481 482 483 484
	int i,result=0;
	for (i=0; i<array_size; i++) {
		result = MAX(result,array[i]);
	}
	return result;
}

Simon Morlat's avatar
Simon Morlat committed
485 486 487 488 489 490 491 492
static int linphone_core_manager_get_mean_audio_bw_base(const int array[],int array_size) {
	int i,result=0;
	for (i=0; i<array_size; i++) {
		result += array[i];
	}
	return result/array_size;
}

493 494 495 496 497 498 499 500
int linphone_core_manager_get_max_audio_down_bw(const LinphoneCoreManager *mgr) {
	return linphone_core_manager_get_max_audio_bw_base(mgr->stat.audio_download_bandwidth
			, sizeof(mgr->stat.audio_download_bandwidth)/sizeof(int));
}
int linphone_core_manager_get_max_audio_up_bw(const LinphoneCoreManager *mgr) {
	return linphone_core_manager_get_max_audio_bw_base(mgr->stat.audio_upload_bandwidth
			, sizeof(mgr->stat.audio_upload_bandwidth)/sizeof(int));
}
501

Simon Morlat's avatar
Simon Morlat committed
502 503 504 505 506 507 508 509 510
int linphone_core_manager_get_mean_audio_down_bw(const LinphoneCoreManager *mgr) {
	return linphone_core_manager_get_mean_audio_bw_base(mgr->stat.audio_download_bandwidth
			, sizeof(mgr->stat.audio_download_bandwidth)/sizeof(int));
}
int linphone_core_manager_get_mean_audio_up_bw(const LinphoneCoreManager *mgr) {
	return linphone_core_manager_get_mean_audio_bw_base(mgr->stat.audio_upload_bandwidth
			, sizeof(mgr->stat.audio_upload_bandwidth)/sizeof(int));
}

511
void liblinphone_tester_before_each(void) {
512 513 514 515
	if (!liblinphone_tester_leak_detector_disabled){
		belle_sip_object_enable_leak_detector(TRUE);
		leaked_objects_count = belle_sip_object_get_object_count();
	}
516 517
}

518 519
static char* all_leaks_buffer = NULL;

520
void liblinphone_tester_after_each(void) {
521 522 523
	if (!liblinphone_tester_leak_detector_disabled){
		int leaked_objects = belle_sip_object_get_object_count() - leaked_objects_count;
		if (leaked_objects > 0) {
524 525 526
			char* format = ms_strdup_printf("%d object%s leaked in suite [%s] test [%s], please fix that!",
											leaked_objects, leaked_objects>1?"s were":"was",
											bc_tester_current_suite_name(), bc_tester_current_test_name());
527
			belle_sip_object_dump_active_objects();
528
			belle_sip_object_flush_active_objects();
529 530 531 532
			bc_tester_printf(bc_printf_verbosity_info, format);
			ms_error("%s", format);

			all_leaks_buffer = ms_strcat_printf(all_leaks_buffer, "\n%s", format);
533
		}
534 535
	}

536
	if (manager_count != 0) {
537
		ms_fatal("%d Linphone core managers are still alive!", manager_count);
538 539
	}
}
540

541 542 543 544 545
void liblinphone_tester_uninit(void) {
	// show all leaks that happened during the test
	if (all_leaks_buffer) {
		bc_tester_printf(bc_printf_verbosity_info, all_leaks_buffer);
		ms_free(all_leaks_buffer);
546
		all_leaks_buffer = NULL;
547 548 549
	}
	bc_tester_uninit();
}
550

551
static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStreamType stream_type) {
552
	MediaStream *ms;
553 554
	switch (stream_type) {
	case LinphoneStreamTypeAudio:
555 556
		ms=&c1->audiostream->ms;
		break;
557
	case LinphoneStreamTypeVideo:
558 559 560 561 562 563 564 565 566
		ms=&c1->videostream->ms;
		break;
	case LinphoneStreamTypeText:
		ms=&c1->textstream->ms;
		break;
	default:
		ms_error("Unknown stream type [%s]",  linphone_stream_type_to_string(stream_type));
		BC_ASSERT_FALSE(stream_type >= LinphoneStreamTypeUnknown);
		return;
567 568 569
	}
	
	
570
	if (linphone_call_get_audio_stats(c1)->ice_state == LinphoneIceStateHostConnection && media_stream_started(ms)) {
571 572 573 574 575 576 577 578 579 580 581 582
		char ip[16];
		char port[8];
		getnameinfo((const struct sockaddr *)&c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr
					, c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addrlen
					, ip
					, sizeof(ip)
					, port
					, sizeof(port)
					, NI_NUMERICHOST|NI_NUMERICSERV);
		BC_ASSERT_STRING_EQUAL(ip, c2->media_localip);
	}
}
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) {
	LinphoneCall *c1,*c2;
	bool_t audio_success=FALSE;
	bool_t video_success=FALSE;
	bool_t text_success=FALSE;
	bool_t video_enabled, realtime_text_enabled;
	MSTimeSpec ts;
	
	c1=linphone_core_get_current_call(caller->lc);
	c2=linphone_core_get_current_call(callee->lc);
	
	BC_ASSERT_PTR_NOT_NULL(c1);
	BC_ASSERT_PTR_NOT_NULL(c2);
	if (!c1 || !c2) return FALSE;
	linphone_call_ref(c1);
	linphone_call_ref(c2);
	
	BC_ASSERT_EQUAL(linphone_call_params_video_enabled(linphone_call_get_current_params(c1)),linphone_call_params_video_enabled(linphone_call_get_current_params(c2)), int, "%d");
	BC_ASSERT_EQUAL(linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c1)),linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c2)), int, "%d");
	video_enabled=linphone_call_params_video_enabled(linphone_call_get_current_params(c1));
	realtime_text_enabled=linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c1));
	liblinphone_tester_clock_start(&ts);
	do{
		if ((c1 != NULL) && (c2 != NULL)) {
			if (linphone_call_get_audio_stats(c1)->ice_state==state &&
				linphone_call_get_audio_stats(c2)->ice_state==state ){
				audio_success=TRUE;
610 611
				check_ice_from_rtp(c1,c2,LinphoneStreamTypeAudio);
				check_ice_from_rtp(c2,c1,LinphoneStreamTypeAudio);
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
				break;
			}
			linphone_core_iterate(caller->lc);
			linphone_core_iterate(callee->lc);
		}
		ms_usleep(20000);
	}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	
	if (video_enabled){
		liblinphone_tester_clock_start(&ts);
		do{
			if ((c1 != NULL) && (c2 != NULL)) {
				if (linphone_call_get_video_stats(c1)->ice_state==state &&
					linphone_call_get_video_stats(c2)->ice_state==state ){
					video_success=TRUE;
627 628
					check_ice_from_rtp(c1,c2,LinphoneStreamTypeVideo);
					check_ice_from_rtp(c2,c1,LinphoneStreamTypeVideo);
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
					break;
				}
				linphone_core_iterate(caller->lc);
				linphone_core_iterate(callee->lc);
			}
			ms_usleep(20000);
		}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	}
	
	if (realtime_text_enabled){
		liblinphone_tester_clock_start(&ts);
		do{
			if ((c1 != NULL) && (c2 != NULL)) {
				if (linphone_call_get_text_stats(c1)->ice_state==state &&
					linphone_call_get_text_stats(c2)->ice_state==state ){
					text_success=TRUE;
645 646
					check_ice_from_rtp(c1,c2,LinphoneStreamTypeText);
					check_ice_from_rtp(c2,c1,LinphoneStreamTypeText);
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
					break;
				}
				linphone_core_iterate(caller->lc);
				linphone_core_iterate(callee->lc);
			}
			ms_usleep(20000);
		}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	}
	
	/*make sure encryption mode are preserved*/
	if (c1) {
		const LinphoneCallParams* call_param = linphone_call_get_current_params(c1);
		BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc), int, "%d");
	}
	if (c2) {
		const LinphoneCallParams* call_param = linphone_call_get_current_params(c2);
		BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(callee->lc), int, "%d");
	}
	linphone_call_unref(c1);
	linphone_call_unref(c2);
	return video_enabled ? (realtime_text_enabled ? text_success && audio_success && video_success : audio_success && video_success) : realtime_text_enabled ? text_success && audio_success : audio_success;
}

670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
void linphone_conference_server_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) {
	LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
	LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)vtable->user_data;
	
	switch(cstate) {
		case LinphoneCallIncomingReceived:
			linphone_core_accept_call(lc, call);
			break;
			
		case LinphoneCallStreamsRunning:
			if(linphone_call_get_conference(call) == NULL) {
				linphone_core_add_to_conference(lc, call);
				linphone_core_leave_conference(lc);
				if(conf_srv->first_call == NULL) conf_srv->first_call = linphone_call_ref(call);
			}
			break;
			
		case LinphoneCallEnd:
			if(call == conf_srv->first_call) {
				linphone_core_terminate_conference(lc);
				linphone_call_unref(call);
				conf_srv->first_call = NULL;
			}
			break;
			
		default: break;
	}
}

699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
void linphone_conference_server_refer_received(LinphoneCore *core, const char *refer_to) {
	char method[20];
	LinphoneAddress *refer_to_addr = linphone_address_new(refer_to);
	char *uri;
	LinphoneCall *call;
	
	if(refer_to_addr == NULL) return;
	strncpy(method, linphone_address_get_method_param(refer_to_addr), sizeof(method));
	if(strcmp(method, "BYE") == 0) {
		linphone_address_clean(refer_to_addr);
		uri = linphone_address_as_string_uri_only(refer_to_addr);
		call = linphone_core_find_call_from_uri(core, uri);
		if(call) linphone_core_terminate_call(core, call);
		ms_free(uri);
	}
	linphone_address_destroy(refer_to_addr);
}

717 718 719 720 721 722
LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file) {
	LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)ms_new0(LinphoneConferenceServer, 1);
	LinphoneCoreManager *lm = (LinphoneCoreManager *)conf_srv;
	
	conf_srv->vtable = linphone_core_v_table_new();
	conf_srv->vtable->call_state_changed = linphone_conference_server_call_state_changed;
723
	conf_srv->vtable->refer_received = linphone_conference_server_refer_received;
724 725 726 727 728 729
	conf_srv->vtable->user_data = conf_srv;
	linphone_core_manager_init(lm, rc_file);
	linphone_core_add_listener(lm->lc, conf_srv->vtable);
	linphone_core_manager_start(lm, TRUE);
	return conf_srv;
}
730

731 732 733 734 735
void linphone_conference_server_destroy(LinphoneConferenceServer *conf_srv) {
	linphone_core_manager_uninit((LinphoneCoreManager *)conf_srv);
	linphone_core_v_table_destroy(conf_srv->vtable);
	ms_free(conf_srv);
}