sal_impl.c 54.1 KB
Newer Older
jehan's avatar
jehan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
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
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
jehan's avatar
jehan committed
18
*/
19

jehan's avatar
jehan committed
20
#include "sal_impl.h"
Yann Diorcet's avatar
Yann Diorcet committed
21

Simon Morlat's avatar
Simon Morlat committed
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;

jehan's avatar
jehan committed
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);
		}
	}
}
Simon Morlat's avatar
Simon Morlat committed
63 64
static void set_tls_properties(Sal *ctx);

jehan's avatar
jehan committed
65
void _belle_sip_log(const char *domain, belle_sip_log_level lev, const char *fmt, va_list args) {
Yann Diorcet's avatar
Yann Diorcet committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
	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;
Yann Diorcet's avatar
Yann Diorcet committed
84
	}
Simon Morlat's avatar
Simon Morlat committed
85 86
	if (ortp_log_level_enabled("belle-sip", ortp_level)){
		ortp_logv("belle-sip", ortp_level,fmt,args);
Yann Diorcet's avatar
Yann Diorcet committed
87 88 89
	}
}

90 91
void sal_enable_log(){
	sal_set_log_level(ORTP_MESSAGE);
jehan's avatar
jehan committed
92
}
Simon Morlat's avatar
Simon Morlat committed
93

94 95 96 97 98 99
void sal_disable_log() {
	sal_set_log_level(ORTP_ERROR);
}

void sal_set_log_level(OrtpLogLevel level) {
	belle_sip_log_level belle_sip_level;
100 101 102 103 104 105 106 107 108 109 110 111 112
	if ((level&ORTP_FATAL) != 0) {
		belle_sip_level = BELLE_SIP_LOG_FATAL;
	} else if ((level&ORTP_ERROR) != 0) {
		belle_sip_level = BELLE_SIP_LOG_ERROR;
	} else if ((level&ORTP_WARNING) != 0) {
		belle_sip_level = BELLE_SIP_LOG_WARNING;
	} else if ((level&ORTP_MESSAGE) != 0) {
		belle_sip_level = BELLE_SIP_LOG_MESSAGE;
	} else if (((level&ORTP_DEBUG) != 0) || ((level&ORTP_TRACE) != 0)) {
		belle_sip_level = BELLE_SIP_LOG_DEBUG;
	} else {
		//well, this should never occurs but...
		belle_sip_level = BELLE_SIP_LOG_MESSAGE;
113 114
	}
	belle_sip_set_log_level(belle_sip_level);
jehan's avatar
jehan committed
115
}
Simon Morlat's avatar
Simon Morlat committed
116

117
void sal_add_pending_auth(Sal *sal, SalOp *op){
118 119
	if (bctbx_list_find(sal->pending_auths,op)==NULL){
		sal->pending_auths=bctbx_list_append(sal->pending_auths,op);
120
		op->has_auth_pending=TRUE;
121
	}
jehan's avatar
jehan committed
122 123
}

Simon Morlat's avatar
Simon Morlat committed
124
void sal_remove_pending_auth(Sal *sal, SalOp *op){
125 126
	if (op->has_auth_pending){
		op->has_auth_pending=FALSE;
127 128
		if (bctbx_list_find(sal->pending_auths,op)){
			sal->pending_auths=bctbx_list_remove(sal->pending_auths,op);
129
		}
130
	}
jehan's avatar
jehan committed
131 132
}

133
void sal_process_authentication(SalOp *op) {
134 135
	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
136
	bool_t is_within_dialog=FALSE;
137 138
	belle_sip_list_t* auth_list=NULL;
	belle_sip_auth_event_t* auth_event;
139
	belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction);
140 141
	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);
142

143 144 145 146
	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));
	}
147

jehan's avatar
jehan committed
148
	if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) {
149 150 151
		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
152 153
		is_within_dialog=TRUE;
	} else {
154 155 156
		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
157
	}
158
	if (new_request==NULL) {
Simon Morlat's avatar
Simon Morlat committed
159 160 161
		ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",op);
		return;
	}
162

163
	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
164
		if (is_within_dialog) {
165
			sal_op_send_request(op,new_request);
166
		} else {
167
			sal_op_resend_request(op,new_request);
jehan's avatar
jehan committed
168
		}
