sal_impl.c 38.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
linphone
Copyright (C) 2012  Belledonne Communications, Grenoble, France

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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
19

20
#include "sal_impl.h"
21

22 23 24
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
25 26 27 28

typedef struct belle_sip_certificates_chain_t _SalCertificatesChain;
typedef struct belle_sip_signing_key_t _SalSigningKey;

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/*
rfc3323
4.2 Expressing Privacy Preferences
When a Privacy header is constructed, it MUST consist of either the
   value 'none', or one or more of the values 'user', 'header' and
   'session' (each of which MUST appear at most once) which MAY in turn
   be followed by the 'critical' indicator.
 */
void sal_op_set_privacy_from_message(SalOp* op,belle_sip_message_t* msg) {
	belle_sip_header_privacy_t* privacy = belle_sip_message_get_header_by_type(msg,belle_sip_header_privacy_t);
	if (!privacy) {
		sal_op_set_privacy(op,SalPrivacyNone);
	} else {
		belle_sip_list_t* privacy_list=belle_sip_header_privacy_get_privacy(privacy);
		sal_op_set_privacy(op,0);
		for (;privacy_list!=NULL;privacy_list=privacy_list->next) {
			char* privacy_value=(char*)privacy_list->data;
			if(strcmp(sal_privacy_to_string(SalPrivacyCritical),privacy_value) == 0)
				sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyCritical);
			if(strcmp(sal_privacy_to_string(SalPrivacyHeader),privacy_value) == 0)
							sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyHeader);
			if(strcmp(sal_privacy_to_string(SalPrivacyId),privacy_value) == 0)
							sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyId);
			if(strcmp(sal_privacy_to_string(SalPrivacyNone),privacy_value) == 0) {
				sal_op_set_privacy(op,SalPrivacyNone);
				break;
			}
			if(strcmp(sal_privacy_to_string(SalPrivacySession),privacy_value) == 0)
							sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacySession);
			if(strcmp(sal_privacy_to_string(SalPrivacyUser),privacy_value) == 0)
										sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyUser);
		}
	}
}
63 64
static void set_tls_properties(Sal *ctx);

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) {
	int ortp_level;
	switch(lev) {
		case BELLE_SIP_LOG_FATAL:
			ortp_level=ORTP_FATAL;
		break;
		case BELLE_SIP_LOG_ERROR:
			ortp_level=ORTP_ERROR;
		break;
		case BELLE_SIP_LOG_WARNING:
			ortp_level=ORTP_WARNING;
		break;
		case BELLE_SIP_LOG_MESSAGE:
			ortp_level=ORTP_MESSAGE;
		break;
		case BELLE_SIP_LOG_DEBUG:
jehan's avatar
jehan committed
81
		default:
jehan's avatar
jehan committed
82
			ortp_level=ORTP_DEBUG;
jehan's avatar
jehan committed
83
			break;
84 85 86 87 88 89
	}
	if (ortp_log_level_enabled(ortp_level)){
		ortp_logv(ortp_level,fmt,args);
	}
}

90 91 92
void sal_enable_logs(){
	belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE);
}
Simon Morlat's avatar
Simon Morlat committed
93

94 95 96
void sal_disable_logs() {
	belle_sip_set_log_level(BELLE_SIP_LOG_ERROR);
}
Simon Morlat's avatar
Simon Morlat committed
97

98
void sal_add_pending_auth(Sal *sal, SalOp *op){
99
	if (ms_list_find(sal->pending_auths,op)==NULL){
Simon Morlat's avatar
Simon Morlat committed
100
		sal->pending_auths=ms_list_append(sal->pending_auths,op);
101
		op->has_auth_pending=TRUE;
102
	}
103 104
}

Simon Morlat's avatar
Simon Morlat committed
105
void sal_remove_pending_auth(Sal *sal, SalOp *op){
106 107 108 109 110
	if (op->has_auth_pending){
		op->has_auth_pending=FALSE;
		if (ms_list_find(sal->pending_auths,op)){
			sal->pending_auths=ms_list_remove(sal->pending_auths,op);
		}
111
	}
112 113
}

114
void sal_process_authentication(SalOp *op) {
115 116
	belle_sip_request_t* initial_request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction);
	belle_sip_request_t* new_request;
jehan's avatar
jehan committed
117
	bool_t is_within_dialog=FALSE;
118 119
	belle_sip_list_t* auth_list=NULL;
	belle_sip_auth_event_t* auth_event;
120
	belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction);
121 122
	belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t);
	belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from);
123

124 125 126 127
	if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){
		/*prefer using the from from the SalOp*/
		from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)sal_op_get_from_address(op));
	}
128

jehan's avatar
jehan committed
129
	if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) {
130 131 132
		new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request);
		if (!new_request)
			new_request = belle_sip_dialog_create_queued_request_from(op->dialog,initial_request);
jehan's avatar
jehan committed
133 134
		is_within_dialog=TRUE;
	} else {
135 136 137
		new_request=initial_request;
		belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_AUTHORIZATION);
		belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_PROXY_AUTHORIZATION);
jehan's avatar
jehan committed
138
	}
139
	if (new_request==NULL) {
Simon Morlat's avatar
Simon Morlat committed
140 141 142
		ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",op);
		return;
	}
143

144
	if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,from_uri,&auth_list,op->base.realm)) {
jehan's avatar
jehan committed
145
		if (is_within_dialog) {
146
			sal_op_send_request(op,new_request);
147
		} else {
148
			sal_op_resend_request(op,new_request);
jehan's avatar
jehan committed
149
		}
150
		sal_remove_pending_auth(op->base.root,op);
jehan's avatar
jehan committed
151
	}else {
152 153 154 155
		belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(response,belle_sip_header_from_t);
		char *tmp=belle_sip_object_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)));
		ms_message("No auth info found for [%s]",tmp);
		belle_sip_free(tmp);
