sal_op_call.c 30.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 17 18 19
/*
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.
*/
#include "sal_impl.h"
jehan's avatar
jehan committed
20
#include "offeranswer.h"
jehan's avatar
jehan committed
21

Simon Morlat's avatar
Simon Morlat committed
22
/*used for calls terminated before creation of a dialog*/
23
static void call_set_released(SalOp* op){
Simon Morlat's avatar
Simon Morlat committed
24 25 26 27 28
	if (!op->call_released){
		op->state=SalOpStateTerminated;
		op->base.root->callbacks.call_released(op);
		op->call_released=TRUE;
	}
29
}
30

Simon Morlat's avatar
Simon Morlat committed
31
/*used when the SalOp was ref'd by the dialog, in which case we rely only on the dialog terminated notification*/
jehan's avatar
jehan committed
32 33 34 35
static void call_set_released_and_unref(SalOp* op) {
	call_set_released(op);
	sal_op_unref(op);
}
36

Simon Morlat's avatar
Simon Morlat committed
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
static void call_set_error(SalOp* op,belle_sip_response_t* response){
	SalError error=SalErrorUnknown;
	SalReason sr=SalReasonUnknown;
	belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
	char* reason=(char*)belle_sip_response_get_reason_phrase(response);
	int code = belle_sip_response_get_status_code(response);
	if (reason_header){
		reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header)));
	}
	sal_compute_sal_errors_from_code(code,&error,&sr);
	op->base.root->callbacks.call_failure(op,error,sr,reason,code);
	if (reason_header != NULL){
		ms_free(reason);
	}
}
53

jehan's avatar
jehan committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67
static void sdp_process(SalOp *h){
	ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming");
	if (h->result){
		sal_media_description_unref(h->result);
	}
	h->result=sal_media_description_new();
	if (h->sdp_offering){
		offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);
	}else{
		int i;
		if (h->sdp_answer){
			belle_sip_object_unref(h->sdp_answer);
		}
		offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);
68
		h->sdp_answer=(belle_sdp_session_description_t *)belle_sip_object_ref(media_description_to_sdp(h->result));
jehan's avatar
jehan committed
69 70 71 72 73
		/*once we have generated the SDP answer, we modify the result description for processing by the upper layer.
		 It should contains media parameters constraint from the remote offer, not our response*/
		strcpy(h->result->addr,h->base.remote_media->addr);
		h->result->bandwidth=h->base.remote_media->bandwidth;

74 75 76 77 78 79
		for(i=0;i<h->result->n_active_streams;++i){
			/*fixme add rtcp*/
			strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
			h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
			h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
			h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
jehan's avatar
jehan committed
80

81 82
			if (h->result->streams[i].proto == SalProtoRtpSavp) {
				h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
jehan's avatar
jehan committed
83 84 85 86 87 88 89 90
			}
		}
	}

}
static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) {
	belle_sip_header_content_type_t* content_type ;
	belle_sip_header_content_length_t* content_length;
Ghislain MARY's avatar
Ghislain MARY committed
91
	belle_sip_error_code error = BELLE_SIP_OK;
92
	size_t length = 0;
Simon Morlat's avatar
Simon Morlat committed
93
	char buff[2048];
jehan's avatar
jehan committed
94 95 96

	if (session_desc) {
		content_type = belle_sip_header_content_type_create("application","sdp");
Ghislain MARY's avatar
Ghislain MARY committed
97 98
		error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,sizeof(buff),&length);
		if (error != BELLE_SIP_OK) {
jehan's avatar
jehan committed
99
			ms_error("Buffer too small or sdp too big");
Simon Morlat's avatar
Simon Morlat committed
100
			return -1;
jehan's avatar
jehan committed
101 102 103 104 105 106 107 108 109 110 111 112
		}

		content_length= belle_sip_header_content_length_create(length);
		belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_type));
		belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_length));
		belle_sip_message_set_body(msg,buff,length);
		return 0;
	} else {
		return -1;
	}
}
static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){
Simon Morlat's avatar
Simon Morlat committed
113 114 115 116 117
	int err;
	belle_sdp_session_description_t *sdp=media_description_to_sdp(desc);
	err=set_sdp(msg,sdp);
	belle_sip_object_unref(sdp);
	return err;
jehan's avatar
jehan committed
118 119

}
jehan's avatar
jehan committed
120
static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
jehan's avatar
jehan committed
121
	SalOp* op=(SalOp*)user_ctx;