169
		sal_remove_pending_auth(op->base.root,op);
jehan's avatar
jehan committed
170
	}else {
171 172 173 174
		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);
175 176
		sal_add_pending_auth(op->base.root,op);

jehan's avatar
jehan committed
177
		if (is_within_dialog) {
178
			belle_sip_object_unref(new_request);
jehan's avatar
jehan committed
179
		}
180 181
	}
	/*always store auth info, for case of wrong credential*/
Simon Morlat's avatar
Simon Morlat committed
182 183 184 185
	if (op->auth_info) {
		sal_auth_info_delete(op->auth_info);
		op->auth_info=NULL;
	}
186 187 188 189
	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);
jehan's avatar
jehan committed
190 191
	}
}
Simon Morlat's avatar
Simon Morlat committed
192

jehan's avatar
jehan committed
193
static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){
Simon Morlat's avatar
Simon Morlat committed
194
	belle_sip_dialog_t* dialog =  belle_sip_dialog_terminated_event_get_dialog(event);
jehan's avatar
jehan committed
195
	SalOp* op = belle_sip_dialog_get_application_data(dialog);
196 197
	if (op && op->callbacks && op->callbacks->process_dialog_terminated) {
		op->callbacks->process_dialog_terminated(op,event);
jehan's avatar
jehan committed
198
	} else {
199
		ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog);
jehan's avatar
jehan committed
200
	}
jehan's avatar
jehan committed
201
}
Simon Morlat's avatar
Simon Morlat committed
202

jehan's avatar
jehan committed
203
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
jehan's avatar
jehan committed
204 205
	belle_sip_client_transaction_t*client_transaction;
	SalOp* op;
206
	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
207 208
		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));
209 210
		/*also reset auth count on IO error*/
		op->auth_requests=0;
211 212
		if (op->callbacks && op->callbacks->process_io_error) {
			op->callbacks->process_io_error(op,event);
jehan's avatar
jehan committed
213 214
		}
	} else {
215 216
		/*ms_error("sal process_io_error not implemented yet for non transaction");*/
		/*nop, because already handle at transaction layer*/
jehan's avatar
jehan committed
217
	}
jehan's avatar
jehan committed
218
}
Simon Morlat's avatar
Simon Morlat committed
219

220 221
static void process_request_event(void *ud, const belle_sip_request_event_t *event) {
	Sal *sal=(Sal*)ud;
jehan's avatar
jehan committed
222
	SalOp* op=NULL;
jehan's avatar
jehan committed
223 224 225
	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;
226
	belle_sip_header_address_t* address=NULL;
jehan's avatar
jehan committed
227
	belle_sip_header_from_t* from_header;
jehan's avatar
jehan committed
228
	belle_sip_header_to_t* to;
jehan's avatar
jehan committed
229
	belle_sip_response_t* resp;
230
	belle_sip_header_t *evh;
231
	const char *method=belle_sip_request_get_method(req);
232
	belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t);
233

jehan's avatar
jehan committed
234 235
	from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);

