tester.c 97.4 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (c) 2010-2019 Belledonne Communications SARL.
 *
 * This file is part of Liblinphone.
 *
 * 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 3 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/>.
18 19 20
 */

#include <stdio.h>
21
#include <stdlib.h>
22
#include "linphone/core.h"
23 24
#include "linphone/logging.h"
#include "logging-private.h"
25
#include "liblinphone_tester.h"
26
#include <bctoolbox/tester.h>
Benjamin REIS's avatar
Benjamin REIS committed
27
#include "tester_utils.h"
28

29 30
#define SKIP_PULSEAUDIO 1

Ghislain MARY's avatar
Ghislain MARY committed
31 32 33
#if _WIN32
#define unlink _unlink
#endif
34

Erwan Croze's avatar
Erwan Croze committed
35
#ifdef __ANDROID__
Erwan Croze's avatar
Erwan Croze committed
36
extern jobject system_context;
Erwan Croze's avatar
Erwan Croze committed
37 38 39
#else
void *system_context=0;
#endif
40

41
static char *liblinphone_tester_empty_rc_path = NULL;
42
static int liblinphone_tester_keep_accounts_flag = 0;
43 44 45
static bool_t liblinphone_tester_keep_record_files = FALSE;
static bool_t liblinphone_tester_leak_detector_disabled = FALSE;
bool_t liblinphone_tester_keep_uuid = FALSE;
46
bool_t liblinphone_tester_tls_support_disabled = FALSE;
47
int manager_count = 0;
48
int leaked_objects_count = 0;
Simon Morlat's avatar
Simon Morlat committed
49 50
const MSAudioDiffParams audio_cmp_params = {10,2000};

51 52 53
const char* test_domain="sipopen.example.org";
const char* auth_domain="sip.example.org";
const char* test_username="liblinphone_tester";
54
const char* test_sha_username="liblinphone_sha_tester";
55
const char* pure_sha256_user="pure_sha256_user";
56 57 58
const char* test_password="secret";
const char* test_route="sip2.linphone.org";
const char *userhostsfile = "tester_hosts";
59
const char *file_transfer_url="https://transfer.example.org:9444/http-file-transfer-server/hft.php";
johan's avatar
johan committed
60 61
const char *lime_server_c25519_url="https://lime.wildcard1.linphone.org:8443/lime-server-c25519/lime-server.php";
const char *lime_server_c448_url="https://lime.wildcard1.linphone.org:8443/lime-server-c448/lime-server.php";
62 63
bool_t liblinphonetester_ipv6 = TRUE;
bool_t liblinphonetester_show_account_manager_logs = FALSE;
64
bool_t liblinphonetester_no_account_creator = FALSE;
65 66 67
int liblinphonetester_transport_timeout = 9000; /*milliseconds. it is set to such low value to workaround a problem with our Freebox v6 when connecting to Ipv6 addresses.
			It was found that the freebox sometimes block SYN-ACK packets, which prevents connection to be succesful.
			Thanks to the timeout, it will fallback to IPv4*/
Nicolas Michon's avatar
Nicolas Michon committed
68 69
char* message_external_body_url=NULL;
static const char *notify_content="<somexml2>blabla</somexml2>";
Gautier Pelloux-Prayer's avatar
Gautier Pelloux-Prayer committed
70

71
const char *liblinphone_tester_mire_id="Mire: Mire (synthetic moving picture)";
72
const char *liblinphone_tester_static_image_id="StaticImage: Static picture";
73

74
static void network_reachable(LinphoneCore *lc, bool_t reachable) {
75 76 77 78 79 80 81 82
	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++;
}
83 84 85 86 87 88 89 90 91 92 93 94
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;
}

95

96
LinphoneAddress * create_linphone_address(const char * domain) {
97 98 99 100
	return create_linphone_address_for_algo(domain,NULL);
}

LinphoneAddress * create_linphone_address_for_algo(const char * domain, const char* username) {
101 102 103 104 105 106 107 108 109 110 111 112 113 114
	LinphoneAddress *addr = linphone_address_new(NULL);
	if (!BC_ASSERT_PTR_NOT_NULL(addr)) return NULL;
	/* For clients who support different algorithms, their usernames must be differnet for having diffrent forms of password */
	if (username) linphone_address_set_username(addr,username);
	else linphone_address_set_username(addr,test_username);
	if (username) BC_ASSERT_STRING_EQUAL(username, linphone_address_get_username(addr));
	else BC_ASSERT_STRING_EQUAL(test_username, linphone_address_get_username(addr));
	if (!domain) domain = test_route;
	linphone_address_set_domain(addr,domain);
	BC_ASSERT_STRING_EQUAL(domain, linphone_address_get_domain(addr));
	linphone_address_set_display_name(addr, NULL);
	linphone_address_set_display_name(addr, "Mr Tester");
	BC_ASSERT_STRING_EQUAL("Mr Tester", linphone_address_get_display_name(addr));
	return addr;
115 116
}

117
static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
118
	stats* counters;
119
	ms_message("Auth info requested (deprecated callback) for user id [%s] at realm [%s]\n", username, realm);