156 157
		sal_add_pending_auth(op->base.root,op);

jehan's avatar
jehan committed
158
		if (is_within_dialog) {
159
			belle_sip_object_unref(new_request);
jehan's avatar
jehan committed
160
		}
161 162
	}
	/*always store auth info, for case of wrong credential*/
Simon Morlat's avatar
Simon Morlat committed
163 164 165 166
	if (op->auth_info) {
		sal_auth_info_delete(op->auth_info);
		op->auth_info=NULL;
	}
167 168 169 170
	if (auth_list){
		auth_event=(belle_sip_auth_event_t*)(auth_list->data);
		op->auth_info=sal_auth_info_create(auth_event);
		belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy);
171 172
	}
}
Simon Morlat's avatar
Simon Morlat committed
173

174
static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){
Simon Morlat's avatar
Simon Morlat committed
175
	belle_sip_dialog_t* dialog =  belle_sip_dialog_terminated_event_get_dialog(event);
176
	SalOp* op = belle_sip_dialog_get_application_data(dialog);
177 178
	if (op && op->callbacks && op->callbacks->process_dialog_terminated) {
		op->callbacks->process_dialog_terminated(op,event);
179
	} else {
180
		ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog);
181
	}
182
}
Simon Morlat's avatar
Simon Morlat committed
183

184
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
jehan's avatar
jehan committed
185 186
	belle_sip_client_transaction_t*client_transaction;
	SalOp* op;
187
	if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_client_transaction_t)) {
jehan's avatar
jehan committed
188 189
		client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event));
		op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
190 191
		/*also reset auth count on IO error*/
		op->auth_requests=0;
192 193
		if (op->callbacks && op->callbacks->process_io_error) {
			op->callbacks->process_io_error(op,event);
jehan's avatar
jehan committed
194 195
		}
	} else {
196 197
		/*ms_error("sal process_io_error not implemented yet for non transaction");*/
		/*nop, because already handle at transaction layer*/
jehan's avatar
jehan committed
198
	}
199
}
Simon Morlat's avatar
Simon Morlat committed
200

201 202
static void process_request_event(void *ud, const belle_sip_request_event_t *event) {
	Sal *sal=(Sal*)ud;
jehan's avatar
jehan committed
203
	SalOp* op=NULL;
jehan's avatar
jehan committed
204 205 206 207
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event);
	belle_sip_header_address_t* origin_address;
	belle_sip_header_address_t* address;
jehan's avatar
jehan committed
208
	belle_sip_header_from_t* from_header;
jehan's avatar
jehan committed
209
	belle_sip_header_to_t* to;
jehan's avatar
jehan committed
210
	belle_sip_response_t* resp;
211
	belle_sip_header_t *evh;
212
	const char *method=belle_sip_request_get_method(req);
213
	belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t);
214

jehan's avatar
jehan committed
215 216
	from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);

jehan's avatar
jehan committed
217 218
	if (dialog) {
		op=(SalOp*)belle_sip_dialog_get_application_data(dialog);
219
		if (op==NULL || op->state==SalOpStateTerminated){
220 221 222
			ms_warning("Receiving request for null or terminated op [%p], ignored",op);
			return;
		}
223
	}else if (strcmp("INVITE",method)==0) {
224
		op=sal_op_new(sal);
jehan's avatar
jehan committed
225
		op->dir=SalOpDirIncoming;
jehan's avatar
jehan committed
226
		sal_op_call_fill_cbs(op);
227
	}else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) {
228
		op=sal_op_new(sal);
jehan's avatar
jehan committed
229
		op->dir=SalOpDirIncoming;
230 231 232 233
		if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){
			sal_op_presence_fill_cbs(op);
		}else
			sal_op_subscribe_fill_cbs(op);
234
	}else if (strcmp("MESSAGE",method)==0) {
235
		op=sal_op_new(sal);
236 237
		op->dir=SalOpDirIncoming;
		sal_op_message_fill_cbs(op);
238
	}else if (strcmp("OPTIONS",method)==0) {
239
		resp=belle_sip_response_create_from_request(req,200);
240
		belle_sip_provider_send_response(sal->prov,resp);
241
		return;
242
	}else if (strcmp("INFO",method)==0) {
243
		resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/
244
		belle_sip_provider_send_response(sal->prov,resp);
245
		return;
246 247
	}else if (strcmp("BYE",method)==0) {
		resp=belle_sip_response_create_from_request(req,481);/*out of dialog BYE */
248
		belle_sip_provider_send_response(sal->prov,resp);
249 250 251 252
		return;
	}else if (strcmp("CANCEL",method)==0) {
		resp=belle_sip_response_create_from_request(req,481);/*out of dialog CANCEL */
		belle_sip_provider_send_response(sal->prov,resp);
253 254 255 256 257
		return;
	}else if (sal->enable_test_features && strcmp("PUBLISH",method)==0) {
		resp=belle_sip_response_create_from_request(req,200);/*out of dialog BYE */
		belle_sip_message_add_header((belle_sip_message_t*)resp,belle_sip_header_create("SIP-Etag","4441929FFFZQOA"));
		belle_sip_provider_send_response(sal->prov,resp);
258
		return;
259
	}else {
jehan's avatar
jehan committed
260
		ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req));
jehan's avatar
jehan committed
261 262 263
		resp=belle_sip_response_create_from_request(req,405);
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp)
									,BELLE_SIP_HEADER(belle_sip_header_allow_create("INVITE, CANCEL, ACK, BYE, SUBSCRIBE, NOTIFY, MESSAGE, OPTIONS, INFO")));
