sal_op_impl.c 30.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
/*
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 20 21 22 23 24
*/
#include "sal_impl.h"

/*create an operation */
SalOp * sal_op_new(Sal *sal){
	SalOp *op=ms_new0(SalOp,1);
	__sal_op_init(op,sal);
25
	op->type=SalOpUnknown;
jehan's avatar
jehan committed
26
	op->privacy=SalPrivacyNone;
27
	op->manual_refresher=FALSE;/*tells that requests with expiry (SUBSCRIBE, PUBLISH) will be automatically refreshed*/
28
	op->sdp_handling=sal->default_sdp_handling;
29
	sal_op_ref(op);
jehan's avatar
jehan committed
30 31
	return op;
}
32

33 34 35 36 37
void sal_op_kill_dialog(SalOp *op) {
	ms_warning("op [%p]: force kill of dialog [%p]", op, op->dialog);
	belle_sip_dialog_delete(op->dialog);
}

jehan's avatar
jehan committed
38
void sal_op_release(SalOp *op){
39 40 41
	/*if in terminating state, keep this state because it means we are waiting for a response to be able to terminate the operation.*/
	if (op->state!=SalOpStateTerminating)
		op->state=SalOpStateTerminated;
42
	sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn't not mean freeing op. Make sure back pointer will not be used later*/
jehan's avatar
jehan committed
43 44
	if (op->base.release_cb)
		op->base.release_cb(&op->base);
Simon Morlat's avatar
Simon Morlat committed
45 46 47
	if (op->refresher) {
		belle_sip_refresher_stop(op->refresher);
	}
48
	op->op_released = TRUE;
49 50
	sal_op_unref(op);
}
51

52
void sal_op_release_impl(SalOp *op){
53
	ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type));
54
	if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction);
Simon Morlat's avatar
Simon Morlat committed
55
	sal_remove_pending_auth(op->base.root,op);
56 57 58
	if (op->auth_info) {
		sal_auth_info_delete(op->auth_info);
	}
59
	if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer);
jehan's avatar
jehan committed
60 61 62
	if (op->refresher) {
		belle_sip_object_unref(op->refresher);
		op->refresher=NULL;
63
	}
Simon Morlat's avatar
Simon Morlat committed
64 65
	if (op->result)
		sal_media_description_unref(op->result);
66 67 68
	if(op->replaces) belle_sip_object_unref(op->replaces);
	if(op->referred_by) belle_sip_object_unref(op->referred_by);

69
	if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans);
jehan's avatar
jehan committed
70
	if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
jehan's avatar
jehan committed
71
	if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans);
72
	if (op->event) belle_sip_object_unref(op->event);
73
	sal_error_info_reset(&op->error_info);
jehan's avatar
jehan committed
74
	__sal_op_free(op);
jehan's avatar
jehan committed
75 76
	return ;
}
77

jehan's avatar
jehan committed
78
void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){
79 80 81 82
	if (op->type == SalOpRegister) {
		/*Registration authenticate is just about registering again*/
		sal_register_refresh(op,-1);
	}else {
Simon Morlat's avatar
Simon Morlat committed
83
		/*for sure auth info will be accessible from the provider*/
84 85
		sal_process_authentication(op);
	}
jehan's avatar
jehan committed
86 87
	return ;
}
jehan's avatar
jehan committed
88

jehan's avatar
jehan committed
89 90 91 92 93
void sal_op_cancel_authentication(SalOp *h){
	ms_fatal("sal_op_cancel_authentication not implemented yet");
	return ;
}

94 95
SalAuthInfo * sal_op_get_auth_requested(SalOp *op){
	return op->auth_info;
jehan's avatar
jehan committed
96
}
97

98
belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){
99
	belle_sip_header_contact_t* contact_header;
100
	belle_sip_uri_t* contact_uri;
101

102 103 104 105 106
	if (sal_op_get_contact_address(op)) {
		contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op)));
	} else {
		contact_header= belle_sip_header_contact_new();
	}
107

108 109 110 111 112
	if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) {
		/*no uri, just creating a new one*/
		contact_uri=belle_sip_uri_new();
		belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri);
	}
113

114
	belle_sip_uri_set_user_password(contact_uri,NULL);
115
	belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op));
