sal_impl.c 24.3 KB
Newer Older
jehan's avatar
jehan committed
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

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 25 26 27
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

static void set_tls_properties(Sal *ctx);

Yann Diorcet's avatar
Yann Diorcet committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
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
44
		default:
jehan's avatar
jehan committed
45
			ortp_level=ORTP_DEBUG;
jehan's avatar
jehan committed
46
			break;
Yann Diorcet's avatar
Yann Diorcet committed
47 48 49 50 51 52
	}
	if (ortp_log_level_enabled(ortp_level)){
		ortp_logv(ortp_level,fmt,args);
	}
}

jehan's avatar
jehan committed
53 54 55 56 57 58
void sal_enable_logs(){
	belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE);
}
void sal_disable_logs() {
	belle_sip_set_log_level(BELLE_SIP_LOG_ERROR);
}
59
void sal_add_pending_auth(Sal *sal, SalOp *op){
60 61 62
	if (ms_list_find(sal->pending_auths,op)==NULL){
		sal->pending_auths=ms_list_append(sal->pending_auths,sal_op_ref(op));
	}
jehan's avatar
jehan committed
63 64 65
}

 void sal_remove_pending_auth(Sal *sal, SalOp *op){
66 67 68 69
	if (ms_list_find(sal->pending_auths,op)){
		sal->pending_auths=ms_list_remove(sal->pending_auths,op);
		sal_op_unref(op);
	}
jehan's avatar
jehan committed
70 71
}

72
void sal_process_authentication(SalOp *op) {
Ghislain MARY's avatar
Ghislain MARY committed
73
	belle_sip_request_t* request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction);
jehan's avatar
jehan committed
74
	bool_t is_within_dialog=FALSE;
75 76
	belle_sip_list_t* auth_list=NULL;
	belle_sip_auth_event_t* auth_event;
77 78 79 80
	belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction);
	
	sal_add_pending_auth(op->base.root,op);
	
jehan's avatar
jehan committed
81
	if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) {
82
		request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)request);
jehan's avatar
jehan committed
83 84 85 86 87
		is_within_dialog=TRUE;
	} else {
		belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION);
		belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION);
	}
88
	if (belle_sip_provider_add_authorization(op->base.root->prov,request,response,&auth_list)) {
jehan's avatar
jehan committed
89 90
		if (is_within_dialog) {
			sal_op_send_request(op,request);
91 92
		} else {
			sal_op_resend_request(op,request);
jehan's avatar
jehan committed
93
		}
94
		sal_remove_pending_auth(op->base.root,op);
jehan's avatar
jehan committed
95 96
	}else {
		ms_message("No auth info found for [%s]",sal_op_get_from(op));
jehan's avatar
jehan committed
97 98 99
		if (is_within_dialog) {
			belle_sip_object_unref(request);
		}
100 101
		if (op->auth_info) sal_auth_info_delete(op->auth_info);
		auth_event=(belle_sip_auth_event_t*)(auth_list->data);
102
		op->auth_info=sal_auth_info_create(auth_event);
103
		belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy);
jehan's avatar
jehan committed
104 105 106
	}

}
jehan's avatar
jehan committed
107 108 109
static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){
	belle_sip_dialog_t* dialog =  belle_sip_dialog_terminated_get_dialog(event);
	SalOp* op = belle_sip_dialog_get_application_data(dialog);
110
	if (op && op->callbacks.process_dialog_terminated) {
jehan's avatar
jehan committed
111 112
		op->callbacks.process_dialog_terminated(op,event);
	} else {
113
		ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog);
jehan's avatar
jehan committed
114
	}
jehan's avatar
jehan committed
115 116
}
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
jehan's avatar
jehan committed
117 118 119 120 121 122 123 124 125
	belle_sip_client_transaction_t*client_transaction;
	SalOp* op;
	if (belle_sip_object_is_instance_of(BELLE_SIP_OBJECT(belle_sip_io_error_event_get_source(event)),BELLE_SIP_TYPE_ID(belle_sip_client_transaction_t))) {
		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));
		if (op->callbacks.process_io_error) {
				op->callbacks.process_io_error(op,event);
		}
	} else {
126
		ms_error("sal process_io_error not implemented yet for non transaction");
jehan's avatar
jehan committed
127
	}
jehan's avatar
jehan committed
128
}
jehan's avatar
jehan committed
129
static void process_request_event(void *sal, const belle_sip_request_event_t *event) {
jehan's avatar
jehan committed
130
	SalOp* op=NULL;
jehan's avatar
jehan committed
131 132 133 134
	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
135
	belle_sip_header_from_t* from_header;
jehan's avatar
jehan committed
136
	belle_sip_header_to_t* to;
jehan's avatar
jehan committed
137
	belle_sip_response_t* resp;
138

jehan's avatar
jehan committed
139 140
	from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);