jehan's avatar
jehan committed
236 237
	if (dialog) {
		op=(SalOp*)belle_sip_dialog_get_application_data(dialog);
238 239 240 241 242
		
		if (op == NULL  && strcmp("NOTIFY",method) == 0) {
			/*special case for Dialog created by notify mathing subscribe*/
			belle_sip_transaction_t * sub_trans = belle_sip_dialog_get_last_transaction(dialog);
			op = (SalOp*)belle_sip_transaction_get_application_data(sub_trans);
243 244
		}
		if (op==NULL || op->state==SalOpStateTerminated){
245 246 247
			ms_warning("Receiving request for null or terminated op [%p], ignored",op);
			return;
		}
248
	}else{
Simon Morlat's avatar
Simon Morlat committed
249
		/*handle the case where we are receiving a request with to tag but it is not belonging to any dialog*/
250 251 252 253 254 255 256 257 258 259 260
		belle_sip_header_to_t *to = belle_sip_message_get_header_by_type(req, belle_sip_header_to_t);
		if ((strcmp("INVITE",method)==0 || strcmp("NOTIFY",method)==0) && (belle_sip_header_to_get_tag(to) != NULL)) {
			ms_warning("Receiving %s with to-tag but no know dialog here. Rejecting.", method);
			resp=belle_sip_response_create_from_request(req,481);
			belle_sip_provider_send_response(sal->prov,resp);
			return;
		/* by default (eg. when a to-tag is present), out of dialog ACK are automatically
		handled in lower layers (belle-sip) but in case it misses, it will be forwarded to us */
		} else if (strcmp("ACK",method)==0 && (belle_sip_header_to_get_tag(to) == NULL)) {
			ms_warning("Receiving ACK without to-tag but no know dialog here. Ignoring");
			return;
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
		}

		if (strcmp("INVITE",method)==0) {
			op=sal_op_new(sal);
			op->dir=SalOpDirIncoming;
			sal_op_call_fill_cbs(op);
		}else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) {
			op=sal_op_new(sal);
			op->dir=SalOpDirIncoming;
			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);
		}else if (strcmp("MESSAGE",method)==0) {
			op=sal_op_new(sal);
			op->dir=SalOpDirIncoming;
			sal_op_message_fill_cbs(op);
		}else if (strcmp("OPTIONS",method)==0) {
			resp=belle_sip_response_create_from_request(req,200);
			belle_sip_provider_send_response(sal->prov,resp);
			return;
		}else if (strcmp("INFO",method)==0) {
			resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/
			belle_sip_provider_send_response(sal->prov,resp);
			return;
		}else if (strcmp("BYE",method)==0) {
			resp=belle_sip_response_create_from_request(req,481);/*out of dialog BYE */
			belle_sip_provider_send_response(sal->prov,resp);
			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);
			return;
		}else if (sal->enable_test_features && strcmp("PUBLISH",method)==0) {
295
			resp=belle_sip_response_create_from_request(req,200);/*out of dialog PUBLISH */
296 297 298 299 300 301 302 303
			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);
			return;
		}else {
			ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req));
			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")));
Simon Morlat's avatar
Simon Morlat committed
304 305 306
			belle_sip_provider_send_response(sal->prov,resp);
			return;
		}
jehan's avatar
jehan committed
307 308 309
	}

	if (!op->base.from_address)  {
310 311 312 313 314 315 316 317
		if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)))
			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)));
		else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header))))
			address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
					,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
		else
			ms_error("Cannot not find from uri from request [%p]",req);
jehan's avatar
jehan committed
318 319 320
		sal_op_set_from_address(op,(SalAddress*)address);
		belle_sip_object_unref(address);
	}
jehan's avatar
jehan committed
321

322 323 324
	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
325

jehan's avatar
jehan committed
326 327
	if (!op->base.to_address) {
		to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t);
328 329 330 331 332 333 334 335 336
		if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)))
			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)));
		else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to))))
			address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to))
					,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to)));
		else
			ms_error("Cannot not find to uri from request [%p]",req);

jehan's avatar
jehan committed
337 338 339 340 341 342 343 344 345 346 347 348 349 350
		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
351 352 353
	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))));
	}
jehan's avatar
jehan committed
354 355 356 357
	/*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
358
	sal_op_assign_recv_headers(op,(belle_sip_message_t*)req);
359 360
	if (op->callbacks && op->callbacks->process_request_event) {
		op->callbacks->process_request_event(op,event);
jehan's avatar
jehan committed
361 362 363 364
	} else {
		ms_error("sal process_request_event not implemented yet");
	}

jehan's avatar
jehan committed
365 366 367 368 369
}

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);
jehan's avatar
jehan committed
370
	int response_code = belle_sip_response_get_status_code(response);
371

372
	if (!client_transaction) {
373
		ms_warning("Discarding stateless response [%i]",response_code);
jehan's avatar
jehan committed
374
		return;
375 376 377
	} 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));
378
		belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t);
379 380 381 382 383

		if (op->state == SalOpStateTerminated) {
			belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code);
			return;
		}
384 385
		/*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));
386 387 388 389 390

		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
391 392 393
		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))));
		}
jehan's avatar
jehan committed
394

395
		sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);
396

397
		if (op->callbacks && op->callbacks->process_response_event) {
398
			/*handle authorization*/
399
			switch (response_code) {
400
				case 200:
401 402
					break;
				case 401:
403
				case 407:
404 405 406 407 408 409 410 411
					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;
						}
412
						if (++op->auth_requests > 2) {
413 414
							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));
415 416 417 418 419 420 421
							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;
						}
422
					}
