sal_op_call.c 29.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

22 23 24 25
static void call_set_released(SalOp* op){
	op->state=SalOpStateTerminated;
	op->base.root->callbacks.call_released(op);
}
jehan's avatar
jehan committed
26 27 28 29
static void call_set_released_and_unref(SalOp* op) {
	call_set_released(op);
	sal_op_unref(op);
}
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
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);
	}
	call_set_released(op);
}
46

jehan's avatar
jehan committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60
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);
61
		h->sdp_answer=(belle_sdp_session_description_t *)belle_sip_object_ref(media_description_to_sdp(h->result));
jehan's avatar
jehan committed
62 63 64 65 66
		/*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;

67 68 69 70 71 72
		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
73

74 75
			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
76 77 78 79 80 81 82 83 84
			}
		}
	}

}
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;
	int length;
Simon Morlat's avatar
Simon Morlat committed
85
	char buff[2048];
jehan's avatar
jehan committed
86 87 88 89

	if (session_desc) {
		content_type = belle_sip_header_content_type_create("application","sdp");
		length = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,0,sizeof(buff));
Simon Morlat's avatar
Simon Morlat committed
90
		if (length>=sizeof(buff)) {
jehan's avatar
jehan committed
91
			ms_error("Buffer too small or sdp too big");
Simon Morlat's avatar
Simon Morlat committed
92
			return -1;
jehan's avatar
jehan committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
		}

		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){
	return set_sdp(msg,media_description_to_sdp(desc));

}
jehan's avatar
jehan committed
108
static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
jehan's avatar
jehan committed
109 110 111 112
	SalOp* op=(SalOp*)user_ctx;
	if (!op->dialog)  {
		/*call terminated very early*/
		op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503);
113
		call_set_released(op);
jehan's avatar
jehan committed
114 115 116
	} else {
		/*dialog will terminated shortly, nothing to do*/
	}
jehan's avatar
jehan committed
117
}
jehan's avatar
jehan committed
118 119
static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
	SalOp* op=(SalOp*)ctx;
120

121
	if (op->dialog && op->dialog==belle_sip_dialog_terminated_get_dialog(event))  {
jehan's avatar
jehan committed
122 123
		belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog);

124 125 126 127 128 129 130 131
		switch(belle_sip_dialog_get_previous_state(op->dialog)) {
		case BELLE_SIP_DIALOG_CONFIRMED:
			if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) {
				/*this is probably a "normal termination from a BYE*/
				op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
				op->state=SalOpStateTerminating;
			}
			break;
jehan's avatar
jehan committed
132 133 134 135 136 137
		case BELLE_SIP_DIALOG_NULL: {
			if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_server_transaction_t)) {
				/*call declined very early, no need to notify call release*/
				break;
			}
		}
138
		default: {
jehan's avatar
jehan committed
139

140 141 142 143 144 145 146 147 148 149
			belle_sip_response_t* response=belle_sip_transaction_get_response(trans);
			int code = belle_sip_response_get_status_code(response);
			if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_client_transaction_t)) {
				switch (code) {
				case 487:
					call_set_released(op);
					break;
				case 401:
				case 407:
					if (op->state!=SalOpStateTerminating) {
jehan's avatar
jehan committed
150
						/*normal termination for challenged dialog */
151 152 153 154 155 156
						break;
					}
				default:
					call_set_error(op,response);
				}
			} else {
jehan's avatar
jehan committed
157
				sal_op_ref(op); /*to make sure op is still there when call released is scheduled*/
158
				belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack)
jehan's avatar
jehan committed
159
											,(belle_sip_callback_t) call_set_released_and_unref
160 161
											, op);
			}
162

163 164
		}
		}
165
		belle_sip_object_unref(op->dialog);
jehan's avatar
jehan committed
166
		op->dialog=NULL;
167 168 169
		sal_op_unref(op);
	} else {
		ms_error("dialog unknown for op ");
jehan's avatar
jehan committed
170
	}
171 172 173 174

	ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_get_dialog(event)
													,op);

