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

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

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

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

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

45

46
static int liblinphone_tester_keep_accounts_flag = 0;
47
static int liblinphone_tester_keep_record_files = FALSE;
48
static int liblinphone_tester_leak_detector_disabled = FALSE;
49
bool_t liblinphone_tester_tls_support_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";
60 61
bool_t liblinphonetester_ipv6 = TRUE;
bool_t liblinphonetester_show_account_manager_logs = FALSE;
62 63 64
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*/
Gautier Pelloux-Prayer's avatar
Gautier Pelloux-Prayer committed
65

66 67
const char *liblinphone_tester_mire_id="Mire: Mire (synthetic moving picture)";

68
static void network_reachable(LinphoneCore *lc, bool_t reachable) {
69 70 71 72 73 74 75 76
	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++;
}
77 78 79 80 81 82 83 84 85 86 87 88
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;
}

89

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

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

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

119
LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) {
120
	LinphoneCore* lc;
121 122 123 124 125 126 127
	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
128
	char *chatdb     = NULL;
129 130 131 132

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

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


141 142 143 144 145
	// 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);
146
	dnsuserhostspath = userhostsfile[0]=='/' ? ms_strdup(userhostsfile) : ms_strdup_printf("%s/%s", path, userhostsfile);
147 148


149 150 151 152 153 154
	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 {
155
		lc = linphone_core_new(v_table,NULL,(filepath!=NULL&&filepath[0]!='\0') ? filepath : NULL, user_data);
156 157 158 159 160

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

163
	linphone_core_enable_ipv6(lc, liblinphonetester_ipv6);
164
	linphone_core_set_sip_transport_timeout(lc, liblinphonetester_transport_timeout);
165

166 167
	sal_enable_test_features(lc->sal,TRUE);
	sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath);
168
#ifdef VIDEO_ENABLED
169
	linphone_core_set_static_picture(lc,nowebcampath);
170
#endif
171

jehan's avatar
jehan committed
172
	linphone_core_set_chat_database_path(lc, chatdb);
173

174 175 176 177 178
	ms_free(ringpath);
	ms_free(ringbackpath);
	ms_free(nowebcampath);
	ms_free(rootcapath);
	ms_free(dnsuserhostspath);
179
	remove(chatdb);
jehan's avatar
jehan committed
180
	ms_free(chatdb);
181 182 183 184 185

	if( filepath ) ms_free(filepath);

	if( config ) lp_config_unref(config);

186 187 188 189 190
	return lc;
}


bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout) {
191
	bctbx_list_t* lcs=NULL;
192 193
	bool_t result;
	if (lc_1)
194
		lcs=bctbx_list_append(lcs,lc_1);
195
	if (lc_2)
196
		lcs=bctbx_list_append(lcs,lc_2);
197
	result=wait_for_list(lcs,counter,value,timout);
198
	bctbx_list_free(lcs);
199 200 201 202
	return result;
}

bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) {
203
	return wait_for_until(lc_1, lc_2,counter,value,10000);
204 205
}

206 207
bool_t wait_for_list(bctbx_list_t* lcs,int* counter,int value,int timeout_ms) {
	bctbx_list_t* iterator;
208
	MSTimeSpec start;
209

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

235 236 237 238
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
239
	while (linphone_core_get_stun_server_addrinfo(m->lc) == NULL && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
240 241 242
		linphone_core_iterate(m->lc);
		ms_usleep(20000);
	}
Ghislain MARY's avatar
Ghislain MARY committed
243
	return linphone_core_get_stun_server_addrinfo(m->lc) != NULL;
244 245
}

246
static void set_codec_enable(LinphoneCore* lc,const char* type,int rate,bool_t enable) {
247 248
	bctbx_list_t* codecs=bctbx_list_copy(linphone_core_get_audio_codecs(lc));
	bctbx_list_t* codecs_it;
249 250
	PayloadType* pt;
	for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) {
251
		linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0);
252
	}
253
	if ((pt = linphone_core_find_payload_type(lc,type,rate,1))) {
254 255
		linphone_core_enable_payload_type(lc,pt, enable);
	}
