tester.c 30.2 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
#include <bctoolbox/tester.h>
24 25 26 27

#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic push
#endif
28
#ifndef _MSC_VER
29
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
30
#endif
31

32 33 34
#ifdef HAVE_GTK
#include <gtk/gtk.h>
#endif
35 36 37 38 39

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

Ghislain MARY's avatar
Ghislain MARY committed
40 41 42
#if _WIN32
#define unlink _unlink
#endif
43

44

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

52 53 54 55 56 57
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";
58
bool_t liblinphonetester_ipv6 = FALSE;
Gautier Pelloux-Prayer's avatar
Gautier Pelloux-Prayer committed
59

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

62
static void network_reachable(LinphoneCore *lc, bool_t reachable) {
63 64 65 66 67 68 69 70
	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++;
}
71 72 73 74 75 76 77 78 79 80 81 82
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;
}

83

84 85
LinphoneAddress * create_linphone_address(const char * domain) {
	LinphoneAddress *addr = linphone_address_new(NULL);
86
	if (!BC_ASSERT_PTR_NOT_NULL(addr)) return NULL;
87
	linphone_address_set_username(addr,test_username);
88
	BC_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr));
89 90
	if (!domain) domain= test_route;
	linphone_address_set_domain(addr,domain);
91
	BC_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr));
92 93
	linphone_address_set_display_name(addr, NULL);
	linphone_address_set_display_name(addr, "Mr Tester");
94
	BC_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr));
95 96 97 98 99 100
	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"
101 102
			   ,username
			   ,realm);
103 104 105 106 107
	counters = get_stats(lc);
	counters->number_of_auth_info_requested++;
}

void reset_counters( stats* counters) {
108
	if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message);
109
	if (counters->last_received_info_message) linphone_info_message_destroy(counters->last_received_info_message);
110 111 112
	memset(counters,0,sizeof(stats));
}

113
LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) {
114
	LinphoneCore* lc;
115 116 117 118 119 120 121
	LpConfig* config = NULL;
	char *filepath         = NULL;
	char *ringpath         = NULL;
	char *ringbackpath     = NULL;
	char *rootcapath       = NULL;
	char *dnsuserhostspath = NULL;
	char *nowebcampath     = NULL;
jehan's avatar
jehan committed
122
	char *chatdb     = NULL;
123 124 125 126

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

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


135 136 137 138 139
	// 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);
140
	dnsuserhostspath = ms_strdup_printf("%s/%s", path, userhostsfile);
141 142


143 144 145 146 147 148
	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 {
149
		lc = linphone_core_new(v_table,NULL,(filepath!=NULL&&filepath[0]!='\0') ? filepath : NULL, user_data);
150 151 152 153 154

		linphone_core_set_ring(lc, ringpath);
		linphone_core_set_ringback(lc, ringbackpath);
		linphone_core_set_root_ca(lc,rootcapath);
	}
jehan's avatar
jehan committed
155
	chatdb = ms_strdup_printf("%s/messages-%p.db",bc_tester_get_writable_dir_prefix(),lc);
156

157
	linphone_core_enable_ipv6(lc, liblinphonetester_ipv6);
158

159 160
	sal_enable_test_features(lc->sal,TRUE);
	sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath);
161
#ifdef VIDEO_ENABLED
162
	linphone_core_set_static_picture(lc,nowebcampath);
163
#endif
164

jehan's avatar
jehan committed
165
	linphone_core_set_chat_database_path(lc, chatdb);
166

167 168 169 170 171
	ms_free(ringpath);
	ms_free(ringbackpath);
	ms_free(nowebcampath);
	ms_free(rootcapath);
	ms_free(dnsuserhostspath);
jehan's avatar
jehan committed
172
	ms_free(chatdb);
173 174 175 176 177

	if( filepath ) ms_free(filepath);

	if( config ) lp_config_unref(config);

178 179 180 181 182
	return lc;
}


bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout) {
183
	bctbx_list_t* lcs=NULL;
184 185
	bool_t result;
	if (lc_1)
186
		lcs=bctbx_list_append(lcs,lc_1);
187
	if (lc_2)
188
		lcs=bctbx_list_append(lcs,lc_2);
189
	result=wait_for_list(lcs,counter,value,timout);
190
	bctbx_list_free(lcs);
191 192 193 194
	return result;
}

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

198 199
bool_t wait_for_list(bctbx_list_t* lcs,int* counter,int value,int timeout_ms) {
	bctbx_list_t* iterator;
200
	MSTimeSpec start;
201

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

227 228 229 230
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
231
	while (linphone_core_get_stun_server_addrinfo(m->lc) == NULL && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
232 233 234
		linphone_core_iterate(m->lc);
		ms_usleep(20000);
	}
Ghislain MARY's avatar
Ghislain MARY committed
235
	return linphone_core_get_stun_server_addrinfo(m->lc) != NULL;
236 237
}

238
static void set_codec_enable(LinphoneCore* lc,const char* type,int rate,bool_t enable) {
239 240
	bctbx_list_t* codecs=bctbx_list_copy(linphone_core_get_audio_codecs(lc));
	bctbx_list_t* codecs_it;
241 242
	PayloadType* pt;
	for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) {
243
		linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0);
244
	}
245
	if ((pt = linphone_core_find_payload_type(lc,type,rate,1))) {
246 247
		linphone_core_enable_payload_type(lc,pt, enable);
	}
248
	bctbx_list_free(codecs);
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
}

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

264
bool_t transport_supported(LinphoneTransportType transport) {
265
	Sal *sal = sal_init(NULL);
266
	bool_t supported = sal_transport_available(sal,(SalTransport)transport);
267
	if (!supported) ms_message("TLS transport not supported, falling back to TCP if possible otherwise skipping test.");
268
	sal_uninit(sal);
269
	return supported;
270 271
}

272 273 274
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic push
#endif
275 276 277
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
278
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
279
#endif
280
void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias) {
281
	char *rc_path = NULL;
jehan's avatar
jehan committed
282
	char *hellopath = bc_tester_res("sounds/hello8000.wav");
283
	mgr->number_of_bcunit_error_at_creation =  bc_get_number_of_failures();
284 285 286 287 288 289 290 291
	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;
292
	mgr->v_table.notify_presence_received_for_uri_or_tel=notify_presence_received_for_uri_or_tel;
293 294 295 296 297 298
	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
299
	mgr->v_table.call_encryption_changed=linphone_call_encryption_changed;
300
	mgr->v_table.network_reachable=network_reachable;
301
	mgr->v_table.dtmf_received=dtmf_received;
302
	mgr->v_table.call_stats_updated=call_stats_updated;
303

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

306 307
	reset_counters(&mgr->stat);
	if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file);
308
	mgr->lc=configure_lc_from(&mgr->v_table, bc_tester_get_resource_dir_prefix(), rc_path, mgr);
309
	linphone_core_manager_check_accounts(mgr);
310

311 312
	manager_count++;

Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
313
#if TARGET_OS_IPHONE
314 315
	linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device");
	linphone_core_set_ringback(mgr->lc, NULL);
316 317
#elif __QNX__
	linphone_core_set_playback_device(mgr->lc, "QSA: voice");
318 319
#endif

320 321 322 323
#ifdef VIDEO_ENABLED
	{
		MSWebCam *cam;

324
		cam = ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(mgr->lc->factory), "Mire: Mire (synthetic moving picture)");
325 326

		if (cam == NULL) {
Simon Morlat's avatar
Simon Morlat committed
327 328 329
			MSWebCamDesc *desc = ms_mire_webcam_desc_get();
			if (desc){
				cam=ms_web_cam_new(desc);
330
				ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(mgr->lc->factory), cam);
Simon Morlat's avatar
Simon Morlat committed
331
			}
332 333 334 335
		}
	}
#endif

jehan's avatar
jehan committed
336

337 338
	linphone_core_set_play_file(mgr->lc,hellopath); /*is also used when in pause*/
	ms_free(hellopath);
339