Simon Morlat's avatar
Simon Morlat committed
122 123 124
	
	if (op->state==SalOpStateTerminated) return;
	
jehan's avatar
jehan committed
125 126 127
	if (!op->dialog)  {
		/*call terminated very early*/
		op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503);
128
		call_set_released(op);
jehan's avatar
jehan committed
129 130 131
	} else {
		/*dialog will terminated shortly, nothing to do*/
	}
jehan's avatar
jehan committed
132
}
jehan's avatar
jehan committed
133 134
static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
	SalOp* op=(SalOp*)ctx;
135

Simon Morlat's avatar
Simon Morlat committed
136
	if (op->dialog && op->dialog==belle_sip_dialog_terminated_event_get_dialog(event))  {
137
		/*belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog);*/
Simon Morlat's avatar
Simon Morlat committed
138
		ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_event_get_dialog(event),op);
139
		
140
		switch(belle_sip_dialog_get_previous_state(op->dialog)) {
141 142
			case BELLE_SIP_DIALOG_CONFIRMED:
				if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) {
Simon Morlat's avatar
Simon Morlat committed
143
					/*this is probably a normal termination from a BYE*/
144 145
					op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
					op->state=SalOpStateTerminating;
146
				}
147 148 149
			break;
			default:
			break;
150
		}
151 152 153
		belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack)
							,(belle_sip_callback_t) call_set_released_and_unref
							, op);
154 155
	} else {
		ms_error("dialog unknown for op ");
jehan's avatar
jehan committed
156
	}
jehan's avatar
jehan committed
157
}
158

jehan's avatar
jehan committed
159 160 161 162 163 164 165 166
static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) {
	belle_sdp_session_description_t* sdp;
	if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) {
		op->base.remote_media=sal_media_description_new();
		sdp_to_media_description(sdp,op->base.remote_media);
		if (op->base.local_media) sdp_process(op);
	}
}
Simon Morlat's avatar
Simon Morlat committed
167

jehan's avatar
jehan committed
168 169
static void cancelling_invite(SalOp* op ){
	belle_sip_request_t* cancel;
jehan's avatar
jehan committed
170
	ms_message("Cancelling INVITE request from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op));
171
	cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans);
jehan's avatar
jehan committed
172
	sal_op_send_request(op,cancel);
173
	op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
174
}
175

176
static void call_process_response(void *op_base, const belle_sip_response_event_t *event){
jehan's avatar
jehan committed
177 178 179
	SalOp* op = (SalOp*)op_base;
	belle_sip_request_t* ack;
	belle_sip_dialog_state_t dialog_state;
jehan's avatar
jehan committed
180
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
181
	belle_sip_request_t* req;
jehan's avatar
jehan committed
182 183
	belle_sip_response_t* response=belle_sip_response_event_get_response(event);
	int code = belle_sip_response_get_status_code(response);
184 185


jehan's avatar
jehan committed
186
	if (!client_transaction) {
187
		ms_warning("Discarding stateless response [%i] on op [%p]",code,op);
jehan's avatar
jehan committed
188 189
		return;
	}
190
	req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
191
	set_or_update_dialog(op,belle_sip_response_event_get_dialog(event));
192
	dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
193 194
	
	ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,op->dialog,belle_sip_dialog_state_to_string(dialog_state));
jehan's avatar
jehan committed
195