423 424 425 426
					break;
				case 403:
					if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info);
					break;
jehan's avatar
jehan committed
427
			}
428
			if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) {
429 430 431
				/*not an auth request*/
				op->auth_requests=0;
			}
432
			op->callbacks->process_response_event(op,event);
433 434 435
		} else {
			ms_error("Unhandled event response [%p]",event);
		}
jehan's avatar
jehan committed
436 437
	}
}
Simon Morlat's avatar
Simon Morlat committed
438

jehan's avatar
jehan committed
439
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
440
	belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event);
jehan's avatar
jehan committed
441
	SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
442 443
	if (op && op->callbacks && op->callbacks->process_timeout) {
		op->callbacks->process_timeout(op,event);
444
	} else {
jehan's avatar
jehan committed
445 446 447
		ms_error("Unhandled event timeout [%p]",event);
	}
}
Simon Morlat's avatar
Simon Morlat committed
448

jehan's avatar
jehan committed
449
static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
450 451
	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);
452
	belle_sip_transaction_t* trans;
Sylvain Berfini's avatar
Sylvain Berfini committed
453 454
	SalOp* op;

455 456 457
	if(client_transaction)
		trans=BELLE_SIP_TRANSACTION(client_transaction);
	 else
Simon Morlat's avatar
Simon Morlat committed
458
		trans=BELLE_SIP_TRANSACTION(server_transaction);
459

Sylvain Berfini's avatar
Sylvain Berfini committed
460
	op = (SalOp*)belle_sip_transaction_get_application_data(trans);
461 462
	if (op && op->callbacks && op->callbacks->process_transaction_terminated) {
		op->callbacks->process_transaction_terminated(op,event);
463
	} else {
464
		ms_message("Unhandled transaction terminated [%p]",trans);
jehan's avatar
jehan committed
465
	}
Simon Morlat's avatar
Simon Morlat committed
466
	if (op) sal_op_unref(op); /*because every transaction ref op*/
jehan's avatar
jehan committed
467
}
Simon Morlat's avatar
Simon Morlat committed
468

469 470 471

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
472
	((Sal*)sal)->callbacks.auth_requested(sal,auth_info);
473 474 475 476 477
	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
478
	sal_auth_info_delete(auth_info);
jehan's avatar
jehan committed
479
}
Simon Morlat's avatar
Simon Morlat committed
480

481
Sal * sal_init(MSFactory *factory){
Simon Morlat's avatar
Simon Morlat committed
482
	belle_sip_listener_callbacks_t listener_callbacks;
jehan's avatar
jehan committed
483
	Sal * sal=ms_new0(Sal,1);
484

485
	/*belle_sip_object_enable_marshal_check(TRUE);*/
486
	sal->auto_contacts=TRUE;
487
	sal->factory = factory;
488 489 490
	/*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);
491

jehan's avatar
jehan committed
492
	sal->user_agent=belle_sip_header_user_agent_new();
jehan's avatar
jehan committed
493 494
#if defined(PACKAGE_NAME) && defined(LIBLINPHONE_VERSION)
	belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LIBLINPHONE_VERSION);
495 496
#else
	belle_sip_header_user_agent_add_product(sal->user_agent, "Unknown");
jehan's avatar
jehan committed
497
#endif
498
	sal_append_stack_string_to_user_agent(sal);
jehan's avatar
jehan committed
499
	belle_sip_object_ref(sal->user_agent);
500

jehan's avatar
jehan committed
501
	sal->prov = belle_sip_stack_create_provider(sal->stack,NULL);
502
	sal_nat_helper_enable(sal,TRUE);
Simon Morlat's avatar
Simon Morlat committed
503 504 505 506 507 508 509 510 511 512
	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);
Simon Morlat's avatar
Simon Morlat committed
513 514
	sal->tls_verify=TRUE;
	sal->tls_verify_cn=TRUE;
jehan's avatar
jehan committed
515
	sal->refresher_retry_after=60000; /*default value in ms*/
516
	sal->enable_sip_update=TRUE;
517
	sal->pending_trans_checking=TRUE;
518
	sal->ssl_config = NULL;
jehan's avatar
jehan committed
519 520
	return sal;
}
521

jehan's avatar
jehan committed
522 523 524 525 526 527 528 529
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;
}