256
	bctbx_list_free(codecs);
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
}

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

272
bool_t transport_supported(LinphoneTransportType transport) {
273 274 275 276 277 278 279 280 281
	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;
	}
282 283
}

284 285 286
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic push
#endif
287 288 289
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
290
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
291
#endif
292
void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias) {
Ghislain MARY's avatar
Ghislain MARY committed
293
	LinphoneImNotifPolicy *im_notif_policy;
294
	char *rc_path = NULL;
jehan's avatar
jehan committed
295
	char *hellopath = bc_tester_res("sounds/hello8000.wav");
Ghislain MARY's avatar
Ghislain MARY committed
296

297
	mgr->number_of_bcunit_error_at_creation =  bc_get_number_of_failures();
298 299 300 301 302 303 304 305
	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;
306
	mgr->v_table.notify_presence_received_for_uri_or_tel=notify_presence_received_for_uri_or_tel;
307 308 309 310 311 312
	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
313
	mgr->v_table.call_encryption_changed=linphone_call_encryption_changed;
314
	mgr->v_table.network_reachable=network_reachable;
315
	mgr->v_table.dtmf_received=dtmf_received;
316
	mgr->v_table.call_stats_updated=call_stats_updated;
317

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

320 321
	reset_counters(&mgr->stat);
	if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file);
322
	mgr->lc=configure_lc_from(&mgr->v_table, bc_tester_get_resource_dir_prefix(), rc_path, mgr);
323
	linphone_core_manager_check_accounts(mgr);
Ghislain MARY's avatar
Ghislain MARY committed
324
	im_notif_policy = linphone_core_get_im_notif_policy(mgr->lc);
325 326 327 328 329 330
	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);
	}
331

332 333
	manager_count++;

Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
334
#if TARGET_OS_IPHONE
335 336
	linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device");
	linphone_core_set_ringback(mgr->lc, NULL);
337 338
#elif __QNX__
	linphone_core_set_playback_device(mgr->lc, "QSA: voice");
339 340
#endif

341 342 343 344
#ifdef VIDEO_ENABLED
	{
		MSWebCam *cam;

345
		cam = ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(mgr->lc->factory), "Mire: Mire (synthetic moving picture)");
346 347

		if (cam == NULL) {
Simon Morlat's avatar
Simon Morlat committed
348 349 350
			MSWebCamDesc *desc = ms_mire_webcam_desc_get();
			if (desc){
				cam=ms_web_cam_new(desc);
351
				ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(mgr->lc->factory), cam);
Simon Morlat's avatar
Simon Morlat committed
352
			}
353 354 355 356
		}
	}
#endif

jehan's avatar
jehan committed
357

358 359
	linphone_core_set_play_file(mgr->lc,hellopath); /*is also used when in pause*/
	ms_free(hellopath);
360

361
	if( manager_count >= 2){
362
		char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",bc_tester_get_writable_dir_prefix(),mgr->lc);
363
		ms_message("Manager for '%s' using files", rc_file ? rc_file : "--");
364
		linphone_core_set_use_files(mgr->lc, TRUE);
365 366
		linphone_core_set_record_file(mgr->lc,recordpath);
		ms_free(recordpath);
367
	}
368

369
	linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix());
370 371
	/*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);
372

373 374
	if (rc_path) ms_free(rc_path);
}
375 376 377
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic pop
#endif
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
378

379
void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies) {
380 381
	LinphoneProxyConfig* proxy;
	int proxy_count;
382

383
	/*BC_ASSERT_EQUAL(bctbx_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count, int, "%d");*/
384
	if (check_for_proxies){ /**/
Ghislain MARY's avatar
Ghislain MARY committed
385
		proxy_count=(int)bctbx_list_size(linphone_core_get_proxy_config_list(mgr->lc));
386
	}else{
387
		proxy_count=0;
388 389 390
		/*this is to prevent registration to go on*/
		linphone_core_set_network_reachable(mgr->lc, FALSE);
	}
391

392 393 394
	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
395
									proxy_count,(REGISTER_TIMEOUT * 1000 * proxy_count));