120 121 122 123 124
	counters = get_stats(lc);
	counters->number_of_auth_info_requested++;
}

void reset_counters( stats* counters) {
125
	if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message);
Ghislain MARY's avatar
Ghislain MARY committed
126
	if (counters->last_received_info_message) linphone_info_message_unref(counters->last_received_info_message);
127 128
	if (counters->dtmf_list_received) bctbx_free(counters->dtmf_list_received);

129 130 131
	memset(counters,0,sizeof(stats));
}

132
static void setup_dns(LinphoneCore *lc, const char *path){
133 134 135 136 137 138 139
	if (strcmp(userhostsfile, "none") != 0) {
		char *dnsuserhostspath = strchr(userhostsfile, '/') ? ms_strdup(userhostsfile) : ms_strdup_printf("%s/%s", path, userhostsfile);
		sal_set_dns_user_hosts_file(linphone_core_get_sal(lc), dnsuserhostspath);
		ms_free(dnsuserhostspath);
	} else {
		bctbx_message("no dns-hosts file used");
	}
140 141
}

142 143 144 145 146 147 148 149 150 151
void configure_lc(LinphoneCore *lc, const char *path, void *user_data) {
	linphone_core_enable_ipv6(lc, liblinphonetester_ipv6);
	linphone_core_set_sip_transport_timeout(lc, liblinphonetester_transport_timeout);
	linphone_core_set_user_data(lc, user_data);

	sal_enable_test_features(linphone_core_get_sal(lc), TRUE);

	setup_dns(lc, path);
}

jehan's avatar
jehan committed
152
LinphoneCore *configure_lc_from(LinphoneCoreCbs *cbs, const char *path, LinphoneConfig *config, void *user_data) {
153
	LinphoneCore *lc;
154 155 156 157
	char *ringpath         = NULL;
	char *ringbackpath     = NULL;
	char *rootcapath       = NULL;
	char *nowebcampath     = NULL;
158

159 160 161 162 163
	// 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);
164

165
	if (config) {
166 167 168
		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);
169 170 171 172 173 174 175

		LinphoneCoreManager *mgr = (LinphoneCoreManager *)user_data;
		if (mgr && mgr->app_group_id) {
			lc = linphone_factory_create_shared_core_with_config(linphone_factory_get(), config, system_context, mgr->app_group_id, mgr->main_core);
		} else {
			lc = linphone_factory_create_core_with_config_3(linphone_factory_get(), config, system_context);
		}
176
	} else {
177
		lc = linphone_factory_create_core_3(linphone_factory_get(), NULL, liblinphone_tester_get_empty_rc(), system_context);
178 179
		linphone_core_set_ring(lc, ringpath);
		linphone_core_set_ringback(lc, ringbackpath);
180
		linphone_core_set_root_ca(lc, rootcapath);
181
	}
182 183
	if (cbs)
		linphone_core_add_callbacks(lc, cbs);
184
#ifdef VIDEO_ENABLED
185
	linphone_core_set_static_picture(lc,nowebcampath);
186
#endif
187
	configure_lc(lc, path, user_data);
188 189 190 191 192

	ms_free(ringpath);
	ms_free(ringbackpath);
	ms_free(nowebcampath);
	ms_free(rootcapath);
193 194 195
	return lc;
}

196 197 198 199 200 201 202 203 204 205 206 207
bool_t wait_for_until_interval(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int min,int max,int timout) {
	bctbx_list_t* lcs=NULL;
	bool_t result;
	if (lc_1)
		lcs=bctbx_list_append(lcs,lc_1);
	if (lc_2)
		lcs=bctbx_list_append(lcs,lc_2);
	result=wait_for_list_interval(lcs,counter,min,max,timout);
	bctbx_list_free(lcs);
	return result;
}

208
bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout) {
209
	bctbx_list_t* lcs=NULL;
210 211
	bool_t result;
	if (lc_1)
212
		lcs=bctbx_list_append(lcs,lc_1);
213
	if (lc_2)
214
		lcs=bctbx_list_append(lcs,lc_2);
215
	result=wait_for_list(lcs,counter,value,timout);
216
	bctbx_list_free(lcs);
217 218 219 220
	return result;
}

bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) {
221
	return wait_for_until(lc_1, lc_2,counter,value,10000);
222 223
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
bool_t wait_for_list_interval(bctbx_list_t* lcs,int* counter,int min, int max,int timeout_ms) {
	bctbx_list_t* iterator;
	MSTimeSpec start;

	liblinphone_tester_clock_start(&start);
	while ((counter==NULL || *counter<min || *counter>max) && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
		for (iterator=lcs;iterator!=NULL;iterator=iterator->next) {
			linphone_core_iterate((LinphoneCore*)(iterator->data));
		}
#ifdef LINPHONE_WINDOWS_DESKTOP
		{
			MSG msg;
			while (PeekMessage(&msg, NULL, 0, 0,1)){
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
#endif
		ms_usleep(20000);
	}
	if(counter && (*counter<min || *counter>max)) return FALSE;
	else return TRUE;
}

248 249
bool_t wait_for_list(bctbx_list_t* lcs,int* counter,int value,int timeout_ms) {
	bctbx_list_t* iterator;
250
	MSTimeSpec start;
251

252 253 254 255 256
	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) {
			linphone_core_iterate((LinphoneCore*)(iterator->data));
		}
Ghislain MARY's avatar
Ghislain MARY committed
257
#ifdef LINPHONE_WINDOWS_DESKTOP
258 259 260 261 262 263 264 265
		{
			MSG msg;
			while (PeekMessage(&msg, NULL, 0, 0,1)){
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
#endif
266
		ms_usleep(20000);
267 268 269 270 271
	}
	if(counter && *counter<value) return FALSE;
	else return TRUE;
}

272 273 274 275
bool_t wait_for_stun_resolution(LinphoneCoreManager *m) {
	MSTimeSpec start;
	int timeout_ms = 10000;
	liblinphone_tester_clock_start(&start);
Ghislain MARY's avatar
Ghislain MARY committed
276
	while (linphone_core_get_stun_server_addrinfo(m->lc) == NULL && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
277 278 279
		linphone_core_iterate(m->lc);
		ms_usleep(20000);
	}
Ghislain MARY's avatar
Ghislain MARY committed
280
	return linphone_core_get_stun_server_addrinfo(m->lc) != NULL;
281 282
}

283
static void set_codec_enable(LinphoneCore* lc,const char* type,int rate,bool_t enable) {
284 285
	bctbx_list_t* codecs=bctbx_list_copy(linphone_core_get_audio_codecs(lc));
	bctbx_list_t* codecs_it;
286 287
	PayloadType* pt;
	for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) {
288
		linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0);
289
	}
290
	if ((pt = linphone_core_find_payload_type(lc,type,rate,1))) {
291 292
		linphone_core_enable_payload_type(lc,pt, enable);
	}
293
	bctbx_list_free(codecs);
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
}

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;
}

309
bool_t transport_supported(LinphoneTransportType transport) {
310 311 312 313 314 315 316 317 318
	if ((transport == LinphoneTransportDtls || transport == LinphoneTransportTls) && liblinphone_tester_tls_support_disabled == TRUE) {
		return FALSE;
	} else {
		Sal *sal = sal_init(NULL);
		bool_t supported = sal_transport_available(sal,(SalTransport)transport);
		if (!supported) ms_message("TLS transport not supported, falling back to TCP if possible otherwise skipping test.");
		sal_uninit(sal);
		return  supported;
	}
319 320
}

321 322 323


#ifdef SKIP_PULSEAUDIO
Simon Morlat's avatar
Simon Morlat committed
324 325 326 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 352 353 354 355
static void avoid_pulseaudio_hack(LinphoneCoreManager *mgr){
	bctbx_list_t *cards = linphone_core_get_sound_devices_list(mgr->lc);
	bctbx_list_t *it;
	bool_t capture_set = FALSE, playback_set = FALSE;
	bool_t pulseaudio_found = FALSE;
	for (it = cards; it != NULL ; it = it->next){
		const char * card_id = (const char *)it->data;
		if (strstr(card_id, "PulseAudio") != NULL) {
			pulseaudio_found = TRUE;
			continue;
		}
		if (!capture_set && linphone_core_sound_device_can_capture(mgr->lc, card_id)){
			capture_set = TRUE;
			linphone_core_set_capture_device(mgr->lc, card_id);
		}
		if (!playback_set && linphone_core_sound_device_can_playback(mgr->lc, card_id)){
			playback_set = TRUE;
			linphone_core_set_playback_device(mgr->lc, card_id);
			linphone_core_set_ringer_device(mgr->lc, card_id);
		}
		if (playback_set && capture_set){
			if (pulseaudio_found) ms_warning("PulseAudio is not used in liblinphone_tester because of internal random crashes or hangs.");
			break;
		}
	}
	if (!playback_set || !capture_set){
		ms_error("Could not find soundcard other than pulseaudio to use during tests. Some tests may crash or hang.");
	}
	bctbx_list_free(cards);
}
#endif

356 357 358
void linphone_core_manager_setup_dns(LinphoneCoreManager *mgr){
	setup_dns(mgr->lc, bc_tester_get_resource_dir_prefix());
}
Simon Morlat's avatar
Simon Morlat committed
359

360 361
LinphoneCore *linphone_core_manager_configure_lc(LinphoneCoreManager *mgr) {
	LinphoneCore *lc;
362
	char *filepath = mgr->rc_path ? bctbx_strdup_printf("%s/%s", bc_tester_get_resource_dir_prefix(), mgr->rc_path) : NULL;
jehan's avatar
jehan committed
363 364 365 366 367 368 369
	if (filepath && bctbx_file_exist(filepath) != 0) {
		ms_fatal("Could not find file %s in path %s, did you configured resources directory correctly?", mgr->rc_path, bc_tester_get_resource_dir_prefix());
	}
	LinphoneConfig * config = linphone_factory_create_config_with_factory(linphone_factory_get(), NULL, filepath);
	linphone_config_set_string(config, "storage", "backend", "sqlite3");
	linphone_config_set_string(config, "storage", "uri", mgr->database_path);
	linphone_config_set_string(config, "lime", "x3dh_db_path", mgr->lime_database_path);
370
	lc = configure_lc_from(mgr->cbs, bc_tester_get_resource_dir_prefix(), config, mgr);
jehan's avatar
jehan committed
371
	linphone_config_unref(config);
372 373 374 375 376 377 378 379 380 381 382 383
	return lc;
}