Simon Morlat's avatar
Simon Morlat committed
196
	switch(dialog_state) {
197
		case BELLE_SIP_DIALOG_NULL:
jehan's avatar
jehan committed
198
		case BELLE_SIP_DIALOG_EARLY: {
199
			if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) {
200
				if (op->state == SalOpStateTerminating) {
201
					/*check if CANCEL was sent before*/
jehan's avatar
jehan committed
202
					if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) {
203
						/*it wasn't sent */
204
						if (code<200) {
jehan's avatar
jehan committed
205
							cancelling_invite(op);
206 207 208
						}else{
							/* no need to send the INVITE because the UAS rejected the INVITE*/
							if (op->dialog==NULL) call_set_released(op);
jehan's avatar
jehan committed
209
						}
210
					} else {
211 212 213 214
						/*it was sent already, so just expect the 487 or any error response to send the call_released() notification*/
						if (code>=300){
							if (op->dialog==NULL) call_set_released(op);
						}
215
					}
jehan's avatar
jehan committed
216
				} else if (code >= 180 && code<300) {
217 218
					handle_sdp_from_response(op,response);
					op->base.root->callbacks.call_ringing(op);
jehan's avatar
jehan committed
219
				} else if (code>=300){
220 221
					call_set_error(op,response);
					if (op->dialog==NULL) call_set_released(op);
222
				}
223
			}
jehan's avatar
jehan committed
224
		}
225
		break;
jehan's avatar
jehan committed
226 227
		case BELLE_SIP_DIALOG_CONFIRMED: {
			switch (op->state) {
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
				case SalOpStateEarly:/*invite case*/
				case SalOpStateActive: /*re-invite case*/
					if (code >=200
						&& code<300
						&& strcmp("INVITE",belle_sip_request_get_method(req))==0) {
						handle_sdp_from_response(op,response);
						ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog));
						if (ack==NULL) {
							ms_error("This call has been already terminated.");
							return ;
						}
						if (op->sdp_answer){
							set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer);
							belle_sip_object_unref(op->sdp_answer);
							op->sdp_answer=NULL;
						}
						belle_sip_dialog_send_ack(op->dialog,ack);
						op->base.root->callbacks.call_accepted(op); /*INVITE*/
						op->state=SalOpStateActive;
					}  else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){
						call_set_error(op,response);
					} else {
							/*ignoring*/
jehan's avatar
jehan committed
251
					}
252 253 254 255 256 257 258
				break;
				case SalOpStateTerminating:
					sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
				break;
				case SalOpStateTerminated:
				default:
					ms_error("Call op [%p] receives unexpected answer [%i] while in state [%s].",op,code, sal_op_state_to_string(op->state));
jehan's avatar
jehan committed
259 260
			}
		}
261
		break;
262
		case BELLE_SIP_DIALOG_TERMINATED: {
263
			if (code >= 300){
264
				call_set_error(op,response);
265
			}
266
		}
267
		break;
jehan's avatar
jehan committed
268
		default: {
269
			ms_error("call op [%p] receive answer [%i] not implemented",op,code);
jehan's avatar
jehan committed
270
		}
271
		break;
jehan's avatar
jehan committed
272
	}
jehan's avatar
jehan committed
273
}
274

jehan's avatar
jehan committed
275
static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
276
	SalOp* op=(SalOp*)user_ctx;
Simon Morlat's avatar
Simon Morlat committed
277 278 279
	
	if (op->state==SalOpStateTerminated) return;
	
280 281 282
	if (!op->dialog)  {
		/*call terminated very early*/
		op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408);
283
		call_set_released(op);
284 285 286
	} else {
		/*dialog will terminated shortly, nothing to do*/
	}
jehan's avatar
jehan committed
287
}
Simon Morlat's avatar
Simon Morlat committed
288

jehan's avatar
jehan committed
289
static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
290 291 292 293 294 295 296 297 298 299 300 301
	SalOp* op = (SalOp*)user_ctx;
	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);
	belle_sip_request_t* req;
	belle_sip_response_t* resp;
	if (client_transaction) {
		req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
		resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction));
	} else {
		req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction));
		resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction));
	}
Simon Morlat's avatar
Simon Morlat committed
302 303 304 305 306
	if (op->state ==SalOpStateTerminating
			&& strcmp("BYE",belle_sip_request_get_method(req))==0
			&& (!resp || (belle_sip_response_get_status_code(resp) !=401
			&& belle_sip_response_get_status_code(resp) !=407))) {
		if (op->dialog==NULL) call_set_released(op);
307
	}
jehan's avatar
jehan committed
308
}
Simon Morlat's avatar
Simon Morlat committed
309