396 397 398 399
		if( !success ){
			ms_error("Did not register after %d seconds for %d proxies", REGISTER_TIMEOUT, proxy_count);
		}
	}
400
	BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count, int, "%d");
401 402
	enable_codec(mgr->lc,"PCMU",8000);

403
	proxy = linphone_core_get_default_proxy_config(mgr->lc);
404
	if (proxy) {
405 406 407
		if (mgr->identity){
			linphone_address_destroy(mgr->identity);
		}
408
		mgr->identity = linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
409 410
		linphone_address_clean(mgr->identity);
	}
411

412
	linphone_core_manager_wait_for_stun_resolution(mgr);
413 414 415 416
	if (!check_for_proxies){
		/*now that stun server resolution is done, we can start registering*/
		linphone_core_set_network_reachable(mgr->lc, TRUE);
	}
417

418 419
}

420
LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, int check_for_proxies, const char* phone_alias) {
421
	LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
422
	
423 424
	linphone_core_manager_init(manager, rc_file, phone_alias);
	linphone_core_manager_start(manager, check_for_proxies);
425 426 427
	return manager;
}

428
LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) {
429
	return linphone_core_manager_new3(rc_file, check_for_proxies, NULL);
430 431
}

432 433 434 435 436
LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) {
	return linphone_core_manager_new2(rc_file, TRUE);
}


437 438
void linphone_core_manager_stop(LinphoneCoreManager *mgr){
	if (mgr->lc) {
439 440
		const char *record_file = linphone_core_get_record_file(mgr->lc);
		char *chatdb = ms_strdup(linphone_core_get_chat_database_path(mgr->lc));
441
		if (!liblinphone_tester_keep_record_files && record_file && ortp_file_exist(record_file)==0) {
442 443 444 445 446 447 448
			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);
			}
		}
449
		linphone_core_destroy(mgr->lc);
Ghislain MARY's avatar
Ghislain MARY committed
450 451 452 453 454
		if (chatdb) {
			if (ortp_file_exist(chatdb)==0) {
				if (unlink(chatdb) != 0){
					ms_error("Could not delete %s: %s", chatdb, strerror(errno));
				}
455
			}
456 457 458
			ms_free(chatdb);
		}
		mgr->lc = NULL;
459 460 461
	}
}

462
void linphone_core_manager_uninit(LinphoneCoreManager *mgr) {
463 464
	int old_log_level = ortp_get_log_level_mask(NULL);
	linphone_core_set_log_level(ORTP_ERROR);
465 466 467
	if (mgr->phone_alias) {
		ms_free(mgr->phone_alias);
	}
468 469 470
	if (mgr->stat.last_received_chat_message) {
		linphone_chat_message_unref(mgr->stat.last_received_chat_message);
	}
471
	if (mgr->stat.last_received_info_message) linphone_info_message_destroy(mgr->stat.last_received_info_message);
472 473 474
	if (mgr->identity) {
		linphone_address_destroy(mgr->identity);
	}
475

476
	manager_count--;
477
	linphone_core_set_log_level(old_log_level);
478
}
479

480 481 482 483 484 485 486 487 488 489
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));
	}
}

490
void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
491
	linphone_core_manager_stop(mgr);
492
	linphone_core_manager_uninit(mgr);
493 494 495
	ms_free(mgr);
}

496
int liblinphone_tester_ipv6_available(void){
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
	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;
		}
512 513 514 515
	}
	return FALSE;
}

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
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;
}


535 536 537 538
void liblinphone_tester_keep_accounts( int keep ){
	liblinphone_tester_keep_accounts_flag = keep;
}

539 540 541 542
void liblinphone_tester_keep_recorded_files(int keep){
	liblinphone_tester_keep_record_files = keep;
}

543 544 545 546
void liblinphone_tester_disable_leak_detector(int disabled){
	liblinphone_tester_leak_detector_disabled = disabled;
}

547 548 549
void liblinphone_tester_clear_accounts(void){
	account_manager_destroy();
}
550 551 552 553