void linphone_core_manager_configure(LinphoneCoreManager *mgr) {
	LinphoneImNotifPolicy *im_notif_policy;
	char *hellopath = bc_tester_res("sounds/hello8000.wav");
	char *filepath = mgr->rc_path ? bctbx_strdup_printf("%s/%s", bc_tester_get_resource_dir_prefix(), mgr->rc_path) : NULL;
	if (filepath && bctbx_file_exist(filepath) != 0) {
		ms_fatal("Could not find file %s in path %s, did you configured resources directory correctly?", mgr->rc_path, bc_tester_get_resource_dir_prefix());
	}

	mgr->lc = linphone_core_manager_configure_lc(mgr);
384

385
	linphone_core_manager_check_accounts(mgr);
Ghislain MARY's avatar
Ghislain MARY committed
386
	im_notif_policy = linphone_core_get_im_notif_policy(mgr->lc);
387 388 389 390 391 392
	if (im_notif_policy != NULL) {
		/* The IM notification policy can be NULL at this point in case of remote provisioning. */
		linphone_im_notif_policy_clear(im_notif_policy);
		linphone_im_notif_policy_set_send_is_composing(im_notif_policy, TRUE);
		linphone_im_notif_policy_set_recv_is_composing(im_notif_policy, TRUE);
	}
393

Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
394
#if TARGET_OS_IPHONE
395 396
	linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device");
	linphone_core_set_ringback(mgr->lc, NULL);
397 398
#elif __QNX__
	linphone_core_set_playback_device(mgr->lc, "QSA: voice");
399
#elif defined(SKIP_PULSEAUDIO)
Simon Morlat's avatar
Simon Morlat committed
400 401 402 403 404 405
	{
		/* Special trick for linux. Pulseaudio has random hangs, deadlocks or abort while executing test suites.
		 * It never happens in the linphone app.
		 * So far we could not identify something bad in our pulseaudio usage. As a workaround, we disable pulseaudio for the tests.*/
		avoid_pulseaudio_hack(mgr);
	}
406 407
#endif

408 409 410 411
#ifdef VIDEO_ENABLED
	{
		MSWebCam *cam;

412
		cam = ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(linphone_core_get_ms_factory(mgr->lc)), "Mire: Mire (synthetic moving picture)");
413

414 415 416 417 418 419 420
		//Usefull especially for encoders not supporting qcif
		#ifdef __ANDROID__
			MSVideoSize vsize = MS_VIDEO_SIZE_CIF;
			linphone_core_set_preferred_video_size(mgr->lc, vsize);
		#endif


421
		if (cam == NULL) {
Simon Morlat's avatar
Simon Morlat committed
422 423 424
			MSWebCamDesc *desc = ms_mire_webcam_desc_get();
			if (desc){
				cam=ms_web_cam_new(desc);
425
				ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(linphone_core_get_ms_factory(mgr->lc)), cam);
Simon Morlat's avatar
Simon Morlat committed
426
			}
427 428 429 430
		}
	}
#endif

jehan's avatar
jehan committed
431

432 433
	linphone_core_set_play_file(mgr->lc,hellopath); /*is also used when in pause*/
	ms_free(hellopath);
434

435
	if( manager_count >= 2){
436
		char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",bc_tester_get_writable_dir_prefix(),mgr->lc);
437
		ms_message("Manager for '%s' using files", mgr->rc_path ? mgr->rc_path : "--");
438
		linphone_core_set_use_files(mgr->lc, TRUE);
439 440
		linphone_core_set_record_file(mgr->lc,recordpath);
		ms_free(recordpath);
441
	}
442

443
	linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix());
444
	/*for now, we need the periodical updates facility to compute bandwidth measurements correctly during tests*/
445
	linphone_core_enable_send_call_stats_periodical_updates(mgr->lc, TRUE);
446

447 448
	// clean
	if (filepath) bctbx_free(filepath);
Ghislain MARY's avatar
Ghislain MARY committed
449
}
450

Ghislain MARY's avatar
Ghislain MARY committed
451
static void generate_random_database_path (LinphoneCoreManager *mgr) {
452 453 454 455 456
	char random_id[32];
	belle_sip_random_token(random_id, sizeof random_id);
	char *database_path_format = bctbx_strdup_printf("linphone_%s.db", random_id);
	mgr->database_path = bc_tester_file(database_path_format);
	bctbx_free(database_path_format);
jehan's avatar
jehan committed
457 458 459
	database_path_format = bctbx_strdup_printf("lime_%s.db", random_id);
	mgr->lime_database_path = bc_tester_file(database_path_format);
	bctbx_free(database_path_format);
460 461
}