jehan's avatar
jehan committed
175
}
jehan's avatar
jehan committed
176 177 178 179 180 181 182 183
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);
	}
}
jehan's avatar
jehan committed
184 185
static void cancelling_invite(SalOp* op ){
	belle_sip_request_t* cancel;
jehan's avatar
jehan committed
186
	ms_message("Cancelling INVITE request from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op));
187
	cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans);
jehan's avatar
jehan committed
188
	sal_op_send_request(op,cancel);
189
	op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
190
}
jehan's avatar
jehan committed
191 192 193 194
static void call_response_event(void *op_base, const belle_sip_response_event_t *event){
	SalOp* op = (SalOp*)op_base;
	belle_sip_request_t* ack;
	belle_sip_dialog_state_t dialog_state;
jehan's avatar
jehan committed
195
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
196
	belle_sip_request_t* req;
jehan's avatar
jehan committed
197 198
	belle_sip_response_t* response=belle_sip_response_event_get_response(event);
	int code = belle_sip_response_get_status_code(response);
199 200


jehan's avatar
jehan committed
201 202 203 204
	if (!client_transaction) {
		ms_warning("Discarding state less response [%i] on op [%p]",code,op);
		return;
	}
205
	req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
206
	set_or_update_dialog(op,belle_sip_response_event_get_dialog(event));
207
	dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
jehan's avatar
jehan committed
208

Simon Morlat's avatar
Simon Morlat committed
209
	switch(dialog_state) {
jehan's avatar
jehan committed
210

211
		case BELLE_SIP_DIALOG_NULL:
jehan's avatar
jehan committed
212
		case BELLE_SIP_DIALOG_EARLY: {
213 214
			if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) {
				if ( op->state == SalOpStateTerminating) {
jehan's avatar
jehan committed
215 216 217 218 219 220 221 222
					if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) {
						if (code <200) {
							cancelling_invite(op);
						} else if (code<400) {
							sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
						} else {
							/*nop ?*/
						}
223
					} else {
jehan's avatar
jehan committed
224
						/*nop, already cancelled*/
225 226
					}
					break;
jehan's avatar
jehan committed
227
				} else if (code >= 180 && code<300) {
228 229 230
					handle_sdp_from_response(op,response);
					op->base.root->callbacks.call_ringing(op);
					break;
jehan's avatar
jehan committed
231 232 233 234 235 236 237
				} else if (code>=300){
					if (dialog_state==BELLE_SIP_DIALOG_NULL) {
						call_set_error(op,response);
						break;
					} else {
					/*nop let process_dialog_terminated manage error reporting*/
					}
238 239 240 241 242
				}

			} else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0
						|| strcmp("BYE",belle_sip_request_get_method(req))==0) {
				break;/*200ok for cancel or BYE*/
jehan's avatar
jehan committed
243
			} else {
244
				/*nop error*/
jehan's avatar
jehan committed
245
			}
246
			ms_error("call op [%p] receive an unexpected answer [%i]",op,code);
jehan's avatar
jehan committed
247 248 249
		}
		case BELLE_SIP_DIALOG_CONFIRMED: {
			switch (op->state) {
jehan's avatar
jehan committed
250 251
			case SalOpStateEarly:/*invite case*/
			case SalOpStateActive: /*re-invite case*/
jehan's avatar
jehan committed
252 253
				if (code >=200
					&& code<300
254
					&& strcmp("INVITE",belle_sip_request_get_method(req))==0) {
jehan's avatar
jehan committed
255 256 257 258 259 260 261 262 263 264 265 266
					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(response),op->sdp_answer);
						op->sdp_answer=NULL;
					}
					belle_sip_dialog_send_ack(op->dialog,ack);
jehan's avatar
jehan committed
267 268
					op->base.root->callbacks.call_accepted(op); /*INVITE*/

jehan's avatar
jehan committed
269
					op->state=SalOpStateActive;
270
				}  else {
jehan's avatar
jehan committed
271
					/*nop*/
jehan's avatar
jehan committed
272
				}
jehan's avatar
jehan committed
273
			break;
274 275
			case SalOpStateTerminating:
				//FIXME send bye
jehan's avatar
jehan committed
276 277
			case SalOpStateTerminated:
			default:
278
				ms_error("call op [%p] receive answer [%i] not implemented",op,code);
jehan's avatar
jehan committed
279 280 281
			}
		break;
		}
282 283 284 285 286 287 288 289 290 291
		case BELLE_SIP_DIALOG_TERMINATED: {
			/*if (code>=400 && strcmp("INVITE",belle_sip_request_get_method(req))==0){
				call_set_error(op,response);
				call_set_released(op);
				op->state=SalOpStateTerminated;
			break;
			}*/
			break;
		}
		/* no break */
jehan's avatar
jehan committed
292
		default: {
293
			ms_error("call op [%p] receive answer [%i] not implemented",op,code);
jehan's avatar
jehan committed
294 295 296 297 298
		}
		/* no break */
	}


jehan's avatar
jehan committed
299
}
300

jehan's avatar
jehan committed
301
static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
302 303 304 305
	SalOp* op=(SalOp*)user_ctx;
	if (!op->dialog)  {
		/*call terminated very early*/
		op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408);
306
		call_set_released(op);
307 308 309 310
		op->state=SalOpStateTerminated;
	} else {
		/*dialog will terminated shortly, nothing to do*/
	}
jehan's avatar
jehan committed
311 312
}
static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
313 314 315 316 317 318 319 320 321 322 323 324
	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));
	}