530
static void unimplemented_stub(void){
jehan's avatar
jehan committed
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
	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
550 551
	if (ctx->callbacks.auth_failure==NULL)
		ctx->callbacks.auth_failure=(SalOnAuthFailure)unimplemented_stub;
jehan's avatar
jehan committed
552 553 554 555 556 557 558 559 560 561
	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;
562 563
	if (ctx->callbacks.incoming_subscribe_closed==NULL)
		ctx->callbacks.incoming_subscribe_closed=(SalOnIncomingSubscribeClosed)unimplemented_stub;
564 565
	if (ctx->callbacks.parse_presence_requested==NULL)
		ctx->callbacks.parse_presence_requested=(SalOnParsePresenceRequested)unimplemented_stub;
566 567
	if (ctx->callbacks.convert_presence_to_xml_requested==NULL)
		ctx->callbacks.convert_presence_to_xml_requested=(SalOnConvertPresenceToXMLRequested)unimplemented_stub;
568 569 570 571
	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;
jehan's avatar
jehan committed
572 573
	if (ctx->callbacks.text_received==NULL)
		ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
574 575
	if (ctx->callbacks.is_composing_received==NULL)
		ctx->callbacks.is_composing_received=(SalOnIsComposingReceived)unimplemented_stub;
jehan's avatar
jehan committed
576 577 578 579
	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
580 581
	if (ctx->callbacks.info_received==NULL)
		ctx->callbacks.info_received=(SalOnInfoReceived)unimplemented_stub;
582 583 584 585
	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;
jehan's avatar
jehan committed
586 587 588 589 590
}



void sal_uninit(Sal* sal){
jehan's avatar
jehan committed
591
	belle_sip_object_unref(sal->user_agent);
jehan's avatar
jehan committed
592 593
	belle_sip_object_unref(sal->prov);
	belle_sip_object_unref(sal->stack);
Simon Morlat's avatar
Simon Morlat committed
594
	belle_sip_object_unref(sal->listener);
595
	if (sal->supported) belle_sip_object_unref(sal->supported);
596
	bctbx_list_free_with_data(sal->supported_tags,ms_free);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
597
	if (sal->uuid) ms_free(sal->uuid);
Simon Morlat's avatar
Simon Morlat committed
598
	if (sal->root_ca) ms_free(sal->root_ca);
jehan's avatar
jehan committed
599 600 601
	ms_free(sal);
};

Simon Morlat's avatar
Simon Morlat committed
602 603 604 605 606 607 608 609 610 611 612 613 614
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;
}

615 616 617 618
bool_t sal_content_encoding_available(Sal *sal, const char *content_encoding) {
	return (bool_t)belle_sip_stack_content_encoding_available(sal->stack, content_encoding);
}

619
static int sal_add_listen_port(Sal *ctx, SalAddress* addr, bool_t is_tunneled){
jehan's avatar
jehan committed
620
	int result;
621 622
	belle_sip_listening_point_t* lp;
	if (is_tunneled){
Simon Morlat's avatar
Simon Morlat committed
623
#ifdef TUNNEL_ENABLED
624 625 626 627 628 629 630 631 632
		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;
		}
Simon Morlat's avatar
Simon Morlat committed
633 634 635 636
#else
		ms_error("No tunnel support in library.");
		return -1;
#endif
637 638
	}else{
		lp = belle_sip_stack_create_listening_point(ctx->stack,
639 640 641 642
									sal_address_get_domain(addr),
									sal_address_get_port(addr),
									sal_transport_to_string(sal_address_get_transport(addr)));
	}
jehan's avatar
jehan committed
643
	if (lp) {
jehan's avatar
jehan committed
644
		belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive);
jehan's avatar
jehan committed
645
		result = belle_sip_provider_add_listening_point(ctx->prov,lp);
jehan's avatar
jehan committed
646 647 648
		if (sal_address_get_transport(addr)==SalTransportTLS) {
			set_tls_properties(ctx);
		}
jehan's avatar
jehan committed
649 650 651 652 653
	} else {
		return -1;
	}
	return result;
}
Simon Morlat's avatar
Simon Morlat committed
654