462 463 464 465 466 467 468 469
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic push
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
470
void linphone_core_manager_init2(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias) {
471
	mgr->number_of_bcunit_error_at_creation =  bc_get_number_of_failures();
472 473 474 475 476 477 478 479 480 481 482 483 484
	mgr->cbs = linphone_factory_create_core_cbs(linphone_factory_get());
	linphone_core_cbs_set_registration_state_changed(mgr->cbs, registration_state_changed);
	linphone_core_cbs_set_auth_info_requested(mgr->cbs, auth_info_requested);
	linphone_core_cbs_set_call_state_changed(mgr->cbs, call_state_changed);
	linphone_core_cbs_set_message_received(mgr->cbs, message_received);
	linphone_core_cbs_set_is_composing_received(mgr->cbs, is_composing_received);
	linphone_core_cbs_set_new_subscription_requested(mgr->cbs, new_subscription_requested);
	linphone_core_cbs_set_notify_presence_received(mgr->cbs, notify_presence_received);
	linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(mgr->cbs, notify_presence_received_for_uri_or_tel);
	linphone_core_cbs_set_transfer_state_changed(mgr->cbs, linphone_transfer_state_changed);
	linphone_core_cbs_set_info_received(mgr->cbs, info_message_received);
	linphone_core_cbs_set_subscription_state_changed(mgr->cbs, linphone_subscription_state_change);
	linphone_core_cbs_set_notify_received(mgr->cbs, linphone_notify_received);
485
	linphone_core_cbs_set_subscribe_received(mgr->cbs, linphone_subscribe_received);
486 487 488 489 490 491
	linphone_core_cbs_set_publish_state_changed(mgr->cbs, linphone_publish_state_changed);
	linphone_core_cbs_set_configuring_status(mgr->cbs, linphone_configuration_status);
	linphone_core_cbs_set_call_encryption_changed(mgr->cbs, linphone_call_encryption_changed);
	linphone_core_cbs_set_network_reachable(mgr->cbs, network_reachable);
	linphone_core_cbs_set_dtmf_received(mgr->cbs, dtmf_received);
	linphone_core_cbs_set_call_stats_updated(mgr->cbs, call_stats_updated);
492
	linphone_core_cbs_set_global_state_changed(mgr->cbs, global_state_changed);
493
	linphone_core_cbs_set_message_sent(mgr->cbs, liblinphone_tester_chat_room_msg_sent);
494 495
	linphone_core_cbs_set_first_call_started(mgr->cbs, first_call_started);
	linphone_core_cbs_set_last_call_ended(mgr->cbs, last_call_ended);
496 497
	linphone_core_cbs_set_audio_device_changed(mgr->cbs, audio_device_changed);
	linphone_core_cbs_set_audio_devices_list_updated(mgr->cbs, audio_devices_list_updated);
498
	linphone_core_cbs_set_imee_user_registration(mgr->cbs, liblinphone_tester_x3dh_user_created);
499 500 501 502 503

	mgr->phone_alias = phone_alias ? ms_strdup(phone_alias) : NULL;

	reset_counters(&mgr->stat);
	manager_count++;
504
}
505

506 507 508
void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias) {
	linphone_core_manager_init2(mgr, rc_file, phone_alias);
	if (rc_file) mgr->rc_path = ms_strdup_printf("rcfiles/%s", rc_file);
Ghislain MARY's avatar
Ghislain MARY committed
509
	generate_random_database_path(mgr);
510
	linphone_core_manager_configure(mgr);
511
}
512 513 514 515 516 517 518 519 520 521 522 523 524 525

void linphone_core_manager_init_shared(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias, LinphoneCoreManager *mgr_to_copy) {
	linphone_core_manager_init2(mgr, rc_file, phone_alias);

	if (mgr_to_copy == NULL) {
		if (rc_file) mgr->rc_path = ms_strdup_printf("rcfiles/%s", rc_file);
		generate_random_database_path(mgr);
	} else {
		mgr->rc_path = ms_strdup(mgr_to_copy->rc_path);
		mgr->database_path = ms_strdup(mgr_to_copy->database_path);
		mgr->lime_database_path = ms_strdup(mgr_to_copy->lime_database_path);
	}
	linphone_core_manager_configure(mgr);
}
526 527 528
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic pop
#endif
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
529

530
void linphone_core_manager_start(LinphoneCoreManager *mgr, bool_t check_for_proxies) {
531 532
	LinphoneProxyConfig* proxy;
	int proxy_count;
533

534 535 536
	if (linphone_core_start(mgr->lc) == -1) {
		ms_error("Core [%p] failed to start", mgr->lc);
	}
537

538
	/*BC_ASSERT_EQUAL(bctbx_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count, int, "%d");*/
539
	if (check_for_proxies){ /**/
Ghislain MARY's avatar
Ghislain MARY committed
540
		proxy_count=(int)bctbx_list_size(linphone_core_get_proxy_config_list(mgr->lc));
541
	}else{
542
		proxy_count=0;
543 544 545
		/*this is to prevent registration to go on*/
		linphone_core_set_network_reachable(mgr->lc, FALSE);
	}
546

547 548 549
	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
550
									proxy_count,(REGISTER_TIMEOUT * 1000 * proxy_count));