116 117 118
	if (op->privacy!=SalPrivacyNone){
		belle_sip_uri_set_user(contact_uri,NULL);
	}
119
	belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts);
120 121 122 123 124 125 126 127 128
	if (op->base.root->uuid){
		if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){
			char *instance_id=belle_sip_strdup_printf("\"<urn:uuid:%s>\"",op->base.root->uuid);
			belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id);
			belle_sip_free(instance_id);
		}
	}
	return contact_header;
}
129

130

Simon Morlat's avatar
Simon Morlat committed
131

132
static void add_initial_route_set(belle_sip_request_t *request, const MSList *list){
133 134 135 136 137 138 139 140 141 142 143 144 145 146
	const MSList *elem;
	for (elem=list;elem!=NULL;elem=elem->next){
		SalAddress *addr=(SalAddress*)elem->data;
		belle_sip_header_route_t *route;
		belle_sip_uri_t *uri;
		/*Optimization: if the initial route set only contains one URI which is the same as the request URI, ommit it*/
		if (elem==list && list->next==NULL){
			belle_sip_uri_t *requri=belle_sip_request_get_uri(request);
			/*skip the first route it is the same as the request uri*/
			if (strcmp(sal_address_get_domain(addr),belle_sip_uri_get_host(requri))==0 ){
				ms_message("Skipping top route of initial route-set because same as request-uri.");
				continue;
			}
		}
147

148 149
		route=belle_sip_header_route_create((belle_sip_header_address_t*)addr);
		uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)route);
150 151 152 153 154
		belle_sip_uri_set_lr_param(uri,1);
		belle_sip_message_add_header((belle_sip_message_t*)request,(belle_sip_header_t*)route);
	}
}

jehan's avatar
jehan committed
155
belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
jehan's avatar
jehan committed
156 157
	belle_sip_header_from_t* from_header;
	belle_sip_header_to_t* to_header;
jehan's avatar
jehan committed
158 159
	belle_sip_provider_t* prov=op->base.root->prov;
	belle_sip_request_t *req;
jehan's avatar
jehan committed
160
	belle_sip_uri_t* req_uri;
161
	belle_sip_uri_t* to_uri;
162
	belle_sip_header_call_id_t *call_id_header;
163 164

	const SalAddress* to_address;
165
	const MSList *elem=sal_op_get_route_addresses(op);
jehan's avatar
jehan committed
166 167
	char token[10];

168 169 170 171 172 173
	/* check that the op has a correct to address */
	to_address = sal_op_get_to_address(op);
	if( to_address == NULL ){
		ms_error("No To: address, cannot build request");
		return NULL;
	}
174

175 176 177 178 179 180
	to_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_address));
	if( to_uri == NULL ){
		ms_error("To: address is invalid, cannot build request");
		return NULL;
	}

jehan's avatar
jehan committed
181
	if (strcmp("REGISTER",method)==0 || op->privacy==SalPrivacyNone) {
182 183
		from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))
						,belle_sip_random_token(token,sizeof(token)));
jehan's avatar
jehan committed
184 185 186
	} else {
		from_header=belle_sip_header_from_create2("Anonymous <sip:anonymous@anonymous.invalid>",belle_sip_random_token(token,sizeof(token)));
	}
jehan's avatar
jehan committed
187
	/*make sure to preserve components like headers or port*/
188 189

	req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)to_uri);
190 191
	belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op));

192
	to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL);
193 194 195 196
	call_id_header = belle_sip_provider_create_call_id(prov);
	if (sal_op_get_call_id(op)) {
		belle_sip_header_call_id_set_call_id(call_id_header, sal_op_get_call_id(op));
	}
jehan's avatar
jehan committed
197

jehan's avatar
jehan committed
198
	req=belle_sip_request_create(
Simon Morlat's avatar
Simon Morlat committed
199 200
					req_uri,
					method,
201
					call_id_header,
Simon Morlat's avatar
Simon Morlat committed
202 203 204 205 206 207 208
					belle_sip_header_cseq_create(20,method),
					from_header,
					to_header,
					belle_sip_header_via_new(),
					70);

	if (op->privacy & SalPrivacyId) {
jehan's avatar
jehan committed
209 210 211
		belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)));
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity));
	}
212

