accountmanager.c 9.76 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 23 24 25
 /*
 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 "liblinphone_tester.h"
#include "private.h"

struct _Account{
	LinphoneAddress *identity;
	LinphoneAddress *modified_identity;
	char *password;
26
	int registered;
27
	int done;
28
	int created;
29
	char *phone_alias;
30
	char *uuid;
31 32 33 34
};

typedef struct _Account Account;

35
static Account *account_new(LinphoneAddress *identity, const char *unique_id){
36 37
	char *modified_username;
	Account *obj=ms_new0(Account,1);
38

39 40 41 42
	/* we need to inhibit leak detector because the two LinphoneAddress will remain behond the scope of the test being run */
	belle_sip_object_inhibit_leak_detector(TRUE);
	obj->identity=linphone_address_clone(identity);
	obj->password=sal_get_random_token(8);
43
	obj->phone_alias = NULL;
44 45 46 47 48 49 50 51 52
	obj->modified_identity=linphone_address_clone(identity);
	modified_username=ms_strdup_printf("%s_%s",linphone_address_get_username(identity), unique_id);
	linphone_address_set_username(obj->modified_identity, modified_username);
	ms_free(modified_username);
	belle_sip_object_inhibit_leak_detector(FALSE);
	return obj;
};

void account_destroy(Account *obj){
53
	if (obj->uuid) bctbx_free(obj->uuid);
54 55 56 57 58 59 60 61
	linphone_address_unref(obj->identity);
	linphone_address_unref(obj->modified_identity);
	ms_free(obj->password);
	ms_free(obj);
}

struct _AccountManager{
	char *unique_id;
62
	bctbx_list_t *accounts;
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
};

typedef struct _AccountManager AccountManager;

static AccountManager *the_am=NULL;

AccountManager *account_manager_get(void){
	if (the_am==NULL){
		the_am=ms_new0(AccountManager,1);
		the_am->unique_id=sal_get_random_token(6);
	}
	return the_am;
}

void account_manager_destroy(void){
	if (the_am){
		ms_free(the_am->unique_id);
80
		bctbx_list_free_with_data(the_am->accounts,(void(*)(void*))account_destroy);
81 82 83
		ms_free(the_am);
	}
	the_am=NULL;
84
	ms_message("Test account manager destroyed.");
85 86 87
}

Account *account_manager_get_account(AccountManager *m, const LinphoneAddress *identity){
88
	bctbx_list_t *it;
89

90 91 92 93 94 95 96 97 98 99 100 101
	for(it=m->accounts;it!=NULL;it=it->next){
		Account *a=(Account*)it->data;
		if (linphone_address_weak_equal(a->identity,identity)){
			return a;
		}
	}
	return NULL;
}

static void account_created_on_server_cb(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *info){
	Account *account=(Account*)linphone_core_get_user_data(lc);
	switch(state){
102 103 104 105 106 107 108 109 110
		case LinphoneRegistrationOk: {
			char * phrase = sal_op_get_error_info((SalOp*)cfg->op)->full_string;
			if (phrase && strcasecmp("Test account created", phrase) == 0) {
				account->created=1;
			} else {
				account->registered=1;
			}
			break;
		}
111 112 113 114 115 116 117 118
		case LinphoneRegistrationCleared:
			account->done=1;
		break;
		default:
		break;
	}
}

119 120 121
// TEMPORARY CODE: remove function below when flexisip is updated, this is not needed anymore!
// The new flexisip now answer "200 Test account created" when creating a test account, and do not
// challenge authentication anymore! so this code is not used for newer version
122
static void account_created_auth_requested_cb(LinphoneCore *lc, const char *username, const char *realm, const char *domain){
123 124 125 126 127
	Account *account=(Account*)linphone_core_get_user_data(lc);
	account->created=1;
}
// TEMPORARY CODE: remove line above when flexisip is updated, this is not needed anymore!