551 552 553 554
		if( !success ){
			ms_error("Did not register after %d seconds for %d proxies", REGISTER_TIMEOUT, proxy_count);
		}
	}
555
	BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count, int, "%d");
556 557
	enable_codec(mgr->lc,"PCMU",8000);

558
	proxy = linphone_core_get_default_proxy_config(mgr->lc);
559
	if (proxy) {
560
		if (mgr->identity){
Simon Morlat's avatar
Simon Morlat committed
561
			linphone_address_unref(mgr->identity);
562
		}
563
		mgr->identity = linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
564 565
		linphone_address_clean(mgr->identity);
	}
566

567
	linphone_core_manager_wait_for_stun_resolution(mgr);
568 569 570 571
	if (!check_for_proxies){
		/*now that stun server resolution is done, we can start registering*/
		linphone_core_set_network_reachable(mgr->lc, TRUE);
	}
572

573 574
}

575
LinphoneCoreManager* linphone_core_manager_create2(const char* rc_file, const char* phone_alias) {
576
	LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
577
	linphone_core_manager_init(manager, rc_file, phone_alias);
578 579 580 581 582 583 584
	return manager;
}

LinphoneCoreManager* linphone_core_manager_create(const char* rc_file) {
	return linphone_core_manager_create2(rc_file, NULL);
}

DanmeiChen's avatar
DanmeiChen committed
585 586 587
LinphoneCoreManager* linphone_core_manager_new4(const char* rc_file, int check_for_proxies, const char* phone_alias, const char* contact_params, int expires) {
	/* This function is for testing purposes. */
	LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
588

DanmeiChen's avatar
DanmeiChen committed
589 590 591 592 593 594 595
	linphone_core_manager_init(manager, rc_file, phone_alias);
	linphone_proxy_config_set_contact_parameters(linphone_core_get_default_proxy_config(manager->lc), contact_params);
	linphone_proxy_config_set_expires(linphone_core_get_default_proxy_config(manager->lc), expires);
	linphone_core_manager_start(manager, check_for_proxies);
	return manager;
}

596
LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, bool_t check_for_proxies, const char* phone_alias) {
597
	LinphoneCoreManager *manager = linphone_core_manager_create2(rc_file, phone_alias);
598
	linphone_core_manager_start(manager, check_for_proxies);
599 600 601
	return manager;
}

602
LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, bool_t check_for_proxies) {
603
	return linphone_core_manager_new3(rc_file, check_for_proxies, NULL);
604 605
}

606
LinphoneCoreManager *linphone_core_manager_new(const char *rc_file) {
607 608 609 610
	return linphone_core_manager_new2(rc_file, TRUE);
}


611 612 613 614 615 616 617 618 619 620 621 622 623 624
/**
 * Create a LinphoneCoreManager that holds a shared Core.
 * mgr_to_copy is used to create a second LinphoneCoreManager with the same identity.
 * If mgr_to_copy has a value, rc_file parameter is ignored.
 */
LinphoneCoreManager* linphone_core_manager_create_shared(const char *rc_file, const char *app_group_id, bool_t main_core, LinphoneCoreManager *mgr_to_copy) {
	LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
	manager->app_group_id = ms_strdup(app_group_id);
	manager->main_core = main_core;
	linphone_core_manager_init_shared(manager, rc_file, NULL, mgr_to_copy);
	return manager;
}

void linphone_core_manager_stop(LinphoneCoreManager *mgr) {
625
	if (mgr->lc) {
626
		const char *record_file = linphone_core_get_record_file(mgr->lc);
627
		if (!liblinphone_tester_keep_record_files && record_file && ortp_file_exist(record_file)==0) {
628 629 630 631 632 633 634
			if ((bc_get_number_of_failures() - mgr->number_of_bcunit_error_at_creation)>0) {
				ms_error("Test has failed, keeping recorded file [%s]", record_file);
			}
			else {
				unlink(record_file);
			}
		}
635
		linphone_core_stop(mgr->lc);
Ghislain MARY's avatar
Ghislain MARY committed
636
		linphone_core_unref(mgr->lc);
637
		mgr->lc = NULL;
638 639 640
	}
}

Paul Cartier's avatar
Paul Cartier committed
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
void linphone_core_manager_uninit_after_stop_async(LinphoneCoreManager *mgr) {
	if (mgr->lc) {
		const char *record_file = linphone_core_get_record_file(mgr->lc);
		if (!liblinphone_tester_keep_record_files && record_file && ortp_file_exist(record_file)==0) {
			if ((bc_get_number_of_failures() - mgr->number_of_bcunit_error_at_creation)>0) {
				ms_error("Test has failed, keeping recorded file [%s]", record_file);
			}
			else {
				unlink(record_file);
			}
		}
		linphone_core_unref(mgr->lc);
		mgr->lc = NULL;
	}
}

