sal_op_call.c 29.7 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
		for(i=0;i<h->result->n_active_streams;++i){
			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;
79 80
			strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
			h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
jehan's avatar
jehan committed
81

82 83
			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
84 85 86 87 88 89 90 91
			}
		}
	}

}
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
92
	belle_sip_error_code error = BELLE_SIP_OK;
93
	size_t length = 0;
Simon Morlat's avatar
Simon Morlat committed
94
	char buff[2048];
jehan's avatar
jehan committed
95 96 97

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

		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
114 115 116 117 118
	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
119 120

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

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

jehan's avatar
jehan committed
160 161 162 163 164 165 166 167
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
168

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

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


jehan's avatar
jehan committed
187
	if (!client_transaction) {
188
		ms_warning("Discarding stateless response [%i] on op [%p]",code,op);
jehan's avatar
jehan committed
189 190
		return;
	}
191
	req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
192
	set_or_update_dialog(op,belle_sip_response_event_get_dialog(event));
193
	dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
194 195
	
	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
196

Simon Morlat's avatar
Simon Morlat committed
197
	switch(dialog_state) {
198
		case BELLE_SIP_DIALOG_NULL:
jehan's avatar
jehan committed
199
		case BELLE_SIP_DIALOG_EARLY: {
200
			if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) {
201
				if (op->state == SalOpStateTerminating) {
202
					/*check if CANCEL was sent before*/
jehan's avatar
jehan committed
203
					if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) {
204
						/*it wasn't sent */
205
						if (code<200) {
jehan's avatar
jehan committed
206
							cancelling_invite(op);
207 208 209
						}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
210
						}
211
					} else {
212 213 214 215
						/*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);
						}
216
					}
jehan's avatar
jehan committed
217
				} else if (code >= 180 && code<300) {
218 219
					handle_sdp_from_response(op,response);
					op->base.root->callbacks.call_ringing(op);
jehan's avatar
jehan committed
220
				} else if (code>=300){
221 222
					call_set_error(op,response);
					if (op->dialog==NULL) call_set_released(op);
223
				}
224
			}
jehan's avatar
jehan committed
225
		}
226
		break;
jehan's avatar
jehan committed
227 228
		case BELLE_SIP_DIALOG_CONFIRMED: {
			switch (op->state) {
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
				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
252
					}
253 254 255 256 257 258 259
				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
260 261
			}
		}
262
		break;
263
		case BELLE_SIP_DIALOG_TERMINATED: {
264
			if (code >= 300){
265
				call_set_error(op,response);
266
			}
267
		}
268
		break;
jehan's avatar
jehan committed
269
		default: {
270
			ms_error("call op [%p] receive answer [%i] not implemented",op,code);
jehan's avatar
jehan committed
271
		}
272
		break;
jehan's avatar
jehan committed
273
	}
jehan's avatar
jehan committed
274
}
275

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

jehan's avatar
jehan committed
290
static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
291 292 293 294 295 296 297 298 299 300 301 302
	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
303 304 305 306 307
	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);
308
	}
jehan's avatar
jehan committed
309
}
Simon Morlat's avatar
Simon Morlat committed
310

jehan's avatar
jehan committed
311 312 313
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));
314
	resp=sal_op_create_response_from_request(op,request,status_code);
jehan's avatar
jehan committed
315 316
	belle_sip_server_transaction_send_response(server_transaction,resp);
}
Simon Morlat's avatar
Simon Morlat committed
317

jehan's avatar
jehan committed
318 319 320 321 322 323 324
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
325 326 327 328 329 330 331 332 333 334
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;
}
335

jehan's avatar
jehan committed
336 337
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
338
	belle_sip_server_transaction_t* server_transaction=NULL;
jehan's avatar
jehan committed
339
	belle_sdp_session_description_t* sdp;
jehan's avatar
jehan committed
340 341
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_state_t dialog_state;
342
	belle_sip_response_t* resp;
jehan's avatar
jehan committed
343
	belle_sip_header_t* call_info;
jehan's avatar
jehan committed
344

jehan's avatar
jehan committed
345 346 347
	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);
348 349 350 351
		belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op);
		sal_op_ref(op);
	}

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

jehan's avatar
jehan committed
359
	if (!op->dialog) {
360
		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
361 362 363 364 365 366
		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: {
367 368 369 370 371 372
		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
373

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

376 377 378 379 380
			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
381 382
			}

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

385 386
			break;
		} /* else same behavior as for EARLY state*/
jehan's avatar
jehan committed
387
	}
jehan's avatar
jehan committed
388 389 390 391 392 393
	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
394
						,sal_op_create_response_from_request(op,req,200));