340
	if( manager_count >= 2){
341
		char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",bc_tester_get_writable_dir_prefix(),mgr->lc);
342
		ms_message("Manager for '%s' using files", rc_file ? rc_file : "--");
343
		linphone_core_set_use_files(mgr->lc, TRUE);
344 345
		linphone_core_set_record_file(mgr->lc,recordpath);
		ms_free(recordpath);
346
	}
347

348
	linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix());
349 350
	/*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);
351

352 353
	if (rc_path) ms_free(rc_path);
}
354 355 356
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic pop
#endif
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
357

358
void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies) {
359 360
	LinphoneProxyConfig* proxy;
	int proxy_count;
361

362
	/*BC_ASSERT_EQUAL(bctbx_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count, int, "%d");*/
363
	if (check_for_proxies){ /**/
Ghislain MARY's avatar
Ghislain MARY committed
364
		proxy_count=(int)bctbx_list_size(linphone_core_get_proxy_config_list(mgr->lc));
365
	}else{
366
		proxy_count=0;
367 368 369
		/*this is to prevent registration to go on*/
		linphone_core_set_network_reachable(mgr->lc, FALSE);
	}
370

371 372 373
	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
374
									proxy_count,(REGISTER_TIMEOUT * 1000 * proxy_count));
375 376 377 378
		if( !success ){
			ms_error("Did not register after %d seconds for %d proxies", REGISTER_TIMEOUT, proxy_count);
		}
	}
379
	BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count, int, "%d");
380 381
	enable_codec(mgr->lc,"PCMU",8000);

382
	proxy = linphone_core_get_default_proxy_config(mgr->lc);
383
	if (proxy) {
384 385 386
		if (mgr->identity){
			linphone_address_destroy(mgr->identity);
		}
387
		mgr->identity = linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
388 389
		linphone_address_clean(mgr->identity);
	}
390

391
	linphone_core_manager_wait_for_stun_resolution(mgr);
392 393 394 395
	if (!check_for_proxies){
		/*now that stun server resolution is done, we can start registering*/
		linphone_core_set_network_reachable(mgr->lc, TRUE);
	}
396

397 398
}

399
LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, int check_for_proxies, const char* phone_alias) {
400
	int old_log_level = ortp_get_log_level_mask(NULL);
401
	LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
402
	linphone_core_set_log_level(ORTP_ERROR);
403 404
	linphone_core_manager_init(manager, rc_file, phone_alias);
	linphone_core_manager_start(manager, check_for_proxies);
405
	linphone_core_set_log_level(old_log_level);
406 407 408
	return manager;
}

409
LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) {
410
	return linphone_core_manager_new3(rc_file, check_for_proxies, NULL);
411 412
}

413 414 415 416 417
LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) {
	return linphone_core_manager_new2(rc_file, TRUE);
}


418 419 420 421 422 423 424
void linphone_core_manager_stop(LinphoneCoreManager *mgr){
	if (mgr->lc) {
		linphone_core_destroy(mgr->lc);
		mgr->lc=NULL;
	}
}

425
void linphone_core_manager_uninit(LinphoneCoreManager *mgr) {
426 427
	int old_log_level = ortp_get_log_level_mask(NULL);
	linphone_core_set_log_level(ORTP_ERROR);
428 429 430
	if (mgr->phone_alias) {
		ms_free(mgr->phone_alias);
	}
431 432 433
	if (mgr->stat.last_received_chat_message) {
		linphone_chat_message_unref(mgr->stat.last_received_chat_message);
	}
434
	if (mgr->stat.last_received_info_message) linphone_info_message_destroy(mgr->stat.last_received_info_message);
Simon Morlat's avatar
Simon Morlat committed
435 436
	if (mgr->lc){
		const char *record_file=linphone_core_get_record_file(mgr->lc);
437
		char *chatdb = ms_strdup(linphone_core_get_chat_database_path(mgr->lc));
438
		if (!liblinphone_tester_keep_record_files && record_file){
439
			if ((bc_get_number_of_failures()-mgr->number_of_bcunit_error_at_creation)>0) {
440
				ms_error("Test has failed, keeping recorded file [%s]",record_file);
Simon Morlat's avatar
Simon Morlat committed
441 442 443
			} else {
				unlink(record_file);
			}
444
		}
Simon Morlat's avatar
Simon Morlat committed
445
		linphone_core_destroy(mgr->lc);
446 447 448 449
		if (chatdb) {
			unlink(chatdb);
			ms_free(chatdb);
		}
450
	}
451 452 453
	if (mgr->identity) {
		linphone_address_destroy(mgr->identity);
	}
454

455
	manager_count--;
456
	linphone_core_set_log_level(old_log_level);
457
}
458