jehan's avatar
jehan committed
310 311 312
static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_transaction, belle_sip_request_t* request,int status_code) {
	belle_sip_response_t* resp;
	op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
313
	resp=sal_op_create_response_from_request(op,request,status_code);
jehan's avatar
jehan committed
314 315
	belle_sip_server_transaction_send_response(server_transaction,resp);
}
Simon Morlat's avatar
Simon Morlat committed
316

jehan's avatar
jehan committed
317 318 319 320 321 322 323
static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) {
	belle_sip_response_t* resp;
	resp=belle_sip_response_create_from_request(request,500);
	belle_sip_server_transaction_send_response(server_transaction,resp);
	return;
}

jehan's avatar
jehan committed
324 325 326 327 328 329 330 331 332 333
static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
	belle_sdp_session_description_t* sdp;
	if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(invite)))) {
		op->sdp_offering=FALSE;
		op->base.remote_media=sal_media_description_new();
		sdp_to_media_description(sdp,op->base.remote_media);
		belle_sip_object_unref(sdp);
	}else
		op->sdp_offering=TRUE;
}
334

jehan's avatar
jehan committed
335 336
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
	SalOp* op = (SalOp*)op_base;
jehan's avatar
jehan committed
337
	belle_sip_server_transaction_t* server_transaction=NULL;
jehan's avatar
jehan committed
338
	belle_sdp_session_description_t* sdp;
jehan's avatar
jehan committed
339 340
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_state_t dialog_state;
341
	belle_sip_response_t* resp;
jehan's avatar
jehan committed
342
	belle_sip_header_t* call_info;
jehan's avatar
jehan committed
343

jehan's avatar
jehan committed
344 345 346
	if (strcmp("ACK",belle_sip_request_get_method(req))!=0){  /*ACK does'nt create srv transaction*/
		server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
		belle_sip_object_ref(server_transaction);
347 348 349 350
		belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op);
		sal_op_ref(op);
	}

351
	if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
352
		if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
353 354
		/*updating pending invite transaction*/
		op->pending_server_trans=server_transaction;
355
		belle_sip_object_ref(op->pending_server_trans);
356 357
	}

jehan's avatar
jehan committed
358
	if (!op->dialog) {
359
		set_or_update_dialog(op,belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)));
jehan's avatar
jehan committed
360 361 362 363 364 365
		ms_message("new incoming call from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
	}
	dialog_state=belle_sip_dialog_get_state(op->dialog);
	switch(dialog_state) {

	case BELLE_SIP_DIALOG_NULL: {
366 367 368 369 370 371
		if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
			if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) {
				belle_sip_object_ref(op->replaces);
			} else if(op->replaces) {
				ms_warning("replace header already set");
			}
jehan's avatar
jehan committed
372

373
			process_sdp_for_invite(op,req);
jehan's avatar
jehan committed
374

375 376 377 378 379
			if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) {
				if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) {
					op->auto_answer_asked=TRUE;
					ms_message("The caller asked to automatically answer the call(Emergency?)\n");
				}
jehan's avatar
jehan committed
380 381
			}

382
			op->base.root->callbacks.call_received(op);
jehan's avatar
jehan committed
383

384 385
			break;
		} /* else same behavior as for EARLY state*/
jehan's avatar
jehan committed
386
	}
jehan's avatar
jehan committed
387 388 389 390 391 392
	case BELLE_SIP_DIALOG_EARLY: {
		//hmm probably a cancel
		if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) {
			if(belle_sip_request_event_get_server_transaction(event)) {
				/*first answer 200 ok to cancel*/
				belle_sip_server_transaction_send_response(server_transaction
393
						,sal_op_create_response_from_request(op,req,200));
394
				/*terminate invite transaction*/
jehan's avatar
jehan committed
395
				call_terminated(op
Simon Morlat's avatar
Simon Morlat committed
396 397
						,op->pending_server_trans
						,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487);
jehan's avatar
jehan committed
398 399 400 401 402


			} else {
				/*call leg does not exist*/
				belle_sip_server_transaction_send_response(server_transaction
403
							,sal_op_create_response_from_request(op,req,481));
jehan's avatar
jehan committed
404
			}
jehan's avatar
jehan committed
405
		} else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) {
406
			resp=sal_op_create_response_from_request(op,req,200);
jehan's avatar
jehan committed
407
			belle_sip_server_transaction_send_response(server_transaction,resp);
jehan's avatar
jehan committed
408
		} else {
409
			belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req));