657 658
void linphone_core_manager_reinit(LinphoneCoreManager *mgr) {
	char *uuid = NULL;
659
	if (mgr->lc) {
660 661
		if (lp_config_get_string(linphone_core_get_config(mgr->lc), "misc", "uuid", NULL))
			uuid = bctbx_strdup(lp_config_get_string(linphone_core_get_config(mgr->lc), "misc", "uuid", NULL));
662
		linphone_core_set_network_reachable(mgr->lc, FALSE); // to avoid unregister
Ghislain MARY's avatar
Ghislain MARY committed
663
		linphone_core_unref(mgr->lc);
664
	}
665 666
	linphone_core_manager_configure(mgr);
	reset_counters(&mgr->stat);
667 668
	// Make sure gruu is preserved
	lp_config_set_string(linphone_core_get_config(mgr->lc), "misc", "uuid", uuid);
669
	if (uuid)
670
		bctbx_free(uuid);
671 672 673
}

void linphone_core_manager_restart(LinphoneCoreManager *mgr, bool_t check_for_proxies) {
674
	linphone_core_manager_reinit(mgr);
675 676 677
	linphone_core_manager_start(mgr, check_for_proxies);
}

678
void linphone_core_manager_uninit(LinphoneCoreManager *mgr) {
679
	int old_log_level = linphone_core_get_log_level_mask();
680
	linphone_core_set_log_level(ORTP_ERROR);
681 682 683
	if (mgr->phone_alias) {
		ms_free(mgr->phone_alias);
	}
684
	if (mgr->identity) {
Simon Morlat's avatar
Simon Morlat committed
685
		linphone_address_unref(mgr->identity);
686
	}
687
	if (mgr->rc_path)
Ghislain MARY's avatar
Ghislain MARY committed
688
		bctbx_free(mgr->rc_path);
689 690
	if (mgr->database_path) {
		unlink(mgr->database_path);
jehan's avatar
jehan committed
691 692 693 694 695
		bc_free(mgr->database_path);
	}
	if (mgr->lime_database_path) {
		unlink(mgr->lime_database_path);
		bc_free(mgr->lime_database_path);
696
	}
697 698
	if (mgr->app_group_id)
		bctbx_free(mgr->app_group_id);
699

700 701
	if (mgr->cbs)
		linphone_core_cbs_unref(mgr->cbs);
702

703 704
	reset_counters(&mgr->stat);

705
	manager_count--;
706
	linphone_core_set_log_level_mask(old_log_level);
707
}
708

709 710 711 712 713 714 715 716 717 718
void linphone_core_manager_wait_for_stun_resolution(LinphoneCoreManager *mgr) {
	LinphoneNatPolicy *nat_policy = linphone_core_get_nat_policy(mgr->lc);
	if ((nat_policy != NULL) && (linphone_nat_policy_get_stun_server(nat_policy) != NULL) &&
		(linphone_nat_policy_stun_enabled(nat_policy) || linphone_nat_policy_turn_enabled(nat_policy)) &&
		(linphone_nat_policy_ice_enabled(nat_policy))) {
		/*before we go, ensure that the stun server is resolved, otherwise all ice related test will fail*/
		BC_ASSERT_TRUE(wait_for_stun_resolution(mgr));
	}
}

719
void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
720
	if (mgr->lc && linphone_core_get_global_state(mgr->lc) != LinphoneGlobalOff && !linphone_core_is_network_reachable(mgr->lc)) {
721 722 723 724
		int previousNbRegistrationOk = mgr->stat.number_of_LinphoneRegistrationOk;
		linphone_core_set_network_reachable(mgr->lc, TRUE);
		wait_for_until(mgr->lc, NULL, &mgr->stat.number_of_LinphoneRegistrationOk, previousNbRegistrationOk + 1, 2000);
	}
725
	linphone_core_manager_stop(mgr);
726
	linphone_core_manager_uninit(mgr);
727 728 729
	ms_free(mgr);
}

Paul Cartier's avatar
Paul Cartier committed
730 731 732 733 734 735 736 737 738 739 740
void linphone_core_manager_destroy_after_stop_async(LinphoneCoreManager* mgr) {
	if (mgr->lc && !linphone_core_is_network_reachable(mgr->lc)) {
		int previousNbRegistrationOk = mgr->stat.number_of_LinphoneRegistrationOk;
		linphone_core_set_network_reachable(mgr->lc, TRUE);
		wait_for_until(mgr->lc, NULL, &mgr->stat.number_of_LinphoneRegistrationOk, previousNbRegistrationOk + 1, 2000);
	}
	linphone_core_manager_uninit_after_stop_async(mgr);
	linphone_core_manager_uninit(mgr);
	ms_free(mgr);
}

741 742
void linphone_core_manager_delete_chat_room (LinphoneCoreManager *mgr, LinphoneChatRoom *cr, bctbx_list_t *coresList) {
	stats mgrStats = mgr->stat;
743 744 745 746
	if (cr) {
		linphone_core_delete_chat_room(mgr->lc, cr);
		BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneChatRoomStateDeleted, mgrStats.number_of_LinphoneChatRoomStateDeleted + 1, 10000));
	}
747 748
}