264
		belle_sip_provider_send_response(sal->prov,resp);
jehan's avatar
jehan committed
265
		return;
jehan's avatar
jehan committed
266 267 268
	}

	if (!op->base.from_address)  {
jehan's avatar
jehan committed
269 270
		address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
														,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
jehan's avatar
jehan committed
271 272 273
		sal_op_set_from_address(op,(SalAddress*)address);
		belle_sip_object_unref(address);
	}
jehan's avatar
jehan committed
274

275 276 277
	if( remote_contact ){
		__sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact)));
	}
jehan's avatar
jehan committed
278

jehan's avatar
jehan committed
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
	if (!op->base.to_address) {
		to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t);
		address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to))
												,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)));
		sal_op_set_to_address(op,(SalAddress*)address);
		belle_sip_object_unref(address);
	}

	if (!op->base.origin) {
		/*set origin uri*/
		origin_address=belle_sip_header_address_create(NULL,belle_sip_request_extract_origin(req));
		__sal_op_set_network_origin_address(op,(SalAddress*)origin_address);
		belle_sip_object_unref(origin_address);
	}
	if (!op->base.remote_ua) {
		sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(req));
	}

jehan's avatar
jehan committed
297 298 299
	if (!op->base.call_id) {
		op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_call_id_t))));
	}
300 301 302 303
	/*It is worth noting that proxies can (and
   will) remove this header field*/
	sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req);

Simon Morlat's avatar
Simon Morlat committed
304
	sal_op_assign_recv_headers(op,(belle_sip_message_t*)req);
305 306
	if (op->callbacks && op->callbacks->process_request_event) {
		op->callbacks->process_request_event(op,event);
jehan's avatar
jehan committed
307 308 309 310
	} else {
		ms_error("sal process_request_event not implemented yet");
	}

311 312 313 314 315
}

static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_response_t* response = belle_sip_response_event_get_response(event);
316
	int response_code = belle_sip_response_get_status_code(response);
317

318
	if (!client_transaction) {
319
		ms_warning("Discarding stateless response [%i]",response_code);
320
		return;
321 322 323
	} else {
		SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
		belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
324
		belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t);
325 326 327 328 329

		if (op->state == SalOpStateTerminated) {
			belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code);
			return;
		}
330 331
		/*do it all the time, since we can receive provisional responses from a different instance than the final one*/
		sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response));
332 333 334 335 336

		if(remote_contact) {
			__sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact)));
		}

jehan's avatar
jehan committed
337 338 339
		if (!op->base.call_id) {
			op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t))));
		}
340

341
		sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);
342

343
		if (op->callbacks && op->callbacks->process_response_event) {
344
			/*handle authorization*/
345
			switch (response_code) {
346
				case 200:
347 348
					break;
				case 401:
349
				case 407:
350 351 352 353 354 355 356 357
					if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) {
						/*only bye are completed*/
						belle_sip_message("Op is in state terminating, nothing else to do ");
					} else {
						if (op->pending_auth_transaction){
							belle_sip_object_unref(op->pending_auth_transaction);
							op->pending_auth_transaction=NULL;
						}
358
						if (++op->auth_requests > 2) {
359 360
							ms_warning("Auth info cannot be found for op [%s/%s] after 2 attempts, giving up",sal_op_get_from(op)
																												,sal_op_get_to(op));
361 362 363 364 365 366 367
							op->base.root->callbacks.auth_failure(op,op->auth_info);
							sal_remove_pending_auth(op->base.root,op);
						} else {
							op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
							sal_process_authentication(op);
							return;
						}
368
					}
369 370 371 372
					break;
				case 403:
					if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info);
					break;
jehan's avatar
jehan committed
373
			}
374
			if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) {
375 376 377
				/*not an auth request*/
				op->auth_requests=0;
			}
378
			op->callbacks->process_response_event(op,event);
379 380 381
		} else {
			ms_error("Unhandled event response [%p]",event);
		}
382 383
	}
}
Simon Morlat's avatar
Simon Morlat committed
384

385
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
386
	belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event);
387
	SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
388 389
	if (op && op->callbacks && op->callbacks->process_timeout) {
		op->callbacks->process_timeout(op,event);
390
	} else {
391 392 393
		ms_error("Unhandled event timeout [%p]",event);
	}
}
Simon Morlat's avatar
Simon Morlat committed
394

395
static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
396 397
	belle_sip_client_transaction_t* client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event);
	belle_sip_server_transaction_t* server_transaction = belle_sip_transaction_terminated_event_get_server_transaction(event);
398
	belle_sip_transaction_t* trans;
399 400
	SalOp* op;

401 402 403
	if(client_transaction)
		trans=BELLE_SIP_TRANSACTION(client_transaction);
	 else
Simon Morlat's avatar
Simon Morlat committed
404
		trans=BELLE_SIP_TRANSACTION(server_transaction);
405

406
	op = (SalOp*)belle_sip_transaction_get_application_data(trans);
407 408
	if (op && op->callbacks && op->callbacks->process_transaction_terminated) {
		op->callbacks->process_transaction_terminated(op,event);
409
	} else {
410
		ms_message("Unhandled transaction terminated [%p]",trans);
411
	}
Simon Morlat's avatar
Simon Morlat committed
412
	if (op) sal_op_unref(op); /*because every transaction ref op*/
413
}
414

415 416 417