395
				/*terminate invite transaction*/
jehan's avatar
jehan committed
396
				call_terminated(op
Simon Morlat's avatar
Simon Morlat committed
397 398
						,op->pending_server_trans
						,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487);
jehan's avatar
jehan committed
399 400 401 402 403


			} else {
				/*call leg does not exist*/
				belle_sip_server_transaction_send_response(server_transaction
404
							,sal_op_create_response_from_request(op,req,481));
jehan's avatar
jehan committed
405
			}
jehan's avatar
jehan committed
406
		} else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) {
407
			resp=sal_op_create_response_from_request(op,req,200);
jehan's avatar
jehan committed
408
			belle_sip_server_transaction_send_response(server_transaction,resp);
jehan's avatar
jehan committed
409
		} else {
410
			belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req));
411
			unsupported_method(server_transaction,req);
jehan's avatar
jehan committed
412 413 414
		}
		break;
	}
jehan's avatar
jehan committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
	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) {
434
			resp=sal_op_create_response_from_request(op,req,200);
435
			belle_sip_server_transaction_send_response(server_transaction,resp);
436 437 438
			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
439 440 441 442 443 444 445 446 447 448 449 450 451
		} 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);
452 453
		} 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
454 455 456 457 458 459 460
				&&	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);

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

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

jehan's avatar
jehan committed
491 492
}

493