410
			unsupported_method(server_transaction,req);
jehan's avatar
jehan committed
411 412 413
		}
		break;
	}
jehan's avatar
jehan committed
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
	case BELLE_SIP_DIALOG_CONFIRMED:
		/*great ACK received*/
		if (strcmp("ACK",belle_sip_request_get_method(req))==0) {
			if (op->sdp_offering){
				if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))){
					if (op->base.remote_media)
						sal_media_description_unref(op->base.remote_media);
					op->base.remote_media=sal_media_description_new();
					sdp_to_media_description(sdp,op->base.remote_media);
					sdp_process(op);
					belle_sip_object_unref(sdp);
				}
			}
			/*FIXME
		if (op->reinvite){
			op->reinvite=FALSE;
		}*/
			op->base.root->callbacks.call_ack(op);
		} else if(strcmp("BYE",belle_sip_request_get_method(req))==0) {
433
			resp=sal_op_create_response_from_request(op,req,200);
434
			belle_sip_server_transaction_send_response(server_transaction,resp);
435 436 437
			op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
			op->state=SalOpStateTerminating;
			/*call end not notified by dialog deletion because transaction can end before dialog*/
jehan's avatar
jehan committed
438 439 440 441 442 443 444 445 446 447 448 449 450
		} else if(strcmp("INVITE",belle_sip_request_get_method(req))==0) {
			/*re-invite*/
			if (op->base.remote_media){
				sal_media_description_unref(op->base.remote_media);
				op->base.remote_media=NULL;
			}
			if (op->result){
				sal_media_description_unref(op->result);
				op->result=NULL;
			}
			process_sdp_for_invite(op,req);

			op->base.root->callbacks.call_updating(op);
451 452
		} else if (strcmp("INFO",belle_sip_request_get_method(req))==0){
			if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))
jehan's avatar
jehan committed
453 454 455 456 457 458 459
				&&	strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) {
				/*vfu request*/
				ms_message("Receiving VFU request on op [%p]",op);
				if (op->base.root->callbacks.vfu_request){
					op->base.root->callbacks.vfu_request(op);

				}
460 461 462 463 464 465 466 467 468 469
			}else{
				SalBody salbody;
				if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) {
					op->base.root->callbacks.info_received(op,&salbody);
				} else {
					op->base.root->callbacks.info_received(op,NULL);
				}
			}
			resp=sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
470
		}else if (strcmp("REFER",belle_sip_request_get_method(req))==0) {
471
			sal_op_process_refer(op,event,server_transaction);
jehan's avatar
jehan committed
472
		} else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
473
			sal_op_call_process_notify(op,event,server_transaction);
jehan's avatar
jehan committed
474
		} else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) {
475
			resp=sal_op_create_response_from_request(op,req,200);
jehan's avatar
jehan committed
476
			belle_sip_server_transaction_send_response(server_transaction,resp);
477
		} else{
jehan's avatar
jehan committed
478
			ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog);
479
			unsupported_method(server_transaction,req);
jehan's avatar
jehan committed
480 481
		}
		break;
jehan's avatar
jehan committed
482 483 484
	default: {
		ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
	}
jehan's avatar
jehan committed
485
	/* no break */
jehan's avatar
jehan committed
486 487
	}

488
	if (server_transaction) belle_sip_object_unref(server_transaction);
jehan's avatar
jehan committed
489

jehan's avatar
jehan committed
490 491
}

492