static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) {
	SalAuthInfo* auth_info = sal_auth_info_create(event);
jehan's avatar
jehan committed
418
	((Sal*)sal)->callbacks.auth_requested(sal,auth_info);
419 420 421 422 423
	belle_sip_auth_event_set_passwd(event,(const char*)auth_info->password);
	belle_sip_auth_event_set_ha1(event,(const char*)auth_info->ha1);
	belle_sip_auth_event_set_userid(event,(const char*)auth_info->userid);
	belle_sip_auth_event_set_signing_key(event,(belle_sip_signing_key_t *)auth_info->key);
	belle_sip_auth_event_set_client_certificates_chain(event,(belle_sip_certificates_chain_t* )auth_info->certificates);
jehan's avatar
jehan committed
424
	sal_auth_info_delete(auth_info);
jehan's avatar
jehan committed
425
}
426

427
Sal * sal_init(){
428
	belle_sip_listener_callbacks_t listener_callbacks;
429
	Sal * sal=ms_new0(Sal,1);
430

431
	/*belle_sip_object_enable_marshal_check(TRUE);*/
432
	sal->auto_contacts=TRUE;
433

434 435 436
	/*first create the stack, which initializes the belle-sip object's pool for this thread*/
	belle_sip_set_log_handler(_belle_sip_log);
	sal->stack = belle_sip_stack_new(NULL);
437

jehan's avatar
jehan committed
438
	sal->user_agent=belle_sip_header_user_agent_new();
jehan's avatar
jehan committed
439 440
#if defined(PACKAGE_NAME) && defined(LIBLINPHONE_VERSION)
	belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LIBLINPHONE_VERSION);
jehan's avatar
jehan committed
441
#endif
442
	sal_append_stack_string_to_user_agent(sal);
jehan's avatar
jehan committed
443
	belle_sip_object_ref(sal->user_agent);
444

445
	sal->prov = belle_sip_stack_create_provider(sal->stack,NULL);
446
	sal_nat_helper_enable(sal,TRUE);
447 448 449 450 451 452 453 454 455 456
	memset(&listener_callbacks,0,sizeof(listener_callbacks));
	listener_callbacks.process_dialog_terminated=process_dialog_terminated;
	listener_callbacks.process_io_error=process_io_error;
	listener_callbacks.process_request_event=process_request_event;
	listener_callbacks.process_response_event=process_response_event;
	listener_callbacks.process_timeout=process_timeout;
	listener_callbacks.process_transaction_terminated=process_transaction_terminated;
	listener_callbacks.process_auth_requested=process_auth_requested;
	sal->listener=belle_sip_listener_create_from_callbacks(&listener_callbacks,sal);
	belle_sip_provider_add_sip_listener(sal->prov,sal->listener);
457 458
	sal->tls_verify=TRUE;
	sal->tls_verify_cn=TRUE;
jehan's avatar
jehan committed
459
	sal->refresher_retry_after=60000; /*default value in ms*/
460
	sal->enable_sip_update=TRUE;
461 462
	return sal;
}
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
void sal_set_user_pointer(Sal *sal, void *user_data){
	sal->up=user_data;
}

void *sal_get_user_pointer(const Sal *sal){
	return sal->up;
}

static void unimplemented_stub(){
	ms_warning("Unimplemented SAL callback");
}

void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
	memcpy(&ctx->callbacks,cbs,sizeof(*cbs));
	if (ctx->callbacks.call_received==NULL)
		ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub;
	if (ctx->callbacks.call_ringing==NULL)
		ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub;
	if (ctx->callbacks.call_accepted==NULL)
		ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub;
	if (ctx->callbacks.call_failure==NULL)
		ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;
	if (ctx->callbacks.call_terminated==NULL)
		ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;
	if (ctx->callbacks.call_released==NULL)
		ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub;
	if (ctx->callbacks.call_updating==NULL)
		ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;
jehan's avatar
jehan committed
492 493
	if (ctx->callbacks.auth_failure==NULL)
		ctx->callbacks.auth_failure=(SalOnAuthFailure)unimplemented_stub;
494 495 496 497 498 499 500 501 502 503
	if (ctx->callbacks.register_success==NULL)
		ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub;
	if (ctx->callbacks.register_failure==NULL)
		ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub;
	if (ctx->callbacks.dtmf_received==NULL)
		ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub;
	if (ctx->callbacks.notify==NULL)
		ctx->callbacks.notify=(SalOnNotify)unimplemented_stub;
	if (ctx->callbacks.subscribe_received==NULL)
		ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;
504 505
	if (ctx->callbacks.subscribe_closed==NULL)
		ctx->callbacks.subscribe_closed=(SalOnSubscribeClosed)unimplemented_stub;
506 507
	if (ctx->callbacks.parse_presence_requested==NULL)
		ctx->callbacks.parse_presence_requested=(SalOnParsePresenceRequested)unimplemented_stub;
508 509
	if (ctx->callbacks.convert_presence_to_xml_requested==NULL)
		ctx->callbacks.convert_presence_to_xml_requested=(SalOnConvertPresenceToXMLRequested)unimplemented_stub;
510 511 512 513
	if (ctx->callbacks.notify_presence==NULL)
		ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;
	if (ctx->callbacks.subscribe_presence_received==NULL)
		ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub;
514 515
	if (ctx->callbacks.text_received==NULL)
		ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
516 517
	if (ctx->callbacks.is_composing_received==NULL)
		ctx->callbacks.is_composing_received=(SalOnIsComposingReceived)unimplemented_stub;
518 519 520 521
	if (ctx->callbacks.ping_reply==NULL)
		ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;
	if (ctx->callbacks.auth_requested==NULL)
		ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;
Simon Morlat's avatar
Simon Morlat committed
522 523
	if (ctx->callbacks.info_received==NULL)
		ctx->callbacks.info_received=(SalOnInfoReceived)unimplemented_stub;