459 460 461 462 463 464 465 466 467 468
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));
	}
}

469 470
void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
	linphone_core_manager_uninit(mgr);
471 472 473
	ms_free(mgr);
}

474
int liblinphone_tester_ipv6_available(void){
475
	struct addrinfo *ai=bctbx_ip_address_to_addrinfo(AF_INET6,SOCK_STREAM,"2a01:e00::2",53);
476 477 478 479 480 481
	if (ai){
		struct sockaddr_storage ss;
		struct addrinfo src;
		socklen_t slen=sizeof(ss);
		char localip[128];
		int port=0;
482
		belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444);
483 484
		src.ai_addr=(struct sockaddr*) &ss;
		src.ai_addrlen=slen;
485
		bctbx_addrinfo_to_ip_address(&src,localip, sizeof(localip),&port);
486 487 488 489 490 491
		freeaddrinfo(ai);
		return strcmp(localip,"::1")!=0;
	}
	return FALSE;
}

492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
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;
}


511 512 513 514
void liblinphone_tester_keep_accounts( int keep ){
	liblinphone_tester_keep_accounts_flag = keep;
}

515 516 517 518
void liblinphone_tester_keep_recorded_files(int keep){
	liblinphone_tester_keep_record_files = keep;
}

519 520 521 522
void liblinphone_tester_disable_leak_detector(int disabled){
	liblinphone_tester_leak_detector_disabled = disabled;
}

523 524 525
void liblinphone_tester_clear_accounts(void){
	account_manager_destroy();
}
526 527 528 529

void liblinphone_tester_add_suites() {
	bc_tester_add_suite(&setup_test_suite);
	bc_tester_add_suite(&register_test_suite);
530
	bc_tester_add_suite(&tunnel_test_suite);
531 532
	bc_tester_add_suite(&offeranswer_test_suite);
	bc_tester_add_suite(&call_test_suite);
533
	bc_tester_add_suite(&call_video_test_suite);
Sylvain Berfini's avatar
Sylvain Berfini committed
534
	bc_tester_add_suite(&audio_bypass_suite);
535 536 537
	bc_tester_add_suite(&multi_call_test_suite);
	bc_tester_add_suite(&message_test_suite);
	bc_tester_add_suite(&presence_test_suite);
538
	bc_tester_add_suite(&presence_server_test_suite);
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
#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);
	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);
554
	bc_tester_add_suite(&proxy_config_test_suite);
jehan's avatar
jehan committed
555 556 557
#if HAVE_SIPP
	bc_tester_add_suite(&complex_sip_call_test_suite);
#endif
558
#ifdef VCARD_ENABLED
559
	bc_tester_add_suite(&vcard_test_suite);
560
#endif
561
}
562

Simon Morlat's avatar
Simon Morlat committed
563
static int linphone_core_manager_get_max_audio_bw_base(const int array[],int array_size) {
564 565 566 567 568 569 570
	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
571 572 573 574 575 576 577 578
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;
}

579 580 581 582 583 584 585 586
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));
}
587

Simon Morlat's avatar
Simon Morlat committed
588 589 590 591 592 593 594 595 596
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));
}

597
void liblinphone_tester_before_each(void) {
598 599 600 601
	if (!liblinphone_tester_leak_detector_disabled){
		belle_sip_object_enable_leak_detector(TRUE);
		leaked_objects_count = belle_sip_object_get_object_count();
	}
602 603
}

604 605
static char* all_leaks_buffer = NULL;