655
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_tunneled) {
jehan's avatar
jehan committed
656 657 658
	SalAddress* sal_addr = sal_address_new(NULL);
	int result;
	sal_address_set_domain(sal_addr,addr);
659
	sal_address_set_port(sal_addr,port);
jehan's avatar
jehan committed
660
	sal_address_set_transport(sal_addr,tr);
661
	result = sal_add_listen_port(ctx, sal_addr, is_tunneled);
jehan's avatar
jehan committed
662 663 664
	sal_address_destroy(sal_addr);
	return result;
}
665

jehan's avatar
jehan committed
666 667 668
static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) {
	belle_sip_provider_remove_listening_point(prov,lp);
}
669 670 671 672 673 674 675 676 677 678

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

jehan's avatar
jehan committed
679 680 681 682 683 684 685 686
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;
}
687

jehan's avatar
jehan committed
688
ortp_socket_t sal_get_socket(Sal *ctx){
jehan's avatar
jehan committed
689
	ms_warning("sal_get_socket is deprecated");
jehan's avatar
jehan committed
690 691
	return -1;
}
692

jehan's avatar
jehan committed
693
void sal_set_user_agent(Sal *ctx, const char *user_agent){
jehan's avatar
jehan committed
694 695
	belle_sip_header_user_agent_set_products(ctx->user_agent,NULL);
	belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent);
jehan's avatar
jehan committed
696 697
	return ;
}
698

699 700 701 702 703 704
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;
}

705 706 707 708 709 710
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);
}

jehan's avatar
jehan committed
711 712
/*keepalive period in ms*/
void sal_set_keepalive_period(Sal *ctx,unsigned int value){
jehan's avatar
jehan committed
713
	const belle_sip_list_t* iterator;
jehan's avatar
jehan committed
714
	belle_sip_listening_point_t* lp;
jehan's avatar
jehan committed
715 716
	ctx->keep_alive=value;
	for (iterator=belle_sip_provider_get_listening_points(ctx->prov);iterator!=NULL;iterator=iterator->next) {
jehan's avatar
jehan committed
717 718 719 720
		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);
		}
jehan's avatar
jehan committed
721
	}
jehan's avatar
jehan committed
722
}
723
int sal_set_tunnel(Sal *ctx, void *tunnelclient) {
724
#ifdef TUNNEL_ENABLED
725
	ctx->tunnel_client=tunnelclient;
726
	return 0;
727
#else
728
	return -1;
729
#endif
Ghislain MARY's avatar
Ghislain MARY committed
730
}
731

jehan's avatar
jehan committed
732 733 734 735 736
/**
 * returns keepalive period in ms
 * 0 desactiaved
 * */
unsigned int sal_get_keepalive_period(Sal *ctx){
jehan's avatar
jehan committed
737
	return ctx->keep_alive;
jehan's avatar
jehan committed
738 739
}
void sal_use_session_timers(Sal *ctx, int expires){
jehan's avatar
jehan committed
740
	ctx->session_expires=expires;
jehan's avatar
jehan committed
741 742
	return ;
}
743

jehan's avatar
jehan committed
744
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){
jehan's avatar
jehan committed
745
	ctx->one_matching_codec=one_matching_codec;
jehan's avatar
jehan committed
746
}
747

jehan's avatar
jehan committed
748
void sal_use_rport(Sal *ctx, bool_t use_rports){
jehan's avatar
jehan committed
749 750
	belle_sip_provider_enable_rport(ctx->prov,use_rports);
	ms_message("Sal use rport [%s]",use_rports?"enabled":"disabled");
jehan's avatar
jehan committed
751 752
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
753 754 755 756 757

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);
758 759 760 761 762 763
		belle_tls_crypto_config_t *crypto_config = belle_tls_crypto_config_new();
		int verify_exceptions = BELLE_TLS_VERIFY_NONE;
		if (!ctx->tls_verify) verify_exceptions = BELLE_TLS_VERIFY_ANY_REASON;
		else if (!ctx->tls_verify_cn) verify_exceptions = BELLE_TLS_VERIFY_CN_MISMATCH;
		belle_tls_crypto_config_set_verify_exceptions(crypto_config, verify_exceptions);
		if (ctx->root_ca != NULL) belle_tls_crypto_config_set_root_ca(crypto_config, ctx->root_ca);
764
		if (ctx->ssl_config != NULL) belle_tls_crypto_config_set_ssl_config(crypto_config, ctx->ssl_config);