524 525 526 527
	if (ctx->callbacks.on_publish_response==NULL)
		ctx->callbacks.on_publish_response=(SalOnPublishResponse)unimplemented_stub;
	if (ctx->callbacks.on_expire==NULL)
		ctx->callbacks.on_expire=(SalOnExpire)unimplemented_stub;
528 529 530 531 532
}



void sal_uninit(Sal* sal){
jehan's avatar
jehan committed
533
	belle_sip_object_unref(sal->user_agent);
534 535
	belle_sip_object_unref(sal->prov);
	belle_sip_object_unref(sal->stack);
536
	belle_sip_object_unref(sal->listener);
537 538
	if (sal->supported) belle_sip_object_unref(sal->supported);
	ms_list_free_with_data(sal->supported_tags,ms_free);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
539
	if (sal->uuid) ms_free(sal->uuid);
540
	if (sal->root_ca) ms_free(sal->root_ca);
541 542 543
	ms_free(sal);
};

Simon Morlat's avatar
Simon Morlat committed
544 545 546 547 548 549 550 551 552 553 554 555 556
int sal_transport_available(Sal *sal, SalTransport t){
	switch(t){
		case SalTransportUDP:
		case SalTransportTCP:
			return TRUE;
		case SalTransportTLS:
			return belle_sip_stack_tls_available(sal->stack);
		case SalTransportDTLS:
			return FALSE;
	}
	return FALSE;
}

557
static int sal_add_listen_port(Sal *ctx, SalAddress* addr, bool_t is_tunneled){
558
	int result;
559 560
	belle_sip_listening_point_t* lp;
	if (is_tunneled){
561
#ifdef TUNNEL_ENABLED
562 563 564 565 566 567 568 569 570
		if (sal_address_get_transport(addr)!=SalTransportUDP){
			ms_error("Tunneled mode is only available for UDP kind of transports.");
			return -1;
		}
		lp = belle_sip_tunnel_listening_point_new(ctx->stack, ctx->tunnel_client);
		if (!lp){
			ms_error("Could not create tunnel listening point.");
			return -1;
		}
571 572 573 574
#else
		ms_error("No tunnel support in library.");
		return -1;
#endif
575 576
	}else{
		lp = belle_sip_stack_create_listening_point(ctx->stack,
577 578 579 580
									sal_address_get_domain(addr),
									sal_address_get_port(addr),
									sal_transport_to_string(sal_address_get_transport(addr)));
	}
581
	if (lp) {
582
		belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive);
583
		result = belle_sip_provider_add_listening_point(ctx->prov,lp);
584
		if (sal_address_get_transport(addr)==SalTransportTLS) set_tls_properties(ctx);
585 586 587 588 589
	} else {
		return -1;
	}
	return result;
}
590

591
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_tunneled) {
jehan's avatar
jehan committed
592 593 594
	SalAddress* sal_addr = sal_address_new(NULL);
	int result;
	sal_address_set_domain(sal_addr,addr);
595
	sal_address_set_port(sal_addr,port);
jehan's avatar
jehan committed
596
	sal_address_set_transport(sal_addr,tr);
597
	result = sal_add_listen_port(ctx, sal_addr, is_tunneled);
jehan's avatar
jehan committed
598 599 600
	sal_address_destroy(sal_addr);
	return result;
}
601

602 603 604
static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) {
	belle_sip_provider_remove_listening_point(prov,lp);
}
605 606 607 608 609 610 611 612 613 614

int sal_get_listening_port(Sal *ctx, SalTransport tr){
	const char *tpn=sal_transport_to_string(tr);
	belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov, tpn);
	if (lp){
		return belle_sip_listening_point_get_port(lp);
	}
	return 0;
}

615 616 617 618 619 620 621 622
int sal_unlisten_ports(Sal *ctx){
	const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov);
	belle_sip_list_t * tmp_list = belle_sip_list_copy(lps);
	belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov);
	belle_sip_list_free(tmp_list);
	ms_message("sal_unlisten_ports done");
	return 0;
}
623

624
ortp_socket_t sal_get_socket(Sal *ctx){
jehan's avatar
jehan committed
625
	ms_warning("sal_get_socket is deprecated");
626 627
	return -1;
}
628

629
void sal_set_user_agent(Sal *ctx, const char *user_agent){
jehan's avatar
jehan committed
630 631
	belle_sip_header_user_agent_set_products(ctx->user_agent,NULL);
	belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent);
632 633
	return ;
}
634

635 636 637 638 639 640
const char* sal_get_user_agent(Sal *ctx){
	static char user_agent[255];
	belle_sip_header_user_agent_get_products_as_string(ctx->user_agent, user_agent, 254);
	return user_agent;
}

641 642 643 644 645 646
void sal_append_stack_string_to_user_agent(Sal *ctx) {
	char stack_string[64];
	snprintf(stack_string, sizeof(stack_string) - 1, "(belle-sip/%s)", belle_sip_version_to_string());
	belle_sip_header_user_agent_add_product(ctx->user_agent, stack_string);
}

647 648
/*keepalive period in ms*/
void sal_set_keepalive_period(Sal *ctx,unsigned int value){
649
	const belle_sip_list_t* iterator;
650
	belle_sip_listening_point_t* lp;
651 652
	ctx->keep_alive=value;
	for (iterator=belle_sip_provider_get_listening_points(ctx->prov);iterator!=NULL;iterator=iterator->next) {
653 654 655 656
		lp=(belle_sip_listening_point_t*)iterator->data;
		if (ctx->use_tcp_tls_keep_alive || strcasecmp(belle_sip_listening_point_get_transport(lp),"udp")==0) {
			belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive);
		}
657
	}