213 214 215
	if (elem && strcmp(method,"REGISTER")!=0 && !op->base.root->no_initial_route){
		add_initial_route_set(req,elem);
	}
216

Simon Morlat's avatar
Simon Morlat committed
217
	if (strcmp("REGISTER",method)!=0 && op->privacy!=SalPrivacyNone ){
jehan's avatar
jehan committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
		belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new();
		if (op->privacy&SalPrivacyCritical)
			belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyCritical));
		if (op->privacy&SalPrivacyHeader)
			belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyHeader));
		if (op->privacy&SalPrivacyId)
			belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyId));
		if (op->privacy&SalPrivacyNone)
			belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyNone));
		if (op->privacy&SalPrivacySession)
			belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacySession));
		if (op->privacy&SalPrivacyUser)
			belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyUser));
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(privacy_header));
	}
233
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->base.root->supported);
jehan's avatar
jehan committed
234
	return req;
jehan's avatar
jehan committed
235 236
}

237 238 239
belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code){
	return sal_create_response_from_request(op->base.root,req,code);
}
jehan's avatar
jehan committed
240

jehan's avatar
jehan committed
241 242
/*ping: main purpose is to obtain its own contact address behind firewalls*/
int sal_ping(SalOp *op, const char *from, const char *to){
jehan's avatar
jehan committed
243 244
	sal_op_set_from(op,from);
	sal_op_set_to(op,to);
Simon Morlat's avatar
Simon Morlat committed
245
	return sal_op_send_request(op,sal_op_build_request(op,"OPTIONS"));
jehan's avatar
jehan committed
246 247
}

248 249 250 251 252 253 254 255
void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) {
	if (op->replaces){
		belle_sip_object_unref(op->replaces);
	}
	op->replaces=replaces;
	belle_sip_object_ref(op->replaces);
}

jehan's avatar
jehan committed
256 257 258
void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) {
	belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t);
	char user_agent_string[256];
259 260 261 262
	if (user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) {
		if (op->base.remote_ua!=NULL){
			ms_free(op->base.remote_ua);
		}
jehan's avatar
jehan committed
263 264 265 266
		op->base.remote_ua=ms_strdup(user_agent_string);
	}
}

jehan's avatar
jehan committed
267 268 269 270 271 272 273 274 275 276
int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) {
	belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES);

	if (!expires_header && expires>=0) {
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new()));
	}
	if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires);
	return sal_op_send_request(op,request);
}

jehan's avatar
jehan committed
277
void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) {
278
	belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ);
jehan's avatar
jehan committed
279 280 281
	belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
	sal_op_send_request(op,request);
}
282

283
static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){
284

285 286 287
	if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){
		belle_sip_header_contact_t* newct;
		/*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/
288
		sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h));
289 290 291 292 293 294
		newct = sal_op_create_contact(op);
		belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct));
		return;
	}
	/*if a header already exists in the message, replace it*/
	belle_sip_message_set_header(msg,h);
295

Simon Morlat's avatar
Simon Morlat committed
296 297
}

298
void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){
Simon Morlat's avatar
Simon Morlat committed
299 300 301
	if (op->base.sent_custom_headers){
		belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers;
		belle_sip_list_t *l=belle_sip_message_get_all_headers(ch);
302 303 304 305
		belle_sip_list_t *elem;
		for(elem=l;elem!=NULL;elem=elem->next){
			add_headers(op,(belle_sip_header_t*)elem->data,msg);
		}
Simon Morlat's avatar
Simon Morlat committed
306 307 308
		belle_sip_list_free(l);
	}
}
jehan's avatar
jehan committed
309

310
static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request, bool_t add_contact) {
jehan's avatar
jehan committed
311 312
	belle_sip_client_transaction_t* client_transaction;
	belle_sip_provider_t* prov=op->base.root->prov;
313
	belle_sip_uri_t* outbound_proxy=NULL;
jehan's avatar
jehan committed
314
	belle_sip_header_contact_t* contact;
315
	int result =-1;
316
	belle_sip_uri_t *next_hop_uri=NULL;
317

318
	if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) {
319 320
		contact = sal_op_create_contact(op);
		belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact));
321
	} /*keep existing*/
322