jehan's avatar
jehan committed
493 494 495 496 497 498 499
/*Call API*/
int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){
	if (desc)
		sal_media_description_ref(desc);
	if (op->base.local_media)
		sal_media_description_unref(op->base.local_media);
	op->base.local_media=desc;
500 501 502 503 504 505 506 507 508 509
	
	if (op->base.remote_media){
		/*case of an incoming call where we modify the local capabilities between the time
		 * the call is ringing and it is accepted (for example if you want to accept without video*/
		/*reset the sdp answer so that it is computed again*/
		if (op->sdp_answer){
			belle_sip_object_unref(op->sdp_answer);
			op->sdp_answer=NULL;
		}
	}
jehan's avatar
jehan committed
510 511
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
512 513

static belle_sip_header_allow_t *create_allow(){
jehan's avatar
jehan committed
514
	belle_sip_header_allow_t* header_allow;
Simon Morlat's avatar
Simon Morlat committed
515 516 517 518 519 520
        header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
	return header_allow;
}

static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) {
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow()));
jehan's avatar
jehan committed
521 522 523 524 525 526 527 528 529 530 531

	if (op->base.root->session_expires!=0){
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200"));
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer"));
	}
	if (op->base.local_media){
			op->sdp_offering=TRUE;
			set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media);
	}else op->sdp_offering=FALSE;
	return;
}
Simon Morlat's avatar
Simon Morlat committed
532

jehan's avatar
jehan committed
533
int sal_call(SalOp *op, const char *from, const char *to){
534
	belle_sip_request_t* invite;
jehan's avatar
jehan committed
535
	op->dir=SalOpDirOutgoing;
536

jehan's avatar
jehan committed
537 538 539
	sal_op_set_from(op,from);
	sal_op_set_to(op,to);

540
	ms_message("[%s] calling [%s] on op [%p]", from, to, op);
541
	invite=sal_op_build_request(op,"INVITE");
jehan's avatar
jehan committed
542

543
	sal_op_fill_invite(op,invite);
jehan's avatar
jehan committed
544

jehan's avatar
jehan committed
545
	sal_op_call_fill_cbs(op);
546 547 548
	if (op->replaces){
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->replaces));
	}
549 550 551
	if (op->referred_by)
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->referred_by));
	
jehan's avatar
jehan committed
552
	return sal_op_send_request(op,invite);
jehan's avatar
jehan committed
553
}
Simon Morlat's avatar
Simon Morlat committed
554

jehan's avatar
jehan committed
555 556
void sal_op_call_fill_cbs(SalOp*op) {
	op->callbacks.process_io_error=call_process_io_error;
557
	op->callbacks.process_response_event=call_process_response;
jehan's avatar
jehan committed
558 559 560
	op->callbacks.process_timeout=call_process_timeout;
	op->callbacks.process_transaction_terminated=call_process_transaction_terminated;
	op->callbacks.process_request_event=process_request_event;
jehan's avatar
jehan committed
561
	op->callbacks.process_dialog_terminated=process_dialog_terminated;
562
	op->type=SalOpCall;
jehan's avatar
jehan committed
563
}
Simon Morlat's avatar
Simon Morlat committed
564

jehan's avatar
jehan committed
565 566 567 568 569 570
static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* response) {
	if (op->base.local_media){
		/*this is the case where we received an invite without SDP*/
		if (op->sdp_offering) {
			set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media);
		}else{
571

572
			if (op->sdp_answer==NULL) sdp_process(op);
573

jehan's avatar
jehan committed
574 575
			if (op->sdp_answer){
				set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer);
Simon Morlat's avatar
Simon Morlat committed
576
				belle_sip_object_unref(op->sdp_answer);
jehan's avatar
jehan committed
577 578 579 580 581 582 583
				op->sdp_answer=NULL;
			}
		}
	}else{
		ms_error("You are accepting a call but not defined any media capabilities !");
	}
}
Simon Morlat's avatar
Simon Morlat committed
584

jehan's avatar
jehan committed
585
int sal_call_notify_ringing(SalOp *op, bool_t early_media){
jehan's avatar
jehan committed
586
	int status_code =early_media?183:180;
jehan's avatar
jehan committed
587
	belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans));
588
	belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code);
589 590 591
	belle_sip_header_t *require;
	const char *tags=NULL;
	
jehan's avatar
jehan committed
592
	if (early_media){
jehan's avatar
jehan committed
593
		handle_offer_answer_response(op,ringing_response);
jehan's avatar
jehan committed
594
	}
595 596 597 598
	require=belle_sip_message_get_header((belle_sip_message_t*)req,"Require");
	if (require) tags=belle_sip_header_get_unparsed_value(require);
	/* if client requires 100rel, then add necessary stuff*/
	if (tags && strstr(tags,"100rel")!=0) {
jehan's avatar
jehan committed
599 600
		belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op);
		belle_sip_header_contact_t* contact_header;