765
		belle_sip_tls_listening_point_set_crypto_config(tlp, crypto_config);
jehan's avatar
jehan committed
766
		belle_sip_object_unref(crypto_config);
Simon Morlat's avatar
Simon Morlat committed
767 768 769
	}
}

jehan's avatar
jehan committed
770
void sal_set_root_ca(Sal* ctx, const char* rootCa){
Simon Morlat's avatar
Simon Morlat committed
771 772 773 774 775 776 777
	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);
jehan's avatar
jehan committed
778 779
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
780

jehan's avatar
jehan committed
781
void sal_verify_server_certificates(Sal *ctx, bool_t verify){
Simon Morlat's avatar
Simon Morlat committed
782 783
	ctx->tls_verify=verify;
	set_tls_properties(ctx);
jehan's avatar
jehan committed
784 785
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
786

787
void sal_verify_server_cn(Sal *ctx, bool_t verify){
Simon Morlat's avatar
Simon Morlat committed
788 789
	ctx->tls_verify_cn=verify;
	set_tls_properties(ctx);
790 791 792
	return ;
}

793 794 795 796 797 798
void sal_set_ssl_config(Sal *ctx, void *ssl_config) {
	ctx->ssl_config = ssl_config;
	set_tls_properties(ctx);
	return ;
}

799
void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {
jehan's avatar
jehan committed
800
	ctx->use_tcp_tls_keep_alive=enabled;
801
}
jehan's avatar
jehan committed
802 803 804 805 806

int sal_iterate(Sal *sal){
	belle_sip_stack_sleep(sal->stack,0);
	return 0;
}
807 808
bctbx_list_t * sal_get_pending_auths(Sal *sal){
	return bctbx_list_copy(sal->pending_auths);
jehan's avatar
jehan committed
809 810 811 812
}

/*misc*/
void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen){
jehan's avatar
jehan committed
813
	strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen);
Simon Morlat's avatar
Simon Morlat committed
814
	ms_error("sal_get_default_local_ip() is deprecated.");
jehan's avatar
jehan committed
815
}
816 817

const char *sal_get_root_ca(Sal* ctx) {
Simon Morlat's avatar
Simon Morlat committed
818
	return ctx->root_ca;
819
}
Simon Morlat's avatar
Simon Morlat committed
820

821
int sal_reset_transports(Sal *ctx){
jehan's avatar
jehan committed
822
	ms_message("Reseting transports");
jehan's avatar
jehan committed
823 824
	belle_sip_provider_clean_channels(ctx->prov);
	return 0;
825
}
Simon Morlat's avatar
Simon Morlat committed
826

827
void sal_set_dscp(Sal *ctx, int dscp){
Simon Morlat's avatar
Simon Morlat committed
828
	belle_sip_stack_set_default_dscp(ctx->stack,dscp);
829
}
Simon Morlat's avatar
Simon Morlat committed
830

831 832 833
void  sal_set_send_error(Sal *sal,int value) {
	 belle_sip_stack_set_send_error(sal->stack,value);
}
jehan's avatar
jehan committed
834 835 836
void  sal_set_recv_error(Sal *sal,int value) {
	 belle_sip_provider_set_recv_error(sal->prov,value);
}
jehan's avatar
jehan committed
837 838
void sal_nat_helper_enable(Sal *sal,bool_t enable) {
	sal->nat_helper_enabled=enable;
839
	belle_sip_provider_enable_nat_helper(sal->prov,enable);
jehan's avatar
jehan committed
840 841 842 843 844
	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
845 846 847
void sal_set_dns_timeout(Sal* sal,int timeout) {
	belle_sip_stack_set_dns_timeout(sal->stack, timeout);
}
848

jehan's avatar
jehan committed
849 850 851
int sal_get_dns_timeout(const Sal* sal)  {
	return belle_sip_stack_get_dns_timeout(sal->stack);
}
852 853 854 855

void sal_set_transport_timeout(Sal* sal,int timeout) {
	belle_sip_stack_set_transport_timeout(sal->stack, timeout);
}
856

857 858 859
int sal_get_transport_timeout(const Sal* sal)  {
	return belle_sip_stack_get_transport_timeout(sal->stack);
}
860

861
void sal_set_dns_servers(Sal *sal, const bctbx_list_t *servers){
862
	belle_sip_list_t *l = NULL;
863