jehan's avatar
jehan committed
141 142 143 144
	if (dialog) {
		op=(SalOp*)belle_sip_dialog_get_application_data(dialog);
	} else if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
		op=sal_op_new((Sal*)sal);
jehan's avatar
jehan committed
145
		op->dir=SalOpDirIncoming;
jehan's avatar
jehan committed
146
		sal_op_call_fill_cbs(op);
jehan's avatar
jehan committed
147 148 149 150
	} else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) {
		op=sal_op_new((Sal*)sal);
		op->dir=SalOpDirIncoming;
		sal_op_presence_fill_cbs(op);
jehan's avatar
jehan committed
151
	} else if (strcmp("MESSAGE",belle_sip_request_get_method(req))==0) {
152 153 154 155
		op=sal_op_new((Sal*)sal);
		op->dir=SalOpDirIncoming;
		sal_op_message_fill_cbs(op);

jehan's avatar
jehan committed
156
	} else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) {
157 158 159 160
		resp=belle_sip_response_create_from_request(req,200);
		belle_sip_provider_send_response(((Sal*)sal)->prov,resp);
		return;
	}else {
jehan's avatar
jehan committed
161
		ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req));
162
		resp=belle_sip_response_create_from_request(req,501);
jehan's avatar
jehan committed
163
		belle_sip_provider_send_response(((Sal*)sal)->prov,resp);
jehan's avatar
jehan committed
164
		return;
jehan's avatar
jehan committed
165 166 167
	}

	if (!op->base.from_address)  {
jehan's avatar
jehan committed
168 169
		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
170 171 172
		sal_op_set_from_address(op,(SalAddress*)address);
		belle_sip_object_unref(address);
	}
jehan's avatar
jehan committed
173 174


jehan's avatar
jehan committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	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
193 194 195
	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
196 197 198 199 200 201
	if (op->callbacks.process_request_event) {
		op->callbacks.process_request_event(op,event);
	} else {
		ms_error("sal process_request_event not implemented yet");
	}

jehan's avatar
jehan committed
202 203 204 205 206
}

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
207
	int response_code = belle_sip_response_get_status_code(response);
208
	if (!client_transaction) {
209
		ms_warning("Discarding stateless response [%i]",response_code);
jehan's avatar
jehan committed
210
		return;
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
	} 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));
		belle_sip_header_contact_t* original_contact;
		belle_sip_header_address_t* contact_address=NULL;
		belle_sip_header_via_t* via_header;
		belle_sip_uri_t* contact_uri;
		unsigned int contact_port;
		const char* received;
		int rport;
		bool_t contact_updated=FALSE;
		char* new_contact;

		if (op->state == SalOpStateTerminated) {
			belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code);
			return;
		}
		if (!op->base.remote_ua) {
			sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response));
jehan's avatar
jehan committed
230
		}
jehan's avatar
jehan committed
231 232 233
		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))));
		}
234 235
		if (op->callbacks.process_response_event) {

jehan's avatar
jehan committed
236 237 238 239 240
			if (op->base.root->nat_helper_enabled) {
				/*Fix contact if needed*/
				via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA);
				received = belle_sip_header_via_get_received(via_header);
				rport = belle_sip_header_via_get_rport(via_header);
241 242 243 244 245
				if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) {
					/*update contact with sent values in any cases*/
					contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact)));
					sal_op_set_contact_address(op,(const SalAddress *)contact_address);
					belle_sip_object_unref(contact_address);
jehan's avatar
jehan committed
246
				}
jehan's avatar
jehan committed
247 248
				if (sal_op_get_contact(op)){
					if (received!=NULL || rport>0) {
249

jehan's avatar
jehan committed
250
						contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op)));
jehan's avatar
jehan committed
251 252 253 254
						contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address));
						if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) {
							/*need to update host*/
							belle_sip_uri_set_host(contact_uri,received);
jehan's avatar
jehan committed
255 256
							contact_updated=TRUE;
						}
jehan's avatar
jehan committed
257 258 259 260
						contact_port =  belle_sip_uri_get_port(contact_uri);
						if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) {
							/*need to update port*/
							belle_sip_uri_set_port(contact_uri,rport);
jehan's avatar
jehan committed
261 262
							contact_updated=TRUE;
						}