606
int liblinphone_tester_after_each(void) {
607
	int err = 0;
608 609 610
	if (!liblinphone_tester_leak_detector_disabled){
		int leaked_objects = belle_sip_object_get_object_count() - leaked_objects_count;
		if (leaked_objects > 0) {
611
			char* format = ms_strdup_printf("%d object%s leaked in suite [%s] test [%s], please fix that!",
612
											leaked_objects, leaked_objects>1?"s were":" was",
613
											bc_tester_current_suite_name(), bc_tester_current_test_name());
614
			belle_sip_object_dump_active_objects();
615
			belle_sip_object_flush_active_objects();
616
			bc_tester_printf(ORTP_MESSAGE, format);
617 618 619
			ms_error("%s", format);

			all_leaks_buffer = ms_strcat_printf(all_leaks_buffer, "\n%s", format);
Ghislain MARY's avatar
Ghislain MARY committed
620
			ms_free(format);
621
		}
622

623 624 625 626 627 628 629 630
		// 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!");
631
				err = 1;
632 633 634
				// and reciprocally
			} else if (leaks_expected && leaked_objects == 0) {
				BC_FAIL("This test is not leaking anymore, please remove LeaksMemory tag!");
635
				// err = 1; // do not force fail actually, because it can be some false positive warning
636
			}
637
		}
638 639
	}

640
	if (manager_count != 0) {
641
		ms_fatal("%d Linphone core managers are still alive!", manager_count);
642
	}
643
	return err;
644
}
645

646 647 648
void liblinphone_tester_uninit(void) {
	// show all leaks that happened during the test
	if (all_leaks_buffer) {
649
		bc_tester_printf(ORTP_MESSAGE, all_leaks_buffer);
650
		ms_free(all_leaks_buffer);
651
		all_leaks_buffer = NULL;
652 653 654
	}
	bc_tester_uninit();
}
655

656
static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStreamType stream_type) {
657
	MediaStream *ms;
658 659
	switch (stream_type) {
	case LinphoneStreamTypeAudio:
660 661
		ms=&c1->audiostream->ms;
		break;
662
	case LinphoneStreamTypeVideo:
663 664 665 666 667 668 669 670 671
		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;
672
	}
673

674
	if (linphone_call_get_audio_stats(c1)->ice_state == LinphoneIceStateHostConnection && media_stream_started(ms)) {
Ghislain MARY's avatar
Ghislain MARY committed
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
		struct sockaddr_storage remaddr;
		socklen_t remaddrlen = sizeof(remaddr);
		char ip[NI_MAXHOST] = { 0 };
		int port = 0;
		SalMediaDescription *result_desc;
		char *expected_addr = NULL;

		const LinphoneCallParams *cp1 = linphone_call_get_current_params(c1);
		const LinphoneCallParams *cp2 = linphone_call_get_current_params(c2);
		if (cp1->update_call_when_ice_completed && cp2->update_call_when_ice_completed) {
			memset(&remaddr, 0, remaddrlen);
			result_desc = sal_call_get_final_media_description(c2->op);
			expected_addr = result_desc->streams[0].rtp_addr;
			if (expected_addr[0] == '\0') expected_addr = result_desc->addr;
			if ((strchr(expected_addr, ':') == NULL) && (c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr.ss_family == AF_INET6)) {
				bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr, (struct sockaddr *)&remaddr, &remaddrlen);
			} else {
				memcpy(&remaddr, &c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr, c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addrlen);
			}
			bctbx_sockaddr_to_ip_address((struct sockaddr *)&remaddr, remaddrlen, ip, sizeof(ip), &port);

			BC_ASSERT_STRING_EQUAL(ip, expected_addr);
		}
698 699
	}
}
Ghislain MARY's avatar
Ghislain MARY committed
700

701 702 703 704 705 706 707
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;
708

709 710
	c1=linphone_core_get_current_call(caller->lc);
	c2=linphone_core_get_current_call(callee->lc);
711

712 713 714 715 716
	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);
717

718 719 720 721 722 723 724 725 726 727
	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;