658
}
659
int sal_set_tunnel(Sal *ctx, void *tunnelclient) {
660
#ifdef TUNNEL_ENABLED
661
	ctx->tunnel_client=tunnelclient;
662
	return 0;
663
#else
664
	return -1;
665
#endif
666
}
667

668 669 670 671 672
/**
 * returns keepalive period in ms
 * 0 desactiaved
 * */
unsigned int sal_get_keepalive_period(Sal *ctx){
673
	return ctx->keep_alive;
674 675
}
void sal_use_session_timers(Sal *ctx, int expires){
676
	ctx->session_expires=expires;
677 678
	return ;
}
679

680
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){
jehan's avatar
jehan committed
681
	ctx->one_matching_codec=one_matching_codec;
682
}
683

684
void sal_use_rport(Sal *ctx, bool_t use_rports){
jehan's avatar
jehan committed
685 686
	belle_sip_provider_enable_rport(ctx->prov,use_rports);
	ms_message("Sal use rport [%s]",use_rports?"enabled":"disabled");
687 688
	return ;
}
689 690 691 692 693 694

static void set_tls_properties(Sal *ctx){
	belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov,"TLS");
	if (lp){
		belle_sip_tls_listening_point_t *tlp=BELLE_SIP_TLS_LISTENING_POINT(lp);
		int verify_exceptions=0;
695

696 697
		if (!ctx->tls_verify) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_ANY_REASON;
		else if (!ctx->tls_verify_cn) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_CN_MISMATCH;
698

jehan's avatar
jehan committed
699
		belle_sip_tls_listening_point_set_root_ca(tlp,ctx->root_ca); /*root_ca might be NULL */
700 701 702 703
		belle_sip_tls_listening_point_set_verify_exceptions(tlp,verify_exceptions);
	}
}

704
void sal_set_root_ca(Sal* ctx, const char* rootCa){
705 706 707 708 709 710 711
	if (ctx->root_ca){
		ms_free(ctx->root_ca);
		ctx->root_ca=NULL;
	}
	if (rootCa)
		ctx->root_ca=ms_strdup(rootCa);
	set_tls_properties(ctx);
712 713
	return ;
}
714

715
void sal_verify_server_certificates(Sal *ctx, bool_t verify){
716 717
	ctx->tls_verify=verify;
	set_tls_properties(ctx);
718 719
	return ;
}
720

721
void sal_verify_server_cn(Sal *ctx, bool_t verify){
722 723
	ctx->tls_verify_cn=verify;
	set_tls_properties(ctx);
724 725 726 727
	return ;
}

void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {
728
	ctx->use_tcp_tls_keep_alive=enabled;
729
}
730 731 732 733 734 735 736 737 738 739 740 741 742 743

int sal_iterate(Sal *sal){
	belle_sip_stack_sleep(sal->stack,0);
	return 0;
}
MSList * sal_get_pending_auths(Sal *sal){
	return ms_list_copy(sal->pending_auths);
}

#define payload_type_set_number(pt,n)	(pt)->user_data=(void*)((long)n);
#define payload_type_get_number(pt)		((int)(long)(pt)->user_data)

/*misc*/
void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen){
jehan's avatar
jehan committed
744
	strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen);
745
	ms_error("sal_get_default_local_ip() is deprecated.");
746
}
747 748

const char *sal_get_root_ca(Sal* ctx) {
749
	return ctx->root_ca;
750
}
751

752
int sal_reset_transports(Sal *ctx){
jehan's avatar
jehan committed
753
	ms_message("Reseting transports");
jehan's avatar
jehan committed
754 755
	belle_sip_provider_clean_channels(ctx->prov);
	return 0;
756
}
757

758
void sal_set_dscp(Sal *ctx, int dscp){
759
	belle_sip_stack_set_default_dscp(ctx->stack,dscp);
760
}
761

762 763 764
void  sal_set_send_error(Sal *sal,int value) {
	 belle_sip_stack_set_send_error(sal->stack,value);
}
jehan's avatar
jehan committed
765 766 767
void  sal_set_recv_error(Sal *sal,int value) {
	 belle_sip_provider_set_recv_error(sal->prov,value);
}
768 769
void sal_nat_helper_enable(Sal *sal,bool_t enable) {
	sal->nat_helper_enabled=enable;
770
	belle_sip_provider_enable_nat_helper(sal->prov,enable);
771 772 773 774 775
	ms_message("Sal nat helper [%s]",enable?"enabled":"disabled");
}
bool_t sal_nat_helper_enabled(Sal *sal) {
	return sal->nat_helper_enabled;
}
jehan's avatar
jehan committed
776 777 778 779 780 781
void sal_set_dns_timeout(Sal* sal,int timeout) {
	belle_sip_stack_set_dns_timeout(sal->stack, timeout);
}
int sal_get_dns_timeout(const Sal* sal)  {
	return belle_sip_stack_get_dns_timeout(sal->stack);
}
782 783 784 785 786 787 788

void sal_set_transport_timeout(Sal* sal,int timeout) {
	belle_sip_stack_set_transport_timeout(sal->stack, timeout);
}
int sal_get_transport_timeout(const Sal* sal)  {
	return belle_sip_stack_get_transport_timeout(sal->stack);
}
789 790 791 792 793 794
void sal_enable_dns_srv(Sal *sal, bool_t enable) {
	belle_sip_stack_enable_dns_srv(sal->stack, (unsigned char)enable);
}
bool_t sal_dns_srv_enabled(const Sal *sal) {
	return (bool_t)belle_sip_stack_dns_srv_enabled(sal->stack);
}
795