Simon Morlat's avatar
Simon Morlat committed
323
	_sal_op_add_custom_headers(op, (belle_sip_message_t*)request);
324

325 326
	if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) {
		/*don't put route header if  dialog is in confirmed state*/
Simon Morlat's avatar
Simon Morlat committed
327 328
		const MSList *elem=sal_op_get_route_addresses(op);
		const char *transport;
Simon Morlat's avatar
Simon Morlat committed
329
		const char *method=belle_sip_request_get_method(request);
330
		belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP");
331

Simon Morlat's avatar
Simon Morlat committed
332 333 334 335
		if (elem) {
			outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data);
			next_hop_uri=outbound_proxy;
		}else{
336
			next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request));
jehan's avatar
jehan committed
337
		}
Simon Morlat's avatar
Simon Morlat committed
338 339 340 341
		transport=belle_sip_uri_get_transport_param(next_hop_uri);
		if (transport==NULL){
			/*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use
			 * the first available transport*/
342
			if (!belle_sip_uri_is_secure(next_hop_uri)){
343
				if (udplp==NULL){
344 345 346 347 348 349 350 351 352
					if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){
						transport="tcp";
					}else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){
						transport="tls";
					}
				}
				if (transport){
					belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport);
					belle_sip_uri_set_transport_param(next_hop_uri,transport);
Simon Morlat's avatar
Simon Morlat committed
353 354
				}
			}
355
		}else{
356
#ifdef TUNNEL_ENABLED
357
			if (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){
358 359 360
				/* our tunnel mode only supports UDP. Force transport to be set to UDP */
				belle_sip_uri_set_transport_param(next_hop_uri,"udp");
			}
361
#endif
362
		}
jehan's avatar
jehan committed
363 364 365
		/*because in case of tunnel, transport can be changed*/
		transport=belle_sip_uri_get_transport_param(next_hop_uri);
		
366
		if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport &&
367 368 369 370 371
			(strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){
			/*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/
			belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t);
			belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL);
		}
jehan's avatar
jehan committed
372
	}
373

jehan's avatar
jehan committed
374
	client_transaction = belle_sip_provider_create_client_transaction(prov,request);
375
	belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op));
jehan's avatar
jehan committed
376 377 378 379
	if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans);
	op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/
	belle_sip_object_ref(op->pending_client_trans);

380 381
	if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL)
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent));
jehan's avatar
jehan committed
382

383
	if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION)
jehan's avatar
jehan committed
384 385
		&& !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) {
		/*hmm just in case we already have authentication param in cache*/
386
		belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL,op->base.realm);
jehan's avatar
jehan committed
387
	}
388
	result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/);
389

390 391 392 393
	/*update call id if not set yet for this OP*/
	if (result == 0 && !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(request), belle_sip_header_call_id_t))));
	}
394

395
	return result;
jehan's avatar
jehan committed
396

jehan's avatar
jehan committed
397
}
jehan's avatar
jehan committed
398