jehan's avatar
jehan committed
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

						/*try to fix transport if needed (very unlikely)*/
						if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) {
							if (!belle_sip_uri_get_transport_param(contact_uri)
									||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) {
								belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header));
								contact_updated=TRUE;
							}
						} else {
							if (belle_sip_uri_get_transport_param(contact_uri)) {
								contact_updated=TRUE;
								belle_sip_uri_set_transport_param(contact_uri,NULL);
							}
						}
						if (contact_updated) {
							char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op)));
							new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address));
							ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op);
							sal_op_set_contact_address(op,(const SalAddress *)contact_address);
							belle_sip_free(new_contact);
							belle_sip_free(old_contact);
						}
						if (contact_address)belle_sip_object_unref(contact_address);
jehan's avatar
jehan committed
286
					}
287
				}
jehan's avatar
jehan committed
288
			}
289 290
			
			/*handle authorization*/
291 292 293 294 295 296
			switch (response_code) {
			case 200: {
				break;
			}
			case 401:
			case 407:{
297
				
298
				/*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/
299 300 301
				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 ");
302
				} else {
303 304 305 306 307 308
					if (op->pending_auth_transaction){
						belle_sip_object_unref(op->pending_auth_transaction);
						op->pending_auth_transaction=NULL;
					}
					op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
					sal_process_authentication(op);
309 310
					return;
				}
jehan's avatar
jehan committed
311
			}
jehan's avatar
jehan committed
312
			}
jehan's avatar
jehan committed
313

314 315 316 317 318
			op->callbacks.process_response_event(op,event);

		} else {
			ms_error("Unhandled event response [%p]",event);
		}
jehan's avatar
jehan committed
319 320 321 322
	}

}
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
323
	belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event);
jehan's avatar
jehan committed
324
	SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
325
	if (op && op->callbacks.process_timeout) {
jehan's avatar
jehan committed
326
		op->callbacks.process_timeout(op,event);
327
	} else {
jehan's avatar
jehan committed
328 329 330 331
		ms_error("Unhandled event timeout [%p]",event);
	}
}
static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
332 333
	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);
334
	belle_sip_transaction_t* trans;
Sylvain Berfini's avatar
Sylvain Berfini committed
335 336
	SalOp* op;

337 338 339 340 341
	if(client_transaction)
		trans=BELLE_SIP_TRANSACTION(client_transaction);
	 else
		 trans=BELLE_SIP_TRANSACTION(server_transaction);

Sylvain Berfini's avatar
Sylvain Berfini committed
342
	op = (SalOp*)belle_sip_transaction_get_application_data(trans);
343 344 345 346
	if (op && op->callbacks.process_transaction_terminated) {
		op->callbacks.process_transaction_terminated(op,event);
	} else {
		ms_error("Unhandled transaction terminated [%p]",trans);
jehan's avatar
jehan committed
347
	}
348
	if (op) sal_op_unref(op); /*no longuer need to ref op*/
349

jehan's avatar
jehan committed
350
}
Simon Morlat's avatar
Simon Morlat committed
351

jehan's avatar
jehan committed
352 353 354 355 356 357 358 359 360 361 362
static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) {
	SalAuthInfo auth_info;
	memset(&auth_info,0,sizeof(SalAuthInfo));
	auth_info.username=(char*)belle_sip_auth_event_get_username(auth_event);
	auth_info.realm=(char*)belle_sip_auth_event_get_realm(auth_event);
	((Sal*)sal)->callbacks.auth_requested(sal,&auth_info);
	belle_sip_auth_event_set_passwd(auth_event,(const char*)auth_info.password);
	belle_sip_auth_event_set_ha1(auth_event,(const char*)auth_info.ha1);
	belle_sip_auth_event_set_userid(auth_event,(const char*)auth_info.userid);
	return;
}
Simon Morlat's avatar
Simon Morlat committed
363

jehan's avatar
jehan committed
364
Sal * sal_init(){
jehan's avatar
jehan committed
365
	char stack_string[64];
Simon Morlat's avatar
Simon Morlat committed
366
	belle_sip_listener_callbacks_t listener_callbacks;
jehan's avatar
jehan committed
367
	Sal * sal=ms_new0(Sal,1);
jehan's avatar
jehan committed
368
	sal->nat_helper_enabled=TRUE;
jehan's avatar
jehan committed
369 370
	snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string());
	sal->user_agent=belle_sip_header_user_agent_new();
jehan's avatar
jehan committed
371
#if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION)
jehan's avatar
jehan committed
372
	belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION);
jehan's avatar
jehan committed
373 374
#endif

jehan's avatar
jehan committed
375 376
	belle_sip_header_user_agent_add_product(sal->user_agent,stack_string);
	belle_sip_object_ref(sal->user_agent);