601
		belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100rel")));
jehan's avatar
jehan committed
602 603
		belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1")));
		if (contact && (contact_header=belle_sip_header_contact_create(contact))) {
604
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header));
jehan's avatar
jehan committed
605 606
		}
	}
jehan's avatar
jehan committed
607
	belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response);
jehan's avatar
jehan committed
608
	return 0;
jehan's avatar
jehan committed
609
}
jehan's avatar
jehan committed
610 611


jehan's avatar
jehan committed
612 613
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h){
jehan's avatar
jehan committed
614 615 616
	belle_sip_response_t *response;
	belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(h);
	belle_sip_header_contact_t* contact_header;
jehan's avatar
jehan committed
617 618 619 620 621 622

	if (!h->pending_server_trans) {
		ms_error("No transaction to accept for op [%p]",h);
		return -1;
	}

jehan's avatar
jehan committed
623
	/* sends a 200 OK */
624
	response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200);
jehan's avatar
jehan committed
625 626 627 628 629

	if (response==NULL){
		ms_error("Fail to build answer for call");
		return -1;
	}
Simon Morlat's avatar
Simon Morlat committed
630
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow()));
jehan's avatar
jehan committed
631 632 633 634 635 636 637 638 639 640
	if (h->base.root->session_expires!=0){
		if (h->supports_session_timers) {
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Supported", "timer"));
		}
	}

	if (contact && (contact_header=belle_sip_header_contact_create(contact))) {
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header));
	}

jehan's avatar
jehan committed
641 642
	handle_offer_answer_response(h,response);

jehan's avatar
jehan committed
643 644
	belle_sip_server_transaction_send_response(h->pending_server_trans,response);
	return 0;
jehan's avatar
jehan committed
645
}
Simon Morlat's avatar
Simon Morlat committed
646

jehan's avatar
jehan committed
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){
	belle_sip_response_t* response;
	belle_sip_header_contact_t* contact=NULL;
	int status;
	switch(reason) {
	case SalReasonBusy:
		status=486;
		break;
	case SalReasonTemporarilyUnavailable:
		status=480;
		break;
	case SalReasonDoNotDisturb:
		status=600;
		break;
	case SalReasonMedia:
		status=415;
		break;
jehan's avatar
jehan committed
664 665 666
	case SalReasonDeclined:
		status=603;
		break;
jehan's avatar
jehan committed
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
	case SalReasonRedirect:
		if(redirection!=NULL) {
			if (strstr(redirection,"sip:")!=0) status=302;
			status=380;
			contact= belle_sip_header_contact_new();
			belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection));
			break;
		} else {
			ms_error("Cannot redirect to null");
		}
		/* no break */

	default:
		status=500;
		ms_error("Unexpected decline reason [%i]",reason);
		/* no break */
	}
684
	response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status);
jehan's avatar
jehan committed
685 686 687 688
	if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact));
	belle_sip_server_transaction_send_response(op->pending_server_trans,response);
	return 0;

jehan's avatar
jehan committed
689
}
jehan's avatar
jehan committed
690 691
int sal_call_update(SalOp *op, const char *subject){
	belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE");
692 693 694 695 696 697
	if (reinvite){
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject));
		sal_op_fill_invite(op, reinvite);
		return sal_op_send_request(op,reinvite);
	}
	return -1;
jehan's avatar
jehan committed
698
}
699

jehan's avatar
jehan committed
700
SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){
jehan's avatar
jehan committed
701
	return h->base.remote_media;;
jehan's avatar
jehan committed
702
}
jehan's avatar
jehan committed
703

jehan's avatar
jehan committed
704
SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
jehan's avatar
jehan committed
705 706 707 708
	if (h->base.local_media && h->base.remote_media && !h->result){
			sdp_process(h);
	}
	return h->result;
jehan's avatar
jehan committed
709
}
710