jehan's avatar
jehan committed
399
int sal_op_send_request(SalOp* op, belle_sip_request_t* request)  {
jehan's avatar
jehan committed
400
	bool_t need_contact=FALSE;
401 402 403
	if (request==NULL) {
		return -1; /*sanity check*/
	}
jehan's avatar
jehan committed
404
	/*
405 406 407
	  Header field          where   proxy ACK BYE CAN INV OPT REG
	  ___________________________________________________________
	  Contact                 R            o   -   -   m   o   o
jehan's avatar
jehan committed
408 409 410 411
	 */
	if (strcmp(belle_sip_request_get_method(request),"INVITE")==0
			||strcmp(belle_sip_request_get_method(request),"REGISTER")==0
			||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0
412 413
			||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0
			||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/
jehan's avatar
jehan committed
414
		need_contact=TRUE;
jehan's avatar
jehan committed
415

jehan's avatar
jehan committed
416
	return _sal_op_send_request_with_contact(op, request,need_contact);
jehan's avatar
jehan committed
417 418
}

419
int sal_reason_to_sip_code(SalReason r){
420 421
	int ret=500;
	switch(r){
422 423 424 425 426 427
		case SalReasonNone:
			ret=200;
			break;
		case SalReasonIOError:
			ret=503;
			break;
428 429
		case SalReasonUnknown:
			ret=400;
jehan's avatar
jehan committed
430
			break;
431 432
		case SalReasonBusy:
			ret=486;
433
			break;
434 435
		case SalReasonDeclined:
			ret=603;
jehan's avatar
jehan committed
436
			break;
437 438
		case SalReasonDoNotDisturb:
			ret=600;
jehan's avatar
jehan committed
439
			break;
440 441
		case SalReasonForbidden:
			ret=403;
jehan's avatar
jehan committed
442
			break;
443
		case SalReasonUnsupportedContent:
444
			ret=415;
jehan's avatar
jehan committed
445
			break;
446 447
		case SalReasonNotFound:
			ret=404;
jehan's avatar
jehan committed
448
			break;
449 450
		case SalReasonRedirect:
			ret=302;
jehan's avatar
jehan committed
451
			break;
452 453
		case SalReasonTemporarilyUnavailable:
			ret=480;
454
			break;
455 456
		case SalReasonServiceUnavailable:
			ret=503;
jehan's avatar
jehan committed
457
			break;
458 459 460
		case SalReasonRequestPending:
			ret=491;
			break;
jehan's avatar
jehan committed
461 462 463
		case SalReasonUnauthorized:
			ret=401;
			break;
464
		case SalReasonNotAcceptable:
465
			ret=488; /*or maybe 606 Not Acceptable ?*/
466
			break;
467 468 469
		case SalReasonNoMatch:
			ret=481;
			break;
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
		case SalReasonRequestTimeout:
			ret=408;
			break;
		case SalReasonMovedPermanently:
			ret=301;
			break;
		case SalReasonGone:
			ret=410;
			break;
		case SalReasonAddressIncomplete:
			ret=484;
			break;
		case SalReasonNotImplemented:
			ret=501;
			break;
		case SalReasonServerTimeout:
			ret=504;
			break;
		case SalReasonBadGateway:
			ret=502;
			break;
491 492 493
		case SalReasonInternalError:
			ret=500;
			break;
494 495 496 497
	}
	return ret;
}

498 499
SalReason _sal_reason_from_sip_code(int code) {
	if (code>=100 && code<300) return SalReasonNone;
500

501
	switch(code) {
502 503
	case 0:
		return SalReasonIOError;
504
	case 301:
505
		return SalReasonMovedPermanently;
506
	case 302:
507
		return SalReasonRedirect;
jehan's avatar
jehan committed
508 509
	case 401:
	case 407:
510
		return SalReasonUnauthorized;
511
	case 403:
512
		return SalReasonForbidden;
513
	case 404:
514
		return SalReasonNotFound;
515
	case 408:
516
		return SalReasonRequestTimeout;
517
	case 410:
518
		return SalReasonGone;
519
	case 415:
520
		return SalReasonUnsupportedContent;
521 522 523 524
	case 422:
		ms_error ("422 not implemented yet");;
		break;
	case 480:
525
		return SalReasonTemporarilyUnavailable;
526
	case 481:
527
		return SalReasonNoMatch;
528
	case 484:
529
		return SalReasonAddressIncomplete;
530
	case 486:
531
		return SalReasonBusy;
532
	case 487:
533
		return SalReasonNone;
534
	case 488:
535
		return SalReasonNotAcceptable;
536
	case 491:
537
		return SalReasonRequestPending;
538 539
	case 500:
		return SalReasonInternalError;
540
	case 501:
541
		return SalReasonNotImplemented;
542
	case 502:
543
		return SalReasonBadGateway;
544 545
	case 503:
		return SalReasonServiceUnavailable;
546
	case 504:
547
		return SalReasonServerTimeout;
548
	case 600:
549
		return SalReasonDoNotDisturb;
550
	case 603:
551
		return SalReasonDeclined;
552
	default:
553
		return SalReasonUnknown;
554
	}
555
	return SalReasonUnknown;
556
}
557 558 559 560 561 562 563

const SalErrorInfo *sal_error_info_none(void){
	static SalErrorInfo none={
		SalReasonNone,
		"Ok",
		200,
		NULL,
564 565
		NULL,
		
566 567 568 569 570 571 572 573
	};
	return &none;
}

void sal_error_info_reset(SalErrorInfo *ei){
	if (ei->status_string){
		ms_free(ei->status_string);
		ei->status_string=NULL;
574
	}
575 576 577
	if (ei->warnings){
		ms_free(ei->warnings);
		ei->warnings=NULL;
578

jehan's avatar
jehan committed
579
	}
580 581 582 583
	if (ei->full_string){
		ms_free(ei->full_string);
		ei->full_string=NULL;
	}
584 585 586 587
	if (ei->protocol){
		ms_free(ei->protocol);
		ei->protocol = NULL;
	}
588 589
	ei->protocol_code=0;
	ei->reason=SalReasonNone;
590
	ei->sub_sei = NULL;
591 592
}

593
void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol, int code, const char *status_string, const char *warning){
594
	sal_error_info_reset(ei);
595
	if (reason==SalReasonUnknown && strcmp(protocol, "SIP") == 0 && code != 0) ei->reason=_sal_reason_from_sip_code(code);
596 597 598 599 600 601
	else{
		ei->reason=reason;
		if (code == 0) {
			code = sal_reason_to_sip_code(reason);
		}
	}
602 603 604
	ei->protocol_code=code;
	ei->status_string=status_string ? ms_strdup(status_string) : NULL;
	ei->warnings=warning ? ms_strdup(warning) : NULL;
605
	ei->protocol = protocol ? ms_strdup(protocol) : NULL;
606 607 608 609 610 611 612
	if (ei->status_string){
		if (ei->warnings)
			ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings);
		else ei->full_string=ms_strdup(ei->status_string);
	}
}