325 326
	if (op->state ==SalOpStateTerminating &&
			strcmp("BYE",belle_sip_request_get_method(req))==0
327 328
					&& (!resp || (belle_sip_response_get_status_code(resp) !=401
									&& belle_sip_response_get_status_code(resp) !=407))) {
329

330
		call_set_released(op);
331 332
	}

jehan's avatar
jehan committed
333
}
jehan's avatar
jehan committed
334 335 336 337 338
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));
	resp=belle_sip_response_create_from_request(request,status_code);
	belle_sip_server_transaction_send_response(server_transaction,resp);
339

jehan's avatar
jehan committed
340 341 342 343 344 345 346 347 348
	return;
}
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
349 350 351 352 353 354 355 356 357 358
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;
}
jehan's avatar
jehan committed
359 360
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
361
	belle_sip_server_transaction_t* server_transaction=NULL;
jehan's avatar
jehan committed
362
	belle_sdp_session_description_t* sdp;
jehan's avatar
jehan committed
363 364
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_state_t dialog_state;
365
	belle_sip_response_t* resp;
jehan's avatar
jehan committed
366
	belle_sip_header_t* call_info;
jehan's avatar
jehan committed
367

jehan's avatar
jehan committed
368 369 370
	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);
371 372 373 374
		belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op);
		sal_op_ref(op);
	}

375 376 377 378
	if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
		if (op->pending_server_trans)belle_sip_object_unref(op->pending_server_trans);
		/*updating pending invite transaction*/
		op->pending_server_trans=server_transaction;
379
		belle_sip_object_ref(op->pending_server_trans);
380 381
	}

jehan's avatar
jehan committed
382
	if (!op->dialog) {
383
		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
384 385 386 387 388 389
		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: {
390 391 392 393 394 395
		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
396

397
			process_sdp_for_invite(op,req);
jehan's avatar
jehan committed
398

399 400 401 402 403
			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
404 405
			}

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

408 409
			break;
		} /* else same behavior as for EARLY state*/
jehan's avatar
jehan committed
410
	}
jehan's avatar
jehan committed
411 412 413 414 415 416 417
	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
															,belle_sip_response_create_from_request(req,200));
418
				/*terminate invite transaction*/
jehan's avatar
jehan committed
419
				call_terminated(op
420 421
								,op->pending_server_trans
								,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487);
jehan's avatar
jehan committed
422 423 424 425 426 427 428


			} else {
				/*call leg does not exist*/
				belle_sip_server_transaction_send_response(server_transaction
															,belle_sip_response_create_from_request(req,481));
			}
jehan's avatar
jehan committed
429 430 431
		} else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) {
			resp=belle_sip_response_create_from_request(req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
jehan's avatar
jehan committed
432 433
		} else {
			belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY");
434
			unsupported_method(server_transaction,req);
jehan's avatar
jehan committed
435 436 437
		}
		break;
	}
jehan's avatar
jehan committed
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
	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) {
457 458
			resp=belle_sip_response_create_from_request(req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
459 460 461
			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
462 463 464 465 466 467 468 469 470 471 472 473 474
		} 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);
jehan's avatar
jehan committed
475 476 477 478 479 480 481 482 483 484 485
		} else if (strcmp("INFO",belle_sip_request_get_method(req))==0
				&& belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))
				&&	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);

				}
				resp=belle_sip_response_create_from_request(req,200);
				belle_sip_server_transaction_send_response(server_transaction,resp);
486
		}else if (strcmp("REFER",belle_sip_request_get_method(req))==0) {
jehan's avatar
jehan committed
487 488 489
			sal_op_process_refer(op,event);
		} else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
			sal_op_call_process_notify(op,event);
jehan's avatar
jehan committed
490 491 492
		} else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) {
			resp=belle_sip_response_create_from_request(req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
493
		} else{
jehan's avatar
jehan committed
494
			ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog);
495
			unsupported_method(server_transaction,req);
jehan's avatar
jehan committed
496 497
		}
		break;
jehan's avatar
jehan committed
498 499 500
	default: {
		ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
	}
jehan's avatar
jehan committed
501
	/* no break */
jehan's avatar
jehan committed
502 503
	}

504
	if (server_transaction) belle_sip_object_unref(server_transaction);
jehan's avatar
jehan committed
505

jehan's avatar
jehan committed
506 507
}

508