728 729
				check_ice_from_rtp(c1,c2,LinphoneStreamTypeAudio);
				check_ice_from_rtp(c2,c1,LinphoneStreamTypeAudio);
730 731 732 733 734 735 736
				break;
			}
			linphone_core_iterate(caller->lc);
			linphone_core_iterate(callee->lc);
		}
		ms_usleep(20000);
	}while(!liblinphone_tester_clock_elapsed(&ts,10000));
737

738 739 740 741 742 743 744
	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;
745 746
					check_ice_from_rtp(c1,c2,LinphoneStreamTypeVideo);
					check_ice_from_rtp(c2,c1,LinphoneStreamTypeVideo);
747 748 749 750 751 752 753 754
					break;
				}
				linphone_core_iterate(caller->lc);
				linphone_core_iterate(callee->lc);
			}
			ms_usleep(20000);
		}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	}
755

756 757 758 759 760 761 762
	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;
763 764
					check_ice_from_rtp(c1,c2,LinphoneStreamTypeText);
					check_ice_from_rtp(c2,c1,LinphoneStreamTypeText);
765 766 767 768 769 770 771 772
					break;
				}
				linphone_core_iterate(caller->lc);
				linphone_core_iterate(callee->lc);
			}
			ms_usleep(20000);
		}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	}
773

774 775 776 777 778 779 780 781 782 783 784 785 786 787
	/*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;
}

788
static void linphone_conference_server_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) {
789 790
	LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
	LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)vtable->user_data;
791

792 793 794 795
	switch(cstate) {
		case LinphoneCallIncomingReceived:
			linphone_core_accept_call(lc, call);
			break;
796

797 798 799 800
		case LinphoneCallStreamsRunning:
			if(linphone_call_get_conference(call) == NULL) {
				linphone_core_add_to_conference(lc, call);
				linphone_core_leave_conference(lc);
801
				if(conf_srv->first_call == NULL) conf_srv->first_call = call;
802 803
			}
			break;
804

805 806
		case LinphoneCallEnd:
			if(call == conf_srv->first_call) {
807 808 809
				if(linphone_core_get_conference(lc)) {
					linphone_core_terminate_conference(lc);
				}
810 811 812
				conf_srv->first_call = NULL;
			}
			break;
813

814 815 816 817
		default: break;
	}
}

818
static void linphone_conference_server_refer_received(LinphoneCore *core, const char *refer_to) {
819 820 821 822
	char method[20];
	LinphoneAddress *refer_to_addr = linphone_address_new(refer_to);
	char *uri;
	LinphoneCall *call;
823

824 825 826 827 828 829 830 831 832 833 834
	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);
}
835

836 837 838 839 840 841 842 843 844 845 846 847
static void linphone_conference_server_registration_state_changed(LinphoneCore *core,
																  LinphoneProxyConfig *cfg,
																  LinphoneRegistrationState cstate,
																  const char *message) {
	LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(core);
	LinphoneConferenceServer *m = (LinphoneConferenceServer *)linphone_core_v_table_get_user_data(vtable);
	if(cfg == linphone_core_get_default_proxy_config(core)) {
		m->reg_state = cstate;
	}
}

LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file, bool_t do_registration) {
848 849
	LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)ms_new0(LinphoneConferenceServer, 1);
	LinphoneCoreManager *lm = (LinphoneCoreManager *)conf_srv;
850

851 852
	conf_srv->vtable = linphone_core_v_table_new();
	conf_srv->vtable->call_state_changed = linphone_conference_server_call_state_changed;
853
	conf_srv->vtable->refer_received = linphone_conference_server_refer_received;
854
	conf_srv->vtable->registration_state_changed = linphone_conference_server_registration_state_changed;
855
	conf_srv->vtable->user_data = conf_srv;
856
	conf_srv->reg_state = LinphoneRegistrationNone;
857
	linphone_core_manager_init(lm, rc_file,NULL);
858
	linphone_core_add_listener(lm->lc, conf_srv->vtable);
859
	linphone_core_manager_start(lm, do_registration);
860 861
	return conf_srv;
}
862

863 864 865 866 867
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);
}