128
void account_create_on_server(Account *account, const LinphoneProxyConfig *refcfg, const char* phone_alias){
129 130 131 132 133 134 135
	LinphoneCoreVTable vtable={0};
	LinphoneCore *lc;
	LinphoneAddress *tmp_identity=linphone_address_clone(account->modified_identity);
	LinphoneProxyConfig *cfg;
	LinphoneAuthInfo *ai;
	char *tmp;
	LinphoneAddress *server_addr;
136
	LinphoneSipTransports tr;
137
	char *chatdb;
138

139
	vtable.registration_state_changed=account_created_on_server_cb;
140 141
	// TEMPORARY CODE: remove line below when flexisip is updated, this is not needed anymore!
	vtable.auth_info_requested=account_created_auth_requested_cb;
142
	lc=configure_lc_from(&vtable,bc_tester_get_resource_dir_prefix(),NULL,account);
143
	chatdb = ms_strdup(linphone_core_get_chat_database_path(lc));
144 145 146 147
	tr.udp_port=LC_SIP_TRANSPORT_RANDOM;
	tr.tcp_port=LC_SIP_TRANSPORT_RANDOM;
	tr.tls_port=LC_SIP_TRANSPORT_RANDOM;
	linphone_core_set_sip_transports(lc,&tr);
148

149
	cfg=linphone_core_create_proxy_config(lc);
150
	linphone_address_set_secure(tmp_identity, FALSE);
151 152
	linphone_address_set_password(tmp_identity,account->password);
	linphone_address_set_header(tmp_identity,"X-Create-Account","yes");
153
	if (phone_alias) linphone_address_set_header(tmp_identity, "X-Phone-Alias", phone_alias);
154 155 156 157
	tmp=linphone_address_as_string(tmp_identity);
	linphone_proxy_config_set_identity(cfg,tmp);
	ms_free(tmp);
	linphone_address_unref(tmp_identity);
158

159
	server_addr=linphone_address_new(linphone_proxy_config_get_server_addr(refcfg));
160 161
	linphone_address_set_secure(server_addr, FALSE);
	linphone_address_set_transport(server_addr,LinphoneTransportTcp); /*use tcp for account creation, we may not have certificates configured at this stage*/
162
	linphone_address_set_port(server_addr,0);
163 164 165 166
	tmp=linphone_address_as_string(server_addr);
	linphone_proxy_config_set_server_addr(cfg,tmp);
	ms_free(tmp);
	linphone_address_unref(server_addr);
167
	linphone_proxy_config_set_expires(cfg,3*3600); //accounts are valid 3 hours
168

169
	linphone_core_add_proxy_config(lc,cfg);
170 171 172
	/*wait 25 seconds, since the DNS SRV resolution may take a while - and
	especially if router does NOT support DNS SRV and we have to wait its timeout*/
	if (wait_for_until(lc,NULL,&account->created,1,25000)==FALSE){
173 174 175
		ms_fatal("Account for %s could not be created on server.", linphone_proxy_config_get_identity(refcfg));
	}
	linphone_proxy_config_edit(cfg);
176 177 178
	tmp_identity=linphone_address_clone(account->modified_identity);
	linphone_address_set_secure(tmp_identity, FALSE);
	tmp=linphone_address_as_string(tmp_identity);
179
	linphone_proxy_config_set_identity(cfg,tmp); /*remove the X-Create-Account header*/
180
	linphone_address_unref(tmp_identity);
181 182
	ms_free(tmp);
	linphone_proxy_config_done(cfg);
183

184 185 186 187
	ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity),
				NULL,
				account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity));
	linphone_core_add_auth_info(lc,ai);
188
	linphone_auth_info_unref(ai);
189

190
	if (wait_for_until(lc,NULL,&account->registered,1,3000)==FALSE){
191 192 193 194 195 196 197
		ms_fatal("Account for %s is not working on server.", linphone_proxy_config_get_identity(refcfg));
	}
	linphone_core_remove_proxy_config(lc,cfg);
	linphone_proxy_config_unref(cfg);
	if (wait_for_until(lc,NULL,&account->done,1,3000)==FALSE){
		ms_error("Account creation could not clean the registration context.");
	}
198
	linphone_core_unref(lc);
199 200
	unlink(chatdb);
	ms_free(chatdb);
201 202
}

203
static LinphoneAddress *account_manager_check_account(AccountManager *m, LinphoneProxyConfig *cfg, LinphoneCoreManager *cm){
204 205 206 207 208 209
	LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
	const char *identity=linphone_proxy_config_get_identity(cfg);
	LinphoneAddress *id_addr=linphone_address_new(identity);
	Account *account=account_manager_get_account(m,id_addr);
	LinphoneAuthInfo *ai;
	bool_t create_account=FALSE;
210 211 212 213
	const LinphoneAuthInfo *original_ai = linphone_core_find_auth_info(lc
																		,NULL
																		, linphone_address_get_username(id_addr)
																		, linphone_address_get_domain(id_addr));
214
	const char *phone_alias = cm->phone_alias;
215

216 217 218 219 220
	if (!account||(phone_alias&&(!account->phone_alias||strcmp(phone_alias,account->phone_alias)!=0))){
		if (account) {
			m->accounts=bctbx_list_remove(m->accounts,account);
			account_destroy(account);
		}
221
		account=account_new(id_addr,m->unique_id);
222
		account->phone_alias=ms_strdup(phone_alias);
223 224
		ms_message("No account for %s exists, going to create one.",identity);
		create_account=TRUE;
225
		m->accounts=bctbx_list_append(m->accounts,account);
226
	}
227 228
	/*modify the username of the identity of the proxy config*/
	linphone_address_set_username(id_addr, linphone_address_get_username(account->modified_identity));
229
	linphone_proxy_config_set_identity_address(cfg, id_addr);
230

231
	if (create_account){
232
		account_create_on_server(account,cfg,phone_alias);
233
	}
234

235 236 237 238 239 240 241 242 243 244
	if (liblinphone_tester_keep_uuid) {
		/* create and/or set uuid */
		if (account->uuid == NULL) {
			char tmp[64];
			sal_create_uuid(cm->lc->sal, tmp, sizeof(tmp));
			account->uuid = bctbx_strdup(tmp);
		}
		sal_set_uuid(cm->lc->sal, account->uuid);
	}

245 246 247 248
	/*remove previous auth info to avoid mismatching*/
	if (original_ai)
		linphone_core_remove_auth_info(lc,original_ai);

249 250 251 252
	ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity),
				NULL,
				account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity));
	linphone_core_add_auth_info(lc,ai);
253
	linphone_auth_info_unref(ai);
254

255 256 257 258
	linphone_address_unref(id_addr);
	return account->modified_identity;
}

259
void linphone_core_manager_check_accounts(LinphoneCoreManager *m){
260
	const bctbx_list_t *it;
261
	AccountManager *am=account_manager_get();
262
	int logmask = linphone_core_get_log_level_mask();
263 264
	
	if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
265
	for(it=linphone_core_get_proxy_config_list(m->lc);it!=NULL;it=it->next){
266
		LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data;
267
		account_manager_check_account(am,cfg,m);
268
	}
269
	if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(logmask);
270
}