jehan's avatar
jehan committed
711
int sal_call_send_dtmf(SalOp *h, char dtmf){
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
	if (h->dialog){
		belle_sip_request_t *req=belle_sip_dialog_create_request(h->dialog,"INFO");
		if (req){
			int bodylen;
			char dtmf_body[128]={0};
			
			snprintf(dtmf_body, sizeof(dtmf_body)-1, "Signal=%c\r\nDuration=250\r\n", dtmf);
			bodylen=strlen(dtmf_body);
			belle_sip_message_set_body((belle_sip_message_t*)req,dtmf_body,bodylen);
			belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_length_create(bodylen));
			belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_type_create("application", "dtmf-relay"));
			sal_op_send_request(h,req);
		}else ms_error("sal_call_send_dtmf(): could not build request");
	}else ms_error("sal_call_send_dtmf(): no dialog");
	return 0;
jehan's avatar
jehan committed
727
}
728

jehan's avatar
jehan committed
729
int sal_call_terminate(SalOp *op){
Simon Morlat's avatar
Simon Morlat committed
730
	belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
jehan's avatar
jehan committed
731 732 733 734
	if (op->state==SalOpStateTerminating || op->state==SalOpStateTerminated) {
		ms_error("Cannot terminate op [%p] in state [%s]",op,sal_op_state_to_string(op->state));
		return -1;
	}
jehan's avatar
jehan committed
735 736 737
	switch(dialog_state) {
		case BELLE_SIP_DIALOG_CONFIRMED: {
			sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
738
			op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
739 740 741 742 743 744
			break;
		}
		case BELLE_SIP_DIALOG_NULL: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
745 746 747 748 749 750 751 752 753 754
			} else if (op->pending_client_trans){
				if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){
					cancelling_invite(op);
				}else{
					/* Case where the CANCEL cannot be sent because no provisional response was received so far.
					 * The Op must be kept for the time of the transaction in case a response is received later.
					 * The state is passed to Terminating to remember to terminate later.
					 */
					op->state=SalOpStateTerminating;
				}
jehan's avatar
jehan committed
755 756 757 758 759 760 761 762 763 764 765
			}
			break;
		}
		case BELLE_SIP_DIALOG_EARLY: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
			} else  {
				cancelling_invite(op);
			}
			break;
jehan's avatar
jehan committed
766 767 768 769 770 771 772
		}
		default: {
			ms_fatal("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
			return -1;
		}
	}
	return 0;
jehan's avatar
jehan committed
773
}
Simon Morlat's avatar
Simon Morlat committed
774

jehan's avatar
jehan committed
775
bool_t sal_call_autoanswer_asked(SalOp *op){
jehan's avatar
jehan committed
776
	return op->auto_answer_asked;
jehan's avatar
jehan committed
777
}
Simon Morlat's avatar
Simon Morlat committed
778

jehan's avatar
jehan committed
779 780 781 782 783 784 785 786 787 788 789 790 791 792
void sal_call_send_vfu_request(SalOp *op){
	char info_body[] =
			"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
			 "<media_control>"
			 "  <vc_primitive>"
			 "    <to_encoder>"
			 "      <picture_fast_update></picture_fast_update>"
			 "    </to_encoder>"
			 "  </vc_primitive>"
			 "</media_control>";
	size_t content_lenth = sizeof(info_body) - 1;
	belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/
	if (dialog_state == BELLE_SIP_DIALOG_CONFIRMED) {
		belle_sip_request_t* info =	belle_sip_dialog_create_request(op->dialog,"INFO");
793 794 795 796 797 798 799 800 801 802
		int error=TRUE;
		if (info) {
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","media_control+xml")));
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_lenth)));
			belle_sip_message_set_body(BELLE_SIP_MESSAGE(info),info_body,content_lenth);
			error=sal_op_send_request(op,info);
		}
		if (error)
			ms_warning("Cannot send vfu request to [%s] ", sal_op_get_to(op));

jehan's avatar
jehan committed
803 804 805 806 807 808
	} else {
		ms_warning("Cannot send vfu request to [%s] because dialog [%p] in wrong state [%s]",sal_op_get_to(op)
																							,op->dialog
																							,belle_sip_dialog_state_to_string(dialog_state));
	}

jehan's avatar
jehan committed
809 810
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
811

jehan's avatar
jehan committed
812 813 814 815
int sal_call_is_offerer(const SalOp *h){
	return h->sdp_offering;
}

816

817 818