613 614 615
void sal_op_set_reason_error_info(SalOp *op, belle_sip_message_t *msg){
	belle_sip_header_reason_t* reason_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_reason_t);
	if (reason_header){
616
		SalErrorInfo *ei=&op->reason_error_info; // ?//
617 618 619 620 621 622 623
		const char *protocol = belle_sip_header_reason_get_protocol(reason_header);
		int code = belle_sip_header_reason_get_cause(reason_header);
		const char *text = belle_sip_header_reason_get_text(reason_header);
		sal_error_info_set(ei, SalReasonUnknown, protocol, code, text, NULL);
	}
}

624 625 626 627 628 629
void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){
	int code = belle_sip_response_get_status_code(response);
	const char *reason_phrase=belle_sip_response_get_reason_phrase(response);
	belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning");
	SalErrorInfo *ei=&op->error_info;
	const char *warnings;
630

631
	warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL;
632
	sal_error_info_set(ei,SalReasonUnknown,"SIP", code,reason_phrase,warnings);
633
	sal_op_set_reason_error_info(op, BELLE_SIP_MESSAGE(response));
634 635 636 637
}

const SalErrorInfo *sal_op_get_error_info(const SalOp *op){
	return &op->error_info;
jehan's avatar
jehan committed
638
}
639

640 641 642 643
const SalErrorInfo * sal_op_get_reason_error_info(const SalOp *op){
	return &op->reason_error_info;
}

644 645 646



647 648 649 650 651 652 653 654 655 656 657 658
static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){
	belle_sip_dialog_set_application_data(dialog,NULL);
	sal_op_unref(op);
	belle_sip_object_unref(dialog);
}

static belle_sip_dialog_t *link_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){
	belle_sip_dialog_set_application_data(dialog,sal_op_ref(op));
	belle_sip_object_ref(dialog);
	return dialog;
}

659
void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) {
660
	ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]",op,op->dialog,dialog);
Simon Morlat's avatar
Simon Morlat committed
661 662
	sal_op_ref(op);
	if (op->dialog!=dialog){
663 664 665 666
		if (op->dialog){
			/*FIXME: shouldn't we delete unconfirmed dialogs ?*/
			unlink_op_with_dialog(op,op->dialog);
			op->dialog=NULL;
667
		}
668 669 670 671
		if (dialog) {
			op->dialog=link_op_with_dialog(op,dialog);
			belle_sip_dialog_enable_pending_trans_checking(dialog,op->base.root->pending_trans_checking);
		}
672
	}
Simon Morlat's avatar
Simon Morlat committed
673
	sal_op_unref(op);