796 797 798 799 800 801 802 803
void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file) {
	belle_sip_stack_set_dns_user_hosts_file(sal->stack, hosts_file);
}

const char * sal_get_dns_user_hosts_file(const Sal *sal) {
	return belle_sip_stack_get_dns_user_hosts_file(sal->stack);
}

804 805
SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) {
	SalAuthInfo* auth_info = sal_auth_info_new();
806 807 808
	auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(event));
	auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event));
	auth_info->domain = ms_strdup(belle_sip_auth_event_get_domain(event));
jehan's avatar
jehan committed
809
	auth_info->mode = (SalAuthMode)belle_sip_auth_event_get_mode(event);
810 811
	return auth_info;
}
Simon Morlat's avatar
Simon Morlat committed
812

813 814 815 816 817 818 819
SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info) { return auth_info->mode; }
SalSigningKey *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info) { return auth_info->key; }
SalCertificatesChain *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info) { return auth_info->certificates; }
void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode) { auth_info->mode = mode; }
void sal_certificates_chain_delete(SalCertificatesChain *chain) {
	belle_sip_object_unref((belle_sip_object_t *)chain);
}
820
void sal_signing_key_delete(SalSigningKey *key) {
821 822 823
	belle_sip_object_unref((belle_sip_object_t *)key);
}

Simon Morlat's avatar
Simon Morlat committed
824
const char* sal_op_type_to_string(const SalOpType type) {
825 826 827 828 829 830 831 832 833
	switch(type) {
	case SalOpRegister: return "SalOpRegister";
	case SalOpCall: return "SalOpCall";
	case SalOpMessage: return "SalOpMessage";
	case SalOpPresence: return "SalOpPresence";
	default:
		return "SalOpUnknown";
	}
}
834 835 836 837

void sal_use_dates(Sal *ctx, bool_t enabled){
	ctx->use_dates=enabled;
}
838 839 840 841

int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]) {
	return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1);
}
842 843 844 845 846


SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
	belle_sip_message_t *msg=(belle_sip_message_t*)ch;
	belle_sip_header_t *h;
847

848 849
	if (msg==NULL){
		msg=(belle_sip_message_t*)belle_sip_request_new();
Simon Morlat's avatar
Simon Morlat committed
850
		belle_sip_object_ref(msg);
851
	}
852
	h=belle_sip_header_create(name,value);
853
	if (h==NULL){
854
		belle_sip_error("Fail to parse custom header.");
855 856 857 858 859 860 861
		return (SalCustomHeader*)msg;
	}
	belle_sip_message_add_header(msg,h);
	return (SalCustomHeader*)msg;
}

const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){
Simon Morlat's avatar
Simon Morlat committed
862 863
	if (ch){
		belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name);
864

Simon Morlat's avatar
Simon Morlat committed
865
		if (h){
866
			return belle_sip_header_get_unparsed_value(h);
867 868 869 870 871 872
		}
	}
	return NULL;
}

void sal_custom_header_free(SalCustomHeader *ch){
Simon Morlat's avatar
Simon Morlat committed
873
	if (ch==NULL) return;
874 875 876 877
	belle_sip_object_unref((belle_sip_message_t*)ch);
}

SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){
Simon Morlat's avatar
Simon Morlat committed
878
	if (ch==NULL) return NULL;
879 880 881
	return (SalCustomHeader*)belle_sip_object_ref((belle_sip_message_t*)ch);
}

Simon Morlat's avatar
Simon Morlat committed
882
const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op){
883
	SalOpBase *b=(SalOpBase *)op;
Simon Morlat's avatar
Simon Morlat committed
884
	return b->recv_custom_headers;
885 886
}

887 888
void sal_set_uuid(Sal *sal, const char *uuid){
	if (sal->uuid){
889
		ms_free(sal->uuid);
890 891 892
		sal->uuid=NULL;
	}
	if (uuid)
893
		sal->uuid=ms_strdup(uuid);
894 895 896
}

typedef struct {
897 898 899 900 901 902
	unsigned int time_low;
	unsigned short time_mid;
	unsigned short time_hi_and_version;
	unsigned char clock_seq_hi_and_reserved;
	unsigned char clock_seq_low;
	unsigned char node[6];
903
} sal_uuid_t;
Simon Morlat's avatar
Simon Morlat committed
904

905

906 907 908 909
int sal_create_uuid(Sal*ctx, char *uuid, size_t len){
	sal_uuid_t uuid_struct;
	int i;
	int written;
910

911 912 913 914 915 916 917
	if (len==0) return -1;
	/*create an UUID as described in RFC4122, 4.4 */
	belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t));
	uuid_struct.clock_seq_hi_and_reserved&=~(1<<6);
	uuid_struct.clock_seq_hi_and_reserved|=1<<7;
	uuid_struct.time_hi_and_version&=~(0xf<<12);
	uuid_struct.time_hi_and_version|=4<<12;
918

919 920 921 922 923 924 925 926 927 928 929 930 931
	written=snprintf(uuid,len,"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", uuid_struct.time_low, uuid_struct.time_mid,
			uuid_struct.time_hi_and_version, uuid_struct.clock_seq_hi_and_reserved,
			uuid_struct.clock_seq_low);
	if (written>len+13){
		ms_error("sal_create_uuid(): buffer is too short !");
		return -1;
	}
	for (i = 0; i < 6; i++)
		written+=snprintf(uuid+written,len-written,"%2.2x", uuid_struct.node[i]);
	uuid[len-1]='\0';
	sal_set_uuid(ctx,uuid);
	return 0;
}
932