jehan's avatar
jehan committed
494 495 496 497 498 499 500
/*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;
501 502 503 504 505 506 507 508 509 510
	
	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
511 512
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
513 514

static belle_sip_header_allow_t *create_allow(){
jehan's avatar
jehan committed
515
	belle_sip_header_allow_t* header_allow;
Simon Morlat's avatar
Simon Morlat committed
516 517 518 519 520 521
        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
522 523 524 525 526 527 528 529 530 531 532

	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
533

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

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

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

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

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

jehan's avatar
jehan committed
556 557
void sal_op_call_fill_cbs(SalOp*op) {
	op->callbacks.process_io_error=call_process_io_error;
558
	op->callbacks.process_response_event=call_process_response;
jehan's avatar
jehan committed
559 560 561
	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
562
	op->callbacks.process_dialog_terminated=process_dialog_terminated;
563
	op->type=SalOpCall;
jehan's avatar
jehan committed
564
}
Simon Morlat's avatar
Simon Morlat committed
565

jehan's avatar
jehan committed
566 567 568 569 570 571
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{
572

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

jehan's avatar
jehan committed
575 576
			if (op->sdp_answer){
				set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer);
Simon Morlat's avatar
Simon Morlat committed
577
				belle_sip_object_unref(op->sdp_answer);
jehan's avatar
jehan committed
578 579 580 581 582 583 584
				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
585

jehan's avatar
jehan committed
586
int sal_call_notify_ringing(SalOp *op, bool_t early_media){
jehan's avatar
jehan committed
587
	int status_code =early_media?183:180;
jehan's avatar
jehan committed
588
	belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans));
589
	belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code);
590 591 592
	belle_sip_header_t *require;
	const char *tags=NULL;
	
jehan's avatar
jehan committed
593
	if (early_media){
jehan's avatar
jehan committed
594
		handle_offer_answer_response(op,ringing_response);
jehan's avatar
jehan committed
595
	}
596 597 598 599
	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
600 601
		belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op);
		belle_sip_header_contact_t* contact_header;
602
		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
603 604
		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))) {
605
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header));
jehan's avatar
jehan committed
606 607
		}
	}
jehan's avatar
jehan committed
608
	belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response);
jehan's avatar
jehan committed
609
	return 0;
jehan's avatar
jehan committed
610
}
jehan's avatar
jehan committed
611 612


jehan's avatar
jehan committed
613 614
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h){
jehan's avatar
jehan committed
615 616
	belle_sip_response_t *response;
	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
	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"));
		}
	}

637
	if ((contact_header=sal_op_create_contact(h))) {
jehan's avatar
jehan committed
638 639 640
		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
int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){
	belle_sip_response_t* response;
	belle_sip_header_contact_t* contact=NULL;
650 651 652 653
	int status=sal_reason_to_sip_code(reason);
	
	if (reason==SalReasonRedirect){
		if (redirection!=NULL) {
jehan's avatar
jehan committed
654 655 656 657 658 659 660 661
			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));
		} else {
			ms_error("Cannot redirect to null");
		}
	}
662
	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
663 664 665
	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
666
}
667

jehan's avatar
jehan committed
668 669
int sal_call_update(SalOp *op, const char *subject){
	belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE");
670 671 672 673 674 675
	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
676
}
677

jehan's avatar
jehan committed
678
SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){
jehan's avatar
jehan committed
679
	return h->base.remote_media;;
jehan's avatar
jehan committed
680
}
jehan's avatar
jehan committed
681

jehan's avatar
jehan committed
682
SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
jehan's avatar
jehan committed
683 684 685 686
	if (h->base.local_media && h->base.remote_media && !h->result){
			sdp_process(h);
	}
	return h->result;
jehan's avatar
jehan committed
687
}
688

jehan's avatar
jehan committed
689
int sal_call_send_dtmf(SalOp *h, char dtmf){
690
	if (h->dialog){
691
		belle_sip_request_t *req=belle_sip_dialog_create_queued_request(h->dialog,"INFO");
692 693 694 695 696 697 698 699 700 701 702 703 704
		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
705
}
706

jehan's avatar
jehan committed
707
int sal_call_terminate(SalOp *op){
Simon Morlat's avatar
Simon Morlat committed
708
	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
709 710 711 712
	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
713 714 715
	switch(dialog_state) {
		case BELLE_SIP_DIALOG_CONFIRMED: {
			sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
716
			op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
717 718 719 720 721 722
			break;
		}
		case BELLE_SIP_DIALOG_NULL: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
723 724 725 726 727 728 729 730 731 732
			} 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
733 734 735 736 737 738 739 740 741 742 743
			}
			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
744 745
		}
		default: {
746
			ms_error("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
jehan's avatar
jehan committed
747 748 749 750
			return -1;
		}
	}
	return 0;
jehan's avatar
jehan committed
751
}
Simon Morlat's avatar
Simon Morlat committed
752

jehan's avatar
jehan committed
753
bool_t sal_call_autoanswer_asked(SalOp *op){
jehan's avatar
jehan committed
754
	return op->auto_answer_asked;
jehan's avatar
jehan committed
755
}
Simon Morlat's avatar
Simon Morlat committed
756

jehan's avatar
jehan committed
757 758 759 760 761 762 763 764 765 766 767 768 769
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) {
770
		belle_sip_request_t* info =	belle_sip_dialog_create_queued_request(op->dialog,"INFO");
771 772 773 774 775 776 777 778 779 780
		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
781 782 783 784 785 786
	} 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
787 788
	return ;
}
Simon Morlat's avatar
Simon Morlat committed
789

jehan's avatar
jehan committed
790 791 792 793
int sal_call_is_offerer(const SalOp *h){
	return h->sdp_offering;
}

794

795 796