749
int liblinphone_tester_ipv6_available(void){
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
	if (liblinphonetester_ipv6) {
		struct addrinfo *ai=bctbx_ip_address_to_addrinfo(AF_INET6,SOCK_STREAM,"2a01:e00::2",53);
		if (ai){
			struct sockaddr_storage ss;
			struct addrinfo src;
			socklen_t slen=sizeof(ss);
			char localip[128];
			int port=0;
			belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444);
			src.ai_addr=(struct sockaddr*) &ss;
			src.ai_addrlen=slen;
			bctbx_addrinfo_to_ip_address(&src,localip, sizeof(localip),&port);
			freeaddrinfo(ai);
			return strcmp(localip,"::1")!=0;
		}
765 766 767 768
	}
	return FALSE;
}

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
int liblinphone_tester_ipv4_available(void){
	struct addrinfo *ai=bctbx_ip_address_to_addrinfo(AF_INET,SOCK_STREAM,"212.27.40.240",53);
	if (ai){
		struct sockaddr_storage ss;
		struct addrinfo src;
		socklen_t slen=sizeof(ss);
		char localip[128];
		int port=0;
		belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444);
		src.ai_addr=(struct sockaddr*) &ss;
		src.ai_addrlen=slen;
		bctbx_addrinfo_to_ip_address(&src,localip, sizeof(localip),&port);
		freeaddrinfo(ai);
		return strcmp(localip,"127.0.0.1")!=0;
	}
	return FALSE;
}


788 789 790 791
void liblinphone_tester_keep_accounts( int keep ){
	liblinphone_tester_keep_accounts_flag = keep;
}

792 793 794 795
void liblinphone_tester_keep_recorded_files(int keep){
	liblinphone_tester_keep_record_files = keep;
}

796 797 798 799
void liblinphone_tester_disable_leak_detector(int disabled){
	liblinphone_tester_leak_detector_disabled = disabled;
}

800 801 802
void liblinphone_tester_clear_accounts(void){
	account_manager_destroy();
}
803

Simon Morlat's avatar
Simon Morlat committed
804
static int linphone_core_manager_get_max_audio_bw_base(const int array[],int array_size) {
805 806 807 808 809 810 811
	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
812 813 814 815 816 817 818 819
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;
}

820 821 822 823 824 825 826 827
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));
}
828

Simon Morlat's avatar
Simon Morlat committed
829 830 831 832 833 834 835 836 837
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));
}

838
void liblinphone_tester_before_each(void) {
839 840 841 842
	if (!liblinphone_tester_leak_detector_disabled){
		belle_sip_object_enable_leak_detector(TRUE);
		leaked_objects_count = belle_sip_object_get_object_count();
	}
843 844
}

845 846
static char* all_leaks_buffer = NULL;

847
void liblinphone_tester_after_each(void) {
Simon Morlat's avatar
Simon Morlat committed
848
	linphone_factory_clean();
849 850 851
	if (!liblinphone_tester_leak_detector_disabled){
		int leaked_objects = belle_sip_object_get_object_count() - leaked_objects_count;
		if (leaked_objects > 0) {
852
			char* format = ms_strdup_printf("%d object%s leaked in suite [%s] test [%s], please fix that!",
853
											leaked_objects, leaked_objects>1?"s were":" was",
854
											bc_tester_current_suite_name(), bc_tester_current_test_name());
855
			belle_sip_object_dump_active_objects();
856
			belle_sip_object_flush_active_objects();
857
			bc_tester_printf(ORTP_MESSAGE, format);
858 859 860
			ms_error("%s", format);

			all_leaks_buffer = ms_strcat_printf(all_leaks_buffer, "\n%s", format);
Ghislain MARY's avatar
Ghislain MARY committed
861
			ms_free(format);
862
		}
863

864 865 866 867 868 869 870 871 872 873 874
		// prevent any future leaks
		{
			const char **tags = bc_tester_current_test_tags();
			int leaks_expected =
				(tags && ((tags[0] && !strcmp(tags[0], "LeaksMemory")) || (tags[1] && !strcmp(tags[1], "LeaksMemory"))));
			// if the test is NOT marked as leaking memory and it actually is, we should make it fail
			if (!leaks_expected && leaked_objects > 0) {
				BC_FAIL("This test is leaking memory!");
				// and reciprocally
			} else if (leaks_expected && leaked_objects == 0) {
				BC_FAIL("This test is not leaking anymore, please remove LeaksMemory tag!");
875
			}
876
		}
877 878
	}

879
	if (manager_count != 0) {
880
		ms_fatal("%d Linphone core managers are still alive!", manager_count);
881 882
	}
}
883

884 885 886
void liblinphone_tester_uninit(void) {
	// show all leaks that happened during the test
	if (all_leaks_buffer) {
887
		bc_tester_printf(ORTP_MESSAGE, all_leaks_buffer);
888
		ms_free(all_leaks_buffer);
889
		all_leaks_buffer = NULL;
890 891
	}
	bc_tester_uninit();
892
	bctbx_uninit_logger();
893
}
894

895
static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStreamType stream_type) {
896
	MediaStream *ms;