Yann Diorcet's avatar
Yann Diorcet committed
377
	belle_sip_set_log_handler(_belle_sip_log);
jehan's avatar
jehan committed
378 379
	sal->stack = belle_sip_stack_new(NULL);
	sal->prov = belle_sip_stack_create_provider(sal->stack,NULL);
Simon Morlat's avatar
Simon Morlat committed
380 381 382 383 384 385 386 387 388 389
	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
390 391
	sal->tls_verify=TRUE;
	sal->tls_verify_cn=TRUE;
jehan's avatar
jehan committed
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
	return sal;
}
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;
	if (ctx->callbacks.auth_requested_legacy==NULL)
		ctx->callbacks.auth_requested_legacy=(SalOnAuthRequestedLegacy)unimplemented_stub;
	if (ctx->callbacks.auth_success==NULL)
		ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub;
	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.notify_presence==NULL)
		ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;
	if (ctx->callbacks.subscribe_received==NULL)
		ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;
	if (ctx->callbacks.text_received==NULL)
		ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
	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;
}



void sal_uninit(Sal* sal){
jehan's avatar
jehan committed
449
	belle_sip_object_unref(sal->user_agent);
jehan's avatar
jehan committed
450 451
	belle_sip_object_unref(sal->prov);
	belle_sip_object_unref(sal->stack);
Simon Morlat's avatar
Simon Morlat committed
452
	belle_sip_object_unref(sal->listener);
Simon Morlat's avatar
Simon Morlat committed
453
	if (sal->root_ca) ms_free(sal->root_ca);
jehan's avatar
jehan committed
454 455 456 457
	ms_free(sal);
	return ;
};

jehan's avatar
jehan committed
458
int sal_add_listen_port(Sal *ctx, SalAddress* addr){
jehan's avatar
jehan committed
459
	int result;
jehan's avatar
jehan committed
460 461 462 463
	belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack
																			,sal_address_get_domain(addr)
																			,sal_address_get_port_int(addr)
																			,sal_transport_to_string(sal_address_get_transport(addr)));
jehan's avatar
jehan committed
464
	if (lp) {
jehan's avatar
jehan committed
465
		belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive);
jehan's avatar
jehan committed
466
		result = belle_sip_provider_add_listening_point(ctx->prov,lp);
Simon Morlat's avatar
Simon Morlat committed
467
		set_tls_properties(ctx);
jehan's avatar
jehan committed
468 469 470 471 472
	} else {
		return -1;
	}
	return result;
}
Simon Morlat's avatar
Simon Morlat committed
473

jehan's avatar
jehan committed
474 475 476 477 478 479 480 481 482 483
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure) {
	SalAddress* sal_addr = sal_address_new(NULL);
	int result;
	sal_address_set_domain(sal_addr,addr);
	sal_address_set_port_int(sal_addr,port);
	sal_address_set_transport(sal_addr,tr);
	result = sal_add_listen_port(ctx,sal_addr);
	sal_address_destroy(sal_addr);
	return result;
}
jehan's avatar
jehan committed
484 485 486 487 488 489 490 491 492 493 494 495 496
static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) {
	belle_sip_provider_remove_listening_point(prov,lp);
}
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;
}
ortp_socket_t sal_get_socket(Sal *ctx){
jehan's avatar
jehan committed
497
	ms_warning("sal_get_socket is deprecated");
jehan's avatar
jehan committed
498 499 500
	return -1;
}
void sal_set_user_agent(Sal *ctx, const char *user_agent){
jehan's avatar
jehan committed
501 502
	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
503 504 505 506
	return ;
}
/*keepalive period in ms*/
void sal_set_keepalive_period(Sal *ctx,unsigned int value){
jehan's avatar
jehan committed
507
	const belle_sip_list_t* iterator;
jehan's avatar
jehan committed
508
	belle_sip_listening_point_t* lp;
jehan's avatar
jehan committed
509 510
	ctx->keep_alive=value;
	for (iterator=belle_sip_provider_get_listening_points(ctx->prov);iterator!=NULL;iterator=iterator->next) {
jehan's avatar
jehan committed
511 512 513 514
		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
515
	}
jehan's avatar
jehan committed
516 517 518 519 520 521 522
	return ;
}
/**
 * returns keepalive period in ms
 * 0 desactiaved
 * */