933 934 935 936 937
static void make_supported_header(Sal *sal){
	MSList *it;
	char *alltags=NULL;
	size_t buflen=64;
	size_t written=0;
938

939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
	if (sal->supported){
		belle_sip_object_unref(sal->supported);
		sal->supported=NULL;
	}
	for(it=sal->supported_tags;it!=NULL;it=it->next){
		const char *tag=(const char*)it->data;
		size_t taglen=strlen(tag);
		if (alltags==NULL || (written+taglen+1>=buflen)) alltags=ms_realloc(alltags,(buflen=buflen*2));
		snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag);
	}
	if (alltags){
		sal->supported=belle_sip_header_create("Supported",alltags);
		if (sal->supported){
			belle_sip_object_ref(sal->supported);
		}
		ms_free(alltags);
	}
}

void sal_set_supported_tags(Sal *ctx, const char* tags){
	ctx->supported_tags=ms_list_free_with_data(ctx->supported_tags,ms_free);
	if (tags){
		char *iter;
		char *buffer=ms_strdup(tags);
		char *tag;
		char *context=NULL;
		iter=buffer;
		while((tag=strtok_r(iter,", ",&context))!=NULL){
			iter=NULL;
			ctx->supported_tags=ms_list_append(ctx->supported_tags,ms_strdup(tag));
		}
		ms_free(buffer);
	}
	make_supported_header(ctx);
}

const char *sal_get_supported_tags(Sal *ctx){
	if (ctx->supported){
		return belle_sip_header_get_unparsed_value(ctx->supported);
	}
	return NULL;
}

void sal_add_supported_tag(Sal *ctx, const char* tag){
983
	MSList *elem=ms_list_find_custom(ctx->supported_tags,(MSCompareFunc)strcasecmp,tag);
984 985 986 987
	if (!elem){
		ctx->supported_tags=ms_list_append(ctx->supported_tags,ms_strdup(tag));
		make_supported_header(ctx);
	}
988

989 990 991
}

void sal_remove_supported_tag(Sal *ctx, const char* tag){
992
	MSList *elem=ms_list_find_custom(ctx->supported_tags,(MSCompareFunc)strcasecmp,tag);
993 994 995 996 997 998 999 1000 1001
	if (elem){
		ms_free(elem->data);
		ctx->supported_tags=ms_list_remove_link(ctx->supported_tags,elem);
		make_supported_header(ctx);
	}
}



1002 1003 1004
belle_sip_response_t* sal_create_response_from_request ( Sal* sal, belle_sip_request_t* req, int code ) {
	belle_sip_response_t *resp=belle_sip_response_create_from_request(req,code);
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(sal->user_agent));
1005
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),sal->supported);
1006 1007
	return resp;
}
1008

jehan's avatar
jehan committed
1009 1010 1011
void sal_set_refresher_retry_after(Sal *sal,int value) {
	sal->refresher_retry_after=value;
}
1012

jehan's avatar
jehan committed
1013 1014 1015
int sal_get_refresher_retry_after(const Sal *sal) {
	return sal->refresher_retry_after;
}
1016 1017 1018 1019

void sal_enable_auto_contacts(Sal *ctx, bool_t enabled){
	ctx->auto_contacts=enabled;
}
1020 1021 1022 1023 1024

void sal_enable_test_features(Sal*ctx, bool_t enabled){
	ctx->enable_test_features=enabled;
}

1025 1026 1027 1028
void sal_use_no_initial_route(Sal *ctx, bool_t enabled){
	ctx->no_initial_route=enabled;
}

1029 1030
SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data){
	return (SalResolverContext*)belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data);
1031 1032
}

1033 1034 1035
/*
void sal_resolve_cancel(Sal *sal, SalResolverContext* ctx){
	belle_sip_stack_resolve_cancel(sal->stack,ctx);
1036
}
1037
*/
1038

1039 1040 1041
void sal_enable_unconditional_answer(Sal *sal,int value) {
	belle_sip_provider_enable_unconditional_answer(sal->prov,value);
}
1042 1043 1044 1045 1046 1047 1048

/** Parse a file containing either a certificate chain order in PEM format or a single DER cert
 * @param auth_info structure where to store the result of parsing
 * @param path path to certificate chain file
 * @param format either PEM or DER
 */
void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format) {
jehan's avatar
jehan committed
1049
	auth_info->certificates = (SalCertificatesChain*) belle_sip_certificates_chain_parse_file(path, (belle_sip_certificate_raw_format_t)format); //
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
	if (auth_info->certificates) belle_sip_object_ref((belle_sip_object_t *) auth_info->certificates);
}

/**
 * Parse a file containing either a private or public rsa key
 * @param auth_info structure where to store the result of parsing
 * @param passwd password (optionnal)
 */
void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd) {
	auth_info->key = (SalSigningKey *) belle_sip_signing_key_parse_file(path, passwd);
	if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key);
}
1062 1063 1064 1065 1066

unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){
	return belle_sip_random_bytes(ret,size);
}

1067 1068 1069 1070 1071 1072
unsigned int sal_get_random(void){
	unsigned int ret=0;
	belle_sip_random_bytes((unsigned char*)&ret,4);
	return ret;
}

1073 1074 1075 1076
belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) {
	belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack);
	return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name);
}
1077

1078 1079 1080 1081
void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) {
	belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack);
	belle_sip_main_loop_remove_source(ml, timer);
}
1082 1083 1084
void sal_enable_sip_update_method(Sal *ctx,bool_t value) {
	ctx->enable_sip_update=value;
}
1085

1086 1087 1088 1089
void sal_default_enable_sdp_removal(Sal *sal, bool_t enable)  {
	if (enable) ms_message("Enabling SDP removal feature by default for all new SalOp in Sal[%p]!", sal);
	sal->default_sdp_removal = enable;
}