674
}
675 676 677 678 679 680 681
/*return reffed op*/
SalOp* sal_op_ref(SalOp* op) {
	op->ref++;
	return op;
}
/*return null, destroy op if ref count =0*/
void* sal_op_unref(SalOp* op) {
Simon Morlat's avatar
Simon Morlat committed
682 683
	op->ref--;
	if (op->ref==0) {
684
		sal_op_release_impl(op);
Simon Morlat's avatar
Simon Morlat committed
685 686
	}else if (op->ref<0){
		ms_fatal("SalOp [%p]: too many unrefs.",op);
687 688 689
	}
	return NULL;
}
Simon Morlat's avatar
Simon Morlat committed
690

jehan's avatar
jehan committed
691
int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) {
Simon Morlat's avatar
Simon Morlat committed
692
	if (sal_op_send_request_with_expires(op,req,expires)==0) {
jehan's avatar
jehan committed
693 694 695 696 697
		if (op->refresher) {
			belle_sip_refresher_stop(op->refresher);
			belle_sip_object_unref(op->refresher);
		}
		if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) {
698
			/*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified
Simon Morlat's avatar
Simon Morlat committed
699 700 701 702 703 704
			 * that it is terminated anymore.*/
			sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*/
			/* Note that the refresher will replace our data with belle_sip_transaction_set_application_data().
			 Something in the design is not very good here, it makes things complicated to the belle-sip user.
			 Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction
			 notify the user as a normal transaction*/
jehan's avatar
jehan committed
705
			belle_sip_refresher_set_listener(op->refresher,listener,op);
jehan's avatar
jehan committed
706
			belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after);
707
			belle_sip_refresher_set_realm(op->refresher,op->base.realm);
708
			belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher);
jehan's avatar
jehan committed
709 710 711 712 713
			return 0;
		} else {
			return -1;
		}
	}
Simon Morlat's avatar
Simon Morlat committed
714
	return -1;
jehan's avatar
jehan committed
715 716
}

717
const char* sal_op_state_to_string(const SalOpState value) {
jehan's avatar
jehan committed
718 719 720 721 722 723
	switch(value) {
	case SalOpStateEarly: return"SalOpStateEarly";
	case SalOpStateActive: return "SalOpStateActive";
	case SalOpStateTerminating: return "SalOpStateTerminating";
	case SalOpStateTerminated: return "SalOpStateTerminated";
	default:
724
		return "Unknown";
jehan's avatar
jehan committed
725 726
	}
}
Simon Morlat's avatar
Simon Morlat committed
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750

/*
 * Warning: this function takes owneship of the custom headers
 */
void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){
	SalOpBase *b=(SalOpBase *)op;
	if (b->sent_custom_headers){
		sal_custom_header_free(b->sent_custom_headers);
		b->sent_custom_headers=NULL;
	}
	if (ch) belle_sip_object_ref((belle_sip_message_t*)ch);
	b->sent_custom_headers=ch;
}

void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){
	if (incoming) belle_sip_object_ref(incoming);
	if (op->base.recv_custom_headers){
		belle_sip_object_unref(op->base.recv_custom_headers);
		op->base.recv_custom_headers=NULL;
	}
	if (incoming){
		op->base.recv_custom_headers=(SalCustomHeader*)incoming;
	}
}
751 752

const char *sal_op_get_remote_contact(const SalOp *op){
753
	/*
Simon Morlat's avatar
Simon Morlat committed
754 755
	 * remote contact is filled in process_response
	 */
756
	return op->base.remote_contact;
757 758
}

759 760 761 762 763 764 765 766 767 768 769
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg) {
	belle_sip_body_handler_t *body_handler = belle_sip_message_get_body_handler(msg);
	if (body_handler != NULL) {
		belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t);
		belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_length_t);
		belle_sip_header_t *content_encoding = belle_sip_message_get_header(msg, "Content-Encoding");
		if (content_type != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_type));
		if (content_length != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_length));
		if (content_encoding != NULL) belle_sip_body_handler_add_header(body_handler, content_encoding);
	}
	return (SalBodyHandler *)body_handler;
770
}
771

jehan's avatar
jehan committed
772 773
void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) {
	op->privacy=privacy;
jehan's avatar
jehan committed
774
}
jehan's avatar
jehan committed
775 776
SalPrivacyMask sal_op_get_privacy(const SalOp* op) {
	return op->privacy;
jehan's avatar
jehan committed
777
}
778 779 780 781 782 783 784