void liblinphone_tester_add_suites() {
	bc_tester_add_suite(&setup_test_suite);
	bc_tester_add_suite(&register_test_suite);
554
	bc_tester_add_suite(&tunnel_test_suite);
555 556
	bc_tester_add_suite(&offeranswer_test_suite);
	bc_tester_add_suite(&call_test_suite);
557
	bc_tester_add_suite(&call_video_test_suite);
Sylvain Berfini's avatar
Sylvain Berfini committed
558
	bc_tester_add_suite(&audio_bypass_suite);
559 560 561
	bc_tester_add_suite(&multi_call_test_suite);
	bc_tester_add_suite(&message_test_suite);
	bc_tester_add_suite(&presence_test_suite);
562
	bc_tester_add_suite(&presence_server_test_suite);
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
#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);
578
	bc_tester_add_suite(&proxy_config_test_suite);
jehan's avatar
jehan committed
579 580 581
#if HAVE_SIPP
	bc_tester_add_suite(&complex_sip_call_test_suite);
#endif
582
#ifdef VCARD_ENABLED
583
	bc_tester_add_suite(&vcard_test_suite);
584
#endif
585
}
586

Simon Morlat's avatar
Simon Morlat committed
587
static int linphone_core_manager_get_max_audio_bw_base(const int array[],int array_size) {
588 589 590 591 592 593 594
	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
595 596 597 598 599 600 601 602
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;
}

603 604 605 606 607 608 609 610
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));
}
611

Simon Morlat's avatar
Simon Morlat committed
612 613 614 615 616 617 618 619 620
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));
}

621
void liblinphone_tester_before_each(void) {
622 623 624 625
	if (!liblinphone_tester_leak_detector_disabled){
		belle_sip_object_enable_leak_detector(TRUE);
		leaked_objects_count = belle_sip_object_get_object_count();
	}
626 627
}

628 629
static char* all_leaks_buffer = NULL;

630 631
void liblinphone_tester_after_each(void) {

632 633 634
	if (!liblinphone_tester_leak_detector_disabled){
		int leaked_objects = belle_sip_object_get_object_count() - leaked_objects_count;
		if (leaked_objects > 0) {
635
			char* format = ms_strdup_printf("%d object%s leaked in suite [%s] test [%s], please fix that!",
636
											leaked_objects, leaked_objects>1?"s were":" was",
637
											bc_tester_current_suite_name(), bc_tester_current_test_name());
638
			belle_sip_object_dump_active_objects();
639
			belle_sip_object_flush_active_objects();
640
			bc_tester_printf(ORTP_MESSAGE, format);
641 642 643
			ms_error("%s", format);

			all_leaks_buffer = ms_strcat_printf(all_leaks_buffer, "\n%s", format);
Ghislain MARY's avatar
Ghislain MARY committed
644
			ms_free(format);
645
		}
646

647 648 649 650 651 652 653 654 655 656 657
		// 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!");
658
			}
659
		}
660 661
	}

662
	if (manager_count != 0) {
663
		ms_fatal("%d Linphone core managers are still alive!", manager_count);
664 665
	}
}
666

667 668 669
void liblinphone_tester_uninit(void) {
	// show all leaks that happened during the test
	if (all_leaks_buffer) {
670
		bc_tester_printf(ORTP_MESSAGE, all_leaks_buffer);
671
		ms_free(all_leaks_buffer);
672
		all_leaks_buffer = NULL;
673 674 675
	}
	bc_tester_uninit();
}
676

677
static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStreamType stream_type) {
678
	MediaStream *ms;
679 680
	switch (stream_type) {
	case LinphoneStreamTypeAudio:
681 682
		ms=&c1->audiostream->ms;
		break;
683
	case LinphoneStreamTypeVideo:
684 685 686 687 688 689 690 691 692
		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;
693
	}
694

695
	if (linphone_call_get_audio_stats(c1)->ice_state == LinphoneIceStateHostConnection && media_stream_started(ms)) {
Ghislain MARY's avatar
Ghislain MARY committed
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
		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);
		}
719 720
	}
}
Ghislain MARY's avatar
Ghislain MARY committed
721

