1 /*
2 tester - liblinphone test suite
3 Copyright (C) 2013 Belledonne Communications SARL
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "liblinphone_tester.h"
20 #include "private.h"
21
22 struct _Account{
23 LinphoneAddress *identity;
24 LinphoneAddress *modified_identity;
25 char *password;
26 int registered;
27 int done;
28 int created;
29 char *phone_alias;
30 };
31
32 typedef struct _Account Account;
33
account_new(LinphoneAddress * identity,const char * unique_id)34 static Account *account_new(LinphoneAddress *identity, const char *unique_id){
35 char *modified_username;
36 Account *obj=ms_new0(Account,1);
37
38 /* we need to inhibit leak detector because the two LinphoneAddress will remain behond the scope of the test being run */
39 belle_sip_object_inhibit_leak_detector(TRUE);
40 obj->identity=linphone_address_clone(identity);
41 obj->password=sal_get_random_token(8);
42 obj->phone_alias = NULL;
43 obj->modified_identity=linphone_address_clone(identity);
44 modified_username=ms_strdup_printf("%s_%s",linphone_address_get_username(identity), unique_id);
45 linphone_address_set_username(obj->modified_identity, modified_username);
46 ms_free(modified_username);
47 belle_sip_object_inhibit_leak_detector(FALSE);
48 return obj;
49 };
50
account_destroy(Account * obj)51 void account_destroy(Account *obj){
52 linphone_address_unref(obj->identity);
53 linphone_address_unref(obj->modified_identity);
54 ms_free(obj->password);
55 ms_free(obj);
56 }
57
58 struct _AccountManager{
59 char *unique_id;
60 bctbx_list_t *accounts;
61 };
62
63 typedef struct _AccountManager AccountManager;
64
65 static AccountManager *the_am=NULL;
66
account_manager_get(void)67 AccountManager *account_manager_get(void){
68 if (the_am==NULL){
69 the_am=ms_new0(AccountManager,1);
70 the_am->unique_id=sal_get_random_token(6);
71 }
72 return the_am;
73 }
74
account_manager_destroy(void)75 void account_manager_destroy(void){
76 if (the_am){
77 ms_free(the_am->unique_id);
78 bctbx_list_free_with_data(the_am->accounts,(void(*)(void*))account_destroy);
79 ms_free(the_am);
80 }
81 the_am=NULL;
82 ms_message("Test account manager destroyed.");
83 }
84
account_manager_get_account(AccountManager * m,const LinphoneAddress * identity)85 Account *account_manager_get_account(AccountManager *m, const LinphoneAddress *identity){
86 bctbx_list_t *it;
87
88 for(it=m->accounts;it!=NULL;it=it->next){
89 Account *a=(Account*)it->data;
90 if (linphone_address_weak_equal(a->identity,identity)){
91 return a;
92 }
93 }
94 return NULL;
95 }
96
account_created_on_server_cb(LinphoneCore * lc,LinphoneProxyConfig * cfg,LinphoneRegistrationState state,const char * info)97 static void account_created_on_server_cb(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *info){
98 Account *account=(Account*)linphone_core_get_user_data(lc);
99 switch(state){
100 case LinphoneRegistrationOk: {
101 char * phrase = sal_op_get_error_info((SalOp*)cfg->op)->full_string;
102 if (phrase && strcasecmp("Test account created", phrase) == 0) {
103 account->created=1;
104 } else {
105 account->registered=1;
106 }
107 break;
108 }
109 case LinphoneRegistrationCleared:
110 account->done=1;
111 break;
112 default:
113 break;
114 }
115 }
116
117 // TEMPORARY CODE: remove function below when flexisip is updated, this is not needed anymore!
118 // The new flexisip now answer "200 Test account created" when creating a test account, and do not
119 // challenge authentication anymore! so this code is not used for newer version
account_created_auth_requested_cb(LinphoneCore * lc,const char * username,const char * realm,const char * domain)120 static void account_created_auth_requested_cb(LinphoneCore *lc, const char *username, const char *realm, const char *domain){
121 Account *account=(Account*)linphone_core_get_user_data(lc);
122 account->created=1;
123 }
124 // TEMPORARY CODE: remove line above when flexisip is updated, this is not needed anymore!
125
account_create_on_server(Account * account,const LinphoneProxyConfig * refcfg,const char * phone_alias)126 void account_create_on_server(Account *account, const LinphoneProxyConfig *refcfg, const char* phone_alias){
127 LinphoneCoreVTable vtable={0};
128 LinphoneCore *lc;
129 LinphoneAddress *tmp_identity=linphone_address_clone(account->modified_identity);
130 LinphoneProxyConfig *cfg;
131 LinphoneAuthInfo *ai;
132 char *tmp;
133 LinphoneAddress *server_addr;
134 LinphoneSipTransports tr;
135 char *chatdb;
136
137 vtable.registration_state_changed=account_created_on_server_cb;
138 // TEMPORARY CODE: remove line below when flexisip is updated, this is not needed anymore!
139 vtable.auth_info_requested=account_created_auth_requested_cb;
140 lc=configure_lc_from(&vtable,bc_tester_get_resource_dir_prefix(),NULL,account);
141 chatdb = ms_strdup(linphone_core_get_chat_database_path(lc));
142 tr.udp_port=LC_SIP_TRANSPORT_RANDOM;
143 tr.tcp_port=LC_SIP_TRANSPORT_RANDOM;
144 tr.tls_port=LC_SIP_TRANSPORT_RANDOM;
145 linphone_core_set_sip_transports(lc,&tr);
146
147 cfg=linphone_core_create_proxy_config(lc);
148 linphone_address_set_secure(tmp_identity, FALSE);
149 linphone_address_set_password(tmp_identity,account->password);
150 linphone_address_set_header(tmp_identity,"X-Create-Account","yes");
151 if (phone_alias) linphone_address_set_header(tmp_identity, "X-Phone-Alias", phone_alias);
152 tmp=linphone_address_as_string(tmp_identity);
153 linphone_proxy_config_set_identity(cfg,tmp);
154 ms_free(tmp);
155 linphone_address_unref(tmp_identity);
156
157 server_addr=linphone_address_new(linphone_proxy_config_get_server_addr(refcfg));
158 linphone_address_set_secure(server_addr, FALSE);
159 linphone_address_set_transport(server_addr,LinphoneTransportTcp); /*use tcp for account creation, we may not have certificates configured at this stage*/
160 linphone_address_set_port(server_addr,0);
161 tmp=linphone_address_as_string(server_addr);
162 linphone_proxy_config_set_server_addr(cfg,tmp);
163 ms_free(tmp);
164 linphone_address_unref(server_addr);
165 linphone_proxy_config_set_expires(cfg,3*3600); //accounts are valid 3 hours
166
167 linphone_core_add_proxy_config(lc,cfg);
168 /*wait 25 seconds, since the DNS SRV resolution may take a while - and
169 especially if router does NOT support DNS SRV and we have to wait its timeout*/
170 if (wait_for_until(lc,NULL,&account->created,1,25000)==FALSE){
171 ms_fatal("Account for %s could not be created on server.", linphone_proxy_config_get_identity(refcfg));
172 }
173 linphone_proxy_config_edit(cfg);
174 tmp_identity=linphone_address_clone(account->modified_identity);
175 linphone_address_set_secure(tmp_identity, FALSE);
176 tmp=linphone_address_as_string(tmp_identity);
177 linphone_proxy_config_set_identity(cfg,tmp); /*remove the X-Create-Account header*/
178 linphone_address_unref(tmp_identity);
179 ms_free(tmp);
180 linphone_proxy_config_done(cfg);
181
182 ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity),
183 NULL,
184 account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity));
185 linphone_core_add_auth_info(lc,ai);
186 linphone_auth_info_unref(ai);
187
188 if (wait_for_until(lc,NULL,&account->registered,1,3000)==FALSE){
189 ms_fatal("Account for %s is not working on server.", linphone_proxy_config_get_identity(refcfg));
190 }
191 linphone_core_remove_proxy_config(lc,cfg);
192 linphone_proxy_config_unref(cfg);
193 if (wait_for_until(lc,NULL,&account->done,1,3000)==FALSE){
194 ms_error("Account creation could not clean the registration context.");
195 }
196 linphone_core_unref(lc);
197 unlink(chatdb);
198 ms_free(chatdb);
199 }
200
account_manager_check_account(AccountManager * m,LinphoneProxyConfig * cfg,const char * phone_alias)201 static LinphoneAddress *account_manager_check_account(AccountManager *m, LinphoneProxyConfig *cfg,const char* phone_alias){
202 LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
203 const char *identity=linphone_proxy_config_get_identity(cfg);
204 LinphoneAddress *id_addr=linphone_address_new(identity);
205 Account *account=account_manager_get_account(m,id_addr);
206 LinphoneAuthInfo *ai;
207 bool_t create_account=FALSE;
208 const LinphoneAuthInfo *original_ai = linphone_core_find_auth_info(lc
209 ,NULL
210 , linphone_address_get_username(id_addr)
211 , linphone_address_get_domain(id_addr));
212
213 if (!account||(phone_alias&&(!account->phone_alias||strcmp(phone_alias,account->phone_alias)!=0))){
214 if (account) {
215 m->accounts=bctbx_list_remove(m->accounts,account);
216 account_destroy(account);
217 }
218 account=account_new(id_addr,m->unique_id);
219 account->phone_alias=ms_strdup(phone_alias);
220 ms_message("No account for %s exists, going to create one.",identity);
221 create_account=TRUE;
222 m->accounts=bctbx_list_append(m->accounts,account);
223 }
224 /*modify the username of the identity of the proxy config*/
225 linphone_address_set_username(id_addr, linphone_address_get_username(account->modified_identity));
226 linphone_proxy_config_set_identity_address(cfg, id_addr);
227
228 if (create_account){
229 account_create_on_server(account,cfg,phone_alias);
230 }
231
232 /*remove previous auth info to avoid mismatching*/
233 if (original_ai)
234 linphone_core_remove_auth_info(lc,original_ai);
235
236 ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity),
237 NULL,
238 account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity));
239 linphone_core_add_auth_info(lc,ai);
240 linphone_auth_info_unref(ai);
241
242 linphone_address_unref(id_addr);
243 return account->modified_identity;
244 }
245
linphone_core_manager_check_accounts(LinphoneCoreManager * m)246 void linphone_core_manager_check_accounts(LinphoneCoreManager *m){
247 const bctbx_list_t *it;
248 AccountManager *am=account_manager_get();
249 int logmask = ortp_get_log_level_mask(NULL);
250
251 if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
252 for(it=linphone_core_get_proxy_config_list(m->lc);it!=NULL;it=it->next){
253 LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data;
254 account_manager_check_account(am,cfg,m->phone_alias);
255 }
256 if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(logmask);
257 }
258