bool_t sal_op_is_secure(const SalOp* op) {
	const SalAddress* from = sal_op_get_from_address(op);
	const SalAddress* to = sal_op_get_to_address(op);

	return from && to && strcasecmp("sips",sal_address_get_scheme(from))==0 && strcasecmp("sips",sal_address_get_scheme(to))==0;
}
785 786 787 788

void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){
	op->manual_refresher=enabled;
}
789

790
int sal_op_get_address_family(SalOp *op){
791 792
	belle_sip_transaction_t *tr=NULL;
	belle_sip_header_address_t *contact;
793
	
794

795 796 797 798 799 800 801
	if (op->refresher)
		tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher);

	if (tr==NULL)
		tr=(belle_sip_transaction_t *)op->pending_client_trans;
	if (tr==NULL)
		tr=(belle_sip_transaction_t *)op->pending_server_trans;
802
	
803 804
	if (tr==NULL){
		ms_error("Unable to determine IP version from signaling operation.");
805
		return AF_UNSPEC;
806
	}
807 808 809 810 811 812 813
	
	
	if (op->refresher) {
		belle_sip_response_t *resp = belle_sip_transaction_get_response(tr);
		belle_sip_header_via_t *via = resp ?belle_sip_message_get_header_by_type(resp,belle_sip_header_via_t):NULL;
		if (!via){
			ms_error("Unable to determine IP version from signaling operation, no via header found.");
814
			return AF_UNSPEC;
815
		}
816
		return (strchr(belle_sip_header_via_get_host(via),':') != NULL) ? AF_INET6 : AF_INET;
817 818 819 820 821 822
	} else {
		belle_sip_request_t *req = belle_sip_transaction_get_request(tr);
		contact=(belle_sip_header_address_t*)belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t);
		if (!contact){
			ms_error("Unable to determine IP version from signaling operation, no contact header found.");
		}
823
		return sal_address_is_ipv6((SalAddress*)contact) ? AF_INET6 : AF_INET;
824 825 826
	}
}

827 828 829 830 831 832 833
bool_t sal_op_is_idle(SalOp *op){
	if (op->dialog){
		return !belle_sip_dialog_request_pending(op->dialog);
	}
	return TRUE;
}

834 835 836 837 838
void sal_op_stop_refreshing(SalOp *op){
	if (op->refresher){
		belle_sip_refresher_stop(op->refresher);
	}
}
839

840 841 842
void sal_call_set_sdp_handling(SalOp *h, SalOpSDPHandling handling)  {
	if (handling != SalOpSDPNormal) ms_message("Enabling special SDP handling for SalOp[%p]!", h);
	h->sdp_handling = handling;
843
}
844 845 846
void sal_op_cnx_ip_to_0000_if_sendonly_enable(SalOp *op,bool_t yesno) {
	op->cnx_ip_to_0000_if_sendonly_enabled = yesno;
}
847

848 849 850
bool_t sal_op_cnx_ip_to_0000_if_sendonly_enabled(SalOp *op) {
	return op->cnx_ip_to_0000_if_sendonly_enabled;
}
851 852 853 854

bool_t sal_op_is_forked_of(const SalOp *op1, const SalOp *op2){
	return op1->base.call_id && op2->base.call_id && strcmp(op1->base.call_id, op2->base.call_id) == 0;
}
855 856 857 858 859
int sal_op_refresh(SalOp *op) {
	if (op->refresher) {
		belle_sip_refresher_refresh(op->refresher,belle_sip_refresher_get_expires(op->refresher));
		return 0;
	}
Simon Morlat's avatar
Simon Morlat committed
860
	ms_warning("sal_refresh on op [%p] of type [%s] no refresher",op,sal_op_type_to_string(op->type));
861 862
	return -1;
}
863 864 865 866 867 868 869 870 871 872

void sal_op_set_event(SalOp *op, const char *eventname){
	belle_sip_header_event_t *header = NULL;
	if (op->event) belle_sip_object_unref(op->event);
	if (eventname){
		header = belle_sip_header_event_create(eventname);
		belle_sip_object_ref(header);
	}
	op->event = header;
}