722 723
bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) {
	LinphoneCall *c1,*c2;
724
	bool_t global_success = TRUE;
725 726 727
	bool_t audio_success=FALSE;
	bool_t video_success=FALSE;
	bool_t text_success=FALSE;
728
	bool_t audio_enabled, video_enabled, realtime_text_enabled;
729
	MSTimeSpec ts;
730

731 732
	c1=linphone_core_get_current_call(caller->lc);
	c2=linphone_core_get_current_call(callee->lc);
733

734 735 736 737 738
	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);
739

740 741
	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");
742
	audio_enabled=linphone_call_params_audio_enabled(linphone_call_get_current_params(c1));
743 744
	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));
745 746 747 748 749 750 751 752 753 754 755 756 757
	if (audio_enabled) {
		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;
					check_ice_from_rtp(c1,c2,LinphoneStreamTypeAudio);
					check_ice_from_rtp(c2,c1,LinphoneStreamTypeAudio);
					break;
				}
				linphone_core_iterate(caller->lc);
				linphone_core_iterate(callee->lc);
758
			}
759 760 761
			ms_usleep(20000);
		}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	}
762

763 764 765 766 767 768 769
	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;
770 771
					check_ice_from_rtp(c1,c2,LinphoneStreamTypeVideo);
					check_ice_from_rtp(c2,c1,LinphoneStreamTypeVideo);
772 773 774 775 776 777 778 779
					break;
				}
				linphone_core_iterate(caller->lc);
				linphone_core_iterate(callee->lc);
			}
			ms_usleep(20000);
		}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	}
780

781 782 783 784 785 786 787
	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;
788 789
					check_ice_from_rtp(c1,c2,LinphoneStreamTypeText);
					check_ice_from_rtp(c2,c1,LinphoneStreamTypeText);
790 791 792 793 794 795 796 797
					break;
				}
				linphone_core_iterate(caller->lc);
				linphone_core_iterate(callee->lc);
			}
			ms_usleep(20000);
		}while(!liblinphone_tester_clock_elapsed(&ts,10000));
	}
798

799 800 801 802 803 804 805 806 807 808 809
	/*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);
810 811 812 813
	if (audio_enabled) global_success = global_success && audio_success;
	if (video_enabled) global_success = global_success && video_success;
	if (realtime_text_enabled) global_success = global_success && text_success;
	return global_success;
814 815
}

816
static void linphone_conference_server_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) {
817 818
	LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
	LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)vtable->user_data;
819

820 821 822 823
	switch(cstate) {
		case LinphoneCallIncomingReceived:
			linphone_core_accept_call(lc, call);
			break;
824

825 826 827 828
		case LinphoneCallStreamsRunning:
			if(linphone_call_get_conference(call) == NULL) {
				linphone_core_add_to_conference(lc, call);
				linphone_core_leave_conference(lc);
829
				if(conf_srv->first_call == NULL) conf_srv->first_call = call;
830 831
			}
			break;
832

833 834
		case LinphoneCallEnd:
			if(call == conf_srv->first_call) {
835 836 837
				if(linphone_core_get_conference(lc)) {
					linphone_core_terminate_conference(lc);
				}
838 839 840
				conf_srv->first_call = NULL;
			}
			break;
841

842 843 844 845
		default: break;
	}
}

846
static void linphone_conference_server_refer_received(LinphoneCore *core, const char *refer_to) {
847 848 849 850
	char method[20];
	LinphoneAddress *refer_to_addr = linphone_address_new(refer_to);
	char *uri;
	LinphoneCall *call;
851

852 853 854 855 856 857 858 859 860 861 862
	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);
}
863

864 865 866 867 868 869 870 871 872 873 874 875
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) {
876 877
	LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)ms_new0(LinphoneConferenceServer, 1);
	LinphoneCoreManager *lm = (LinphoneCoreManager *)conf_srv;
jehan's avatar
jehan committed
878
	LinphoneProxyConfig *proxy;
879 880
	conf_srv->vtable = linphone_core_v_table_new();
	conf_srv->vtable->call_state_changed = linphone_conference_server_call_state_changed;
881