jehan's avatar
jehan committed
509 510 511 512 513 514 515 516 517
/*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;
	return 0;
}
jehan's avatar
jehan committed
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) {
	belle_sip_header_allow_t* header_allow;
	header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(header_allow));

	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;
}
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 549 550 551
	if (op->replaces){
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->replaces));
			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 553
	return sal_op_send_request(op,invite);

554

jehan's avatar
jehan committed
555
}
jehan's avatar
jehan committed
556 557 558 559 560 561
void sal_op_call_fill_cbs(SalOp*op) {
	op->callbacks.process_io_error=call_process_io_error;
	op->callbacks.process_response_event=call_response_event;
	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
}
jehan's avatar
jehan committed
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
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{
			if (op->sdp_answer==NULL) sdp_process(op);
			if (op->sdp_answer){
				set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer);
				op->sdp_answer=NULL;
			}
		}
	}else{
		ms_error("You are accepting a call but not defined any media capabilities !");
	}
}
jehan's avatar
jehan committed
581
int sal_call_notify_ringing(SalOp *op, bool_t early_media){
jehan's avatar
jehan committed
582
	int status_code =early_media?183:180;
jehan's avatar
jehan committed
583 584
	belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans));
	belle_sip_response_t* ringing_response = belle_sip_response_create_from_request(req,status_code);
jehan's avatar
jehan committed
585
	if (early_media){
jehan's avatar
jehan committed
586
		handle_offer_answer_response(op,ringing_response);
jehan's avatar
jehan committed
587
	}
jehan's avatar
jehan committed
588
	/*fixme it should support PRACK in the right way*/
589
	if (belle_sip_message_get_header((belle_sip_message_t*)req,"Require") || belle_sip_message_get_header((belle_sip_message_t*)req,"Supported")) {
jehan's avatar
jehan committed
590 591
		belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op);
		belle_sip_header_contact_t* contact_header;
592
		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
593 594 595 596 597
		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))) {
				belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header));
		}
	}
jehan's avatar
jehan committed
598
	belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response);
jehan's avatar
jehan committed
599
	return 0;
jehan's avatar
jehan committed
600
}
jehan's avatar
jehan committed
601 602


jehan's avatar
jehan committed
603 604
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h){
jehan's avatar
jehan committed
605 606 607
	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
608 609 610 611 612 613

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

jehan's avatar
jehan committed
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
	/* sends a 200 OK */
	response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200);

	if (response==NULL){
		ms_error("Fail to build answer for call");
		return -1;
	}
	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
631 632
	handle_offer_answer_response(h,response);

jehan's avatar
jehan committed
633 634
	belle_sip_server_transaction_send_response(h->pending_server_trans,response);
	return 0;
jehan's avatar
jehan committed
635
}
jehan's avatar
jehan committed
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
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
653 654 655
	case SalReasonDeclined:
		status=603;
		break;
jehan's avatar
jehan committed
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
	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 */
	}
	response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status);
	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
678
}
jehan's avatar
jehan committed
679 680 681 682
int sal_call_update(SalOp *op, const char *subject){
	belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE");
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject));
	sal_op_fill_invite(op, reinvite);
jehan's avatar
jehan committed
683
	return sal_op_send_request(op,reinvite);
jehan's avatar
jehan committed
684 685
}
SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){
jehan's avatar
jehan committed
686
	return h->base.remote_media;;
jehan's avatar
jehan committed
687
}
jehan's avatar
jehan committed
688 689


jehan's avatar
jehan committed
690
SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
jehan's avatar
jehan committed
691 692 693 694
	if (h->base.local_media && h->base.remote_media && !h->result){
			sdp_process(h);
	}
	return h->result;
jehan's avatar
jehan committed
695
}
696

jehan's avatar
jehan committed
697
int sal_call_send_dtmf(SalOp *h, char dtmf){
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
	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
713
}
714

jehan's avatar
jehan committed
715
int sal_call_terminate(SalOp *op){
716
	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*/
jehan's avatar
jehan committed
717 718 719 720
	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
721 722 723
	switch(dialog_state) {
		case BELLE_SIP_DIALOG_CONFIRMED: {
			sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
724
			op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
725 726 727 728 729 730
			break;
		}
		case BELLE_SIP_DIALOG_NULL: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
731 732
			} else if (op->pending_client_trans
					&& belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){
jehan's avatar
jehan committed
733 734 735
				cancelling_invite(op);
				break;
			} else {
736 737 738 739
				/*just schedule call released*/
				belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack)
															,(belle_sip_callback_t) call_set_released
															, op);
jehan's avatar
jehan committed
740 741 742 743 744 745 746 747 748 749 750
			}
			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
751 752 753 754 755 756 757
		}
		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
758 759
}
bool_t sal_call_autoanswer_asked(SalOp *op){
jehan's avatar
jehan committed
760
	return op->auto_answer_asked;
jehan's avatar
jehan committed
761
}
jehan's avatar
jehan committed
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
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");
		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);
		sal_op_send_request(op,info);
	} 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
786 787 788 789 790 791
	return ;
}
int sal_call_is_offerer(const SalOp *h){
	return h->sdp_offering;
}

792

793 794