unsigned int sal_get_keepalive_period(Sal *ctx){
jehan's avatar
jehan committed
523
	return ctx->keep_alive;
jehan's avatar
jehan committed
524 525
}
void sal_use_session_timers(Sal *ctx, int expires){
jehan's avatar
jehan committed
526
	ctx->session_expires=expires;
jehan's avatar
jehan committed
527 528 529
	return ;
}
void sal_use_double_registrations(Sal *ctx, bool_t enabled){
jehan's avatar
jehan committed
530
	ms_warning("sal_use_double_registrations is deprecated");
jehan's avatar
jehan committed
531 532 533
	return ;
}
void sal_reuse_authorization(Sal *ctx, bool_t enabled){
jehan's avatar
jehan committed
534
	ms_warning("sal_reuse_authorization is deprecated");
jehan's avatar
jehan committed
535 536 537
	return ;
}
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){
jehan's avatar
jehan committed
538
	ctx->one_matching_codec=one_matching_codec;
jehan's avatar
jehan committed
539 540
}
void sal_use_rport(Sal *ctx, bool_t use_rports){
jehan's avatar
jehan committed
541 542
	belle_sip_provider_enable_rport(ctx->prov,use_rports);
	ms_message("Sal use rport [%s]",use_rports?"enabled":"disabled");
jehan's avatar
jehan committed
543 544 545
	return ;
}
void sal_use_101(Sal *ctx, bool_t use_101){
jehan's avatar
jehan committed
546
	ms_warning("sal_use_101 is deprecated");
jehan's avatar
jehan committed
547 548
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563

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;
		
		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;
		
		belle_sip_tls_listening_point_set_root_ca(tlp,ctx->root_ca);
		belle_sip_tls_listening_point_set_verify_exceptions(tlp,verify_exceptions);
	}
}

jehan's avatar
jehan committed
564
void sal_set_root_ca(Sal* ctx, const char* rootCa){
Simon Morlat's avatar
Simon Morlat committed
565 566 567 568 569 570 571
	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
572 573
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
574

jehan's avatar
jehan committed
575
void sal_verify_server_certificates(Sal *ctx, bool_t verify){
Simon Morlat's avatar
Simon Morlat committed
576 577
	ctx->tls_verify=verify;
	set_tls_properties(ctx);
jehan's avatar
jehan committed
578 579
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
580

581
void sal_verify_server_cn(Sal *ctx, bool_t verify){
Simon Morlat's avatar
Simon Morlat committed
582 583
	ctx->tls_verify_cn=verify;
	set_tls_properties(ctx);
584 585 586 587
	return ;
}

void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {
jehan's avatar
jehan committed
588
	ctx->use_tcp_tls_keep_alive=enabled;
589
}
jehan's avatar
jehan committed
590 591 592 593 594 595 596 597 598 599 600 601 602 603

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
604
	strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen);
Simon Morlat's avatar
Simon Morlat committed
605
	ms_error("sal_get_default_local_ip() is deprecated.");
jehan's avatar
jehan committed
606
}
607 608

const char *sal_get_root_ca(Sal* ctx) {
Simon Morlat's avatar
Simon Morlat committed
609
	return ctx->root_ca;
610
}
Simon Morlat's avatar
Simon Morlat committed
611

612
int sal_reset_transports(Sal *ctx){
jehan's avatar
jehan committed
613
	ms_message("Reseting transports");
jehan's avatar
jehan committed
614 615
	belle_sip_provider_clean_channels(ctx->prov);
	return 0;
616
}
Simon Morlat's avatar
Simon Morlat committed
617

618
void sal_set_dscp(Sal *ctx, int dscp){
Simon Morlat's avatar
Simon Morlat committed
619
	belle_sip_stack_set_default_dscp(ctx->stack,dscp);
620
}
Simon Morlat's avatar
Simon Morlat committed
621

622 623 624
void  sal_set_send_error(Sal *sal,int value) {
	 belle_sip_stack_set_send_error(sal->stack,value);
}
jehan's avatar
jehan committed
625 626 627
void  sal_set_recv_error(Sal *sal,int value) {
	 belle_sip_provider_set_recv_error(sal->prov,value);
}
jehan's avatar
jehan committed
628 629 630 631 632 633 634
void sal_nat_helper_enable(Sal *sal,bool_t enable) {
	sal->nat_helper_enabled=enable;
	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
635 636 637 638 639 640
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);
}
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657

SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) {
	SalAuthInfo* auth_info = sal_auth_info_new();
	auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(event)) ;
	auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)) ;
	return auth_info;
}
const char* sal_op_type_to_string(const SalOpType_t type) {
	switch(type) {
	case SalOpRegister: return "SalOpRegister";
	case SalOpCall: return "SalOpCall";
	case SalOpMessage: return "SalOpMessage";
	case SalOpPresence: return "SalOpPresence";
	default:
		return "SalOpUnknown";
	}
}