Example #1
0
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_queued_request(op->dialog,"INFO");
		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));

	} 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));
	}

	return ;
}
Example #2
0
int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){
	belle_sip_dialog_state_t other_call_dialog_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL;
	belle_sip_dialog_state_t op_dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
	belle_sip_header_replaces_t* replaces;
	belle_sip_header_refer_to_t* refer_to;
	belle_sip_header_referred_by_t* referred_by;
	const char* from_tag;
	const char* to_tag;
	char* escaped_replaces;
	/*first, build refer to*/
	if ((other_call_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) && (other_call_dialog_state!=BELLE_SIP_DIALOG_EARLY)) {
		ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED or BELE_SIP_DIALOG_EARLY",
			belle_sip_dialog_state_to_string(other_call_dialog_state),
			other_call_op);
		return -1;
	}
	if (op_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) {
		ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED",
			belle_sip_dialog_state_to_string(op_dialog_state),
			op);
		return -1;
	}

	refer_to=belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog));
	belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(refer_to));
	/*rfc3891
	 ...
	 4.  User Agent Client Behavior: Sending a Replaces Header
	 
	 A User Agent that wishes to replace a single existing early or
	 confirmed dialog with a new dialog of its own, MAY send the target
	 User Agent an INVITE request containing a Replaces header field.  The
	 User Agent Client (UAC) places the Call-ID, to-tag, and from-tag
	 information for the target dialog in a single Replaces header field
	 and sends the new INVITE to the target.*/
	from_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog);
	to_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog);
	
	replaces=belle_sip_header_replaces_create(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(other_call_op->dialog))
											,from_tag,to_tag);
	escaped_replaces=belle_sip_header_replaces_value_to_escaped_string(replaces);
	belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)),"Replaces",escaped_replaces);
	belle_sip_free(escaped_replaces);
	referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog));
	belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(referred_by));
	return sal_call_refer_to(op,refer_to,referred_by);
}
Example #3
0
static int sal_op_check_dialog_state(SalOp *op) {
	belle_sip_dialog_state_t state=op->dialog?belle_sip_dialog_get_state(op->dialog): BELLE_SIP_DIALOG_NULL;
	if (state != BELLE_SIP_DIALOG_CONFIRMED) {
		ms_warning("Cannot notify presence for op [%p] because dialog in state [%s]",op, belle_sip_dialog_state_to_string(state));
		return -1;
	} else
		return 0;
}
Example #4
0
static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) {
	SalOp* op = (SalOp*)op_base;
	belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_state_t dialog_state;
	belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
	belle_sip_response_t* resp;
	const char *method=belle_sip_request_get_method(req);
	
	belle_sip_object_ref(server_transaction);
	if (op->pending_server_trans)  belle_sip_object_unref(op->pending_server_trans);
	op->pending_server_trans=server_transaction;


	if (!op->dialog) {
		if (strcmp(method,"SUBSCRIBE")==0){
			op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
			belle_sip_dialog_set_application_data(op->dialog,op);
			sal_op_ref(op);
			ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
		}else{ /* this is a NOTIFY */
			ms_message("Receiving out of dialog notify");
			handle_notify(op,req);
			return;
		}
	}
	dialog_state=belle_sip_dialog_get_state(op->dialog);
	switch(dialog_state) {
		case BELLE_SIP_DIALOG_NULL: {
			op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op));
			break;
		}
		case BELLE_SIP_DIALOG_EARLY:
			ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",method,op->dialog);
			break;

		case BELLE_SIP_DIALOG_CONFIRMED:
			if (strcmp("NOTIFY",method)==0) {
				handle_notify(op,req);
			} else if (strcmp("SUBSCRIBE",method)==0) {
				/*either a refresh or an unsubscribe*/
				if (expires && belle_sip_header_expires_get_expires(expires)>0) {
					op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op));
				} else if(expires) {
					ms_message("Unsubscribe received from [%s]",sal_op_get_from(op));
					resp=sal_op_create_response_from_request(op,req,200);
					belle_sip_server_transaction_send_response(server_transaction,resp);
				}
			}
			break;
		default: 
			ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
			break;
	}
}
static void callee_process_request_event(void *user_ctx, const belle_sip_request_event_t *event) {
	belle_sip_dialog_t* dialog;
	belle_sip_response_t* ringing_response;
	belle_sip_header_content_type_t* content_type ;
	belle_sip_header_content_length_t* content_length;
	belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event);
	belle_sip_header_to_t* to=belle_sip_message_get_header_by_type(belle_sip_request_event_get_request(event),belle_sip_header_to_t);
	const char* method;
	if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)))) {
		belle_sip_message("Message [%p] not for callee, skipping",belle_sip_request_event_get_request(event));
		return; /*not for the callee*/
	}
	method = belle_sip_request_get_method(belle_sip_request_event_get_request(event));
	if (!server_transaction && strcmp(method,"ACK")!=0) {
		server_transaction= belle_sip_provider_create_server_transaction(prov,belle_sip_request_event_get_request(event));
	}

	belle_sip_message("callee_process_request_event received [%s] message",method);
	dialog = belle_sip_request_event_get_dialog(event);
	if (!dialog ) {
		BC_ASSERT_STRING_EQUAL_FATAL("INVITE",method);
		dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(server_transaction));
		callee_dialog=dialog;
		inserv_transaction=server_transaction;
	}
	if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_NULL) {
		ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),180);
		/*prepare 200ok*/
		ok_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),200);
		content_length= belle_sip_header_content_length_create(strlen(sdp));
		content_type = belle_sip_header_content_type_create("application","sdp");
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_type));
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_length));
		belle_sip_message_set_body(BELLE_SIP_MESSAGE(ok_response),sdp,strlen(sdp));
		belle_sip_object_ref(ok_response);
		/*only send ringing*/
		belle_sip_server_transaction_send_response(server_transaction,ringing_response);
	} else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED) {
		/*time to send bye*/
		belle_sip_client_transaction_t* client_transaction = belle_sip_provider_create_client_transaction(prov,belle_sip_dialog_create_request(dialog,"BYE"));
		belle_sip_client_transaction_send_request(client_transaction);
	} else {
		belle_sip_warning("Unexpected state [%s] for dialog [%p]",belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog)),dialog );
	}

}
Example #6
0
int sal_call_terminate(SalOp *op){
	belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
	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;
	}
	switch(dialog_state) {
		case BELLE_SIP_DIALOG_CONFIRMED: {
			sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
			op->state=SalOpStateTerminating;
			break;
		}
		case BELLE_SIP_DIALOG_NULL: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
			} 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;
				}
			}
			break;
		}
		case BELLE_SIP_DIALOG_EARLY: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
			} else  {
				cancelling_invite(op);
			}
			break;
		}
		default: {
			ms_error("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
			return -1;
		}
	}
	return 0;
}
Example #7
0
int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){
	belle_sip_request_t *update;
	belle_sip_dialog_state_t state=belle_sip_dialog_get_state(op->dialog);
	/*check for dialog state*/
	if ( state == BELLE_SIP_DIALOG_CONFIRMED) {
		if (no_user_consent)
			update=belle_sip_dialog_create_request(op->dialog,"UPDATE");
		else
			update=belle_sip_dialog_create_request(op->dialog,"INVITE");
	} else if (state == BELLE_SIP_DIALOG_EARLY)  {
		update=belle_sip_dialog_create_request(op->dialog,"UPDATE");
	} else {
		ms_error("Cannot update op [%p] with dialog [%p] in state [%s]",op, op->dialog,belle_sip_dialog_state_to_string(state));
		return  -1;
	}
	if (update){
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(update),belle_sip_header_create( "Subject", subject));
		sal_op_fill_invite(op, update);
		return sal_op_send_request(op,update);
	}
	return -1;
}
Example #8
0
int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){
	belle_sip_dialog_state_t other_call_dialog_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL;
	belle_sip_dialog_state_t op_dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
	belle_sip_header_replaces_t* replaces;
	belle_sip_header_refer_to_t* refer_to;
	belle_sip_header_referred_by_t* referred_by;
	const char* from_tag;
	const char* to_tag;
	char* escaped_replaces;
	/*first, build refer to*/
	if (other_call_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) {
		ms_error(" wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED",belle_sip_dialog_state_to_string(other_call_dialog_state)
																							,other_call_op);
		return -1;
	}
	if (op_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) {
		ms_error(" wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED",belle_sip_dialog_state_to_string(op_dialog_state)
																							,op);
		return -1;
	}

	refer_to=belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog));
	belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(refer_to));
	if (belle_sip_dialog_is_server(other_call_op->dialog)) {
		to_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog);
		from_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog);;

	} else {
		from_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog);
		to_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog);;
	}
	replaces=belle_sip_header_replaces_create(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(other_call_op->dialog))
											,from_tag,to_tag);
	escaped_replaces=belle_sip_header_replaces_value_to_escaped_string(replaces);
	belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)),"Replaces",escaped_replaces);
	belle_sip_free(escaped_replaces);
	referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog));
	belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(referred_by));
	return sal_call_refer_to(op,refer_to,referred_by);
}
Example #9
0
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
	SalOp* op = (SalOp*)op_base;
	belle_sip_server_transaction_t* server_transaction=NULL;
	belle_sdp_session_description_t* sdp;
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_state_t dialog_state;
	belle_sip_response_t* resp;
	belle_sip_header_t* call_info;
	const char *method=belle_sip_request_get_method(req);
	bool_t is_update=FALSE;

	if (strcmp("ACK",method)!=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);
		belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),sal_op_ref(op));
	}

	if (strcmp("INVITE",method)==0) {
		if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
		/*updating pending invite transaction*/
		op->pending_server_trans=server_transaction;
		belle_sip_object_ref(op->pending_server_trans);
	}

	if (strcmp("UPDATE",method)==0) {
		if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans);
		/*updating pending update transaction*/
		op->pending_update_server_trans=server_transaction;
		belle_sip_object_ref(op->pending_update_server_trans);
	}

	if (!op->dialog) {
		set_or_update_dialog(op,belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)));
		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: {
		if (strcmp("INVITE",method)==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");
			}

			if (process_sdp_for_invite(op,req) == 0) {
				if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) {
					if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) {
						op->auto_answer_asked=TRUE;
						ms_message("The caller asked to automatically answer the call(Emergency?)\n");
					}
				}
				op->base.root->callbacks.call_received(op);
			}
			break;
		} /* else same behavior as for EARLY state*/
	}
	case BELLE_SIP_DIALOG_EARLY: {
		//hmm probably a cancel
		if (strcmp("CANCEL",method)==0) {
			if(belle_sip_request_event_get_server_transaction(event)) {
				/*first answer 200 ok to cancel*/
				belle_sip_server_transaction_send_response(server_transaction
						,sal_op_create_response_from_request(op,req,200));
				/*terminate invite transaction*/
				call_terminated(op
						,op->pending_server_trans
						,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487);


			} else {
				/*call leg does not exist*/
				belle_sip_server_transaction_send_response(server_transaction
							,sal_op_create_response_from_request(op,req,481));
			}
		} else if (strcmp("PRACK",method)==0) {
			resp=sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
		} else if (strcmp("UPDATE",method)==0) {
			sal_op_reset_descriptions(op);
			if (process_sdp_for_invite(op,req)==0)
				op->base.root->callbacks.call_updating(op,TRUE);
		} else {
			belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req));
			unsupported_method(server_transaction,req);
		}
		break;
	}
	case BELLE_SIP_DIALOG_CONFIRMED:
		/*great ACK received*/
		if (strcmp("ACK",method)==0) {
			if (op->sdp_offering){
				SalReason reason;
				if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){
					if (sdp){
						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);
					}else{
						ms_warning("SDP expected in ACK but not found.");
					}
				}
			}
			op->base.root->callbacks.call_ack(op);
		} else if(strcmp("BYE",method)==0) {
			resp=sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
			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*/
		} else if(strcmp("INVITE",method)==0 || (is_update=(strcmp("UPDATE",method)==0)) ) {
			if (is_update && !belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))) {
				/*session timer case*/
				/*session expire should be handled. to be done when real session timer (rfc4028) will be implemented*/
				resp=sal_op_create_response_from_request(op,req,200);
				belle_sip_server_transaction_send_response(server_transaction,resp);
				belle_sip_object_unref(op->pending_update_server_trans);
				op->pending_update_server_trans=NULL;
			} else {
				/*re-invite*/
				sal_op_reset_descriptions(op);
				if (process_sdp_for_invite(op,req)==0)
					op->base.root->callbacks.call_updating(op,is_update);
			}
		} else if (strcmp("INFO",method)==0){
			if (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);

				}
			}else{
				SalBody salbody;
				if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) {
					if (sal_body_has_type(&salbody,"application","dtmf-relay")){
						char tmp[10];
						if (sal_lines_get_value(salbody.data, "Signal",tmp, sizeof(tmp))){
							op->base.root->callbacks.dtmf_received(op,tmp[0]);
						}
					}else
						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);
		}else if (strcmp("REFER",method)==0) {
			sal_op_process_refer(op,event,server_transaction);
		} else if (strcmp("NOTIFY",method)==0) {
			sal_op_call_process_notify(op,event,server_transaction);
		} else if (strcmp("OPTIONS",method)==0) {
			resp=sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
		} else if (strcmp("CANCEL",method)==0) {
			/*call leg does not exist because 200ok already sent*/
			belle_sip_server_transaction_send_response(server_transaction,sal_op_create_response_from_request(op,req,481));
		} else if (strcmp("MESSAGE",method)==0){
			sal_process_incoming_message(op,event);
		}else{
			ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog);
			unsupported_method(server_transaction,req);
		}
		break;
	default:
		ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
		break;
	}

	if (server_transaction) belle_sip_object_unref(server_transaction);

}
Example #10
0
static void call_process_response(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;
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_request_t* req;
	belle_sip_response_t* response=belle_sip_response_event_get_response(event);
	int code = belle_sip_response_get_status_code(response);
	belle_sip_header_content_type_t *header_content_type=NULL;
	belle_sip_dialog_t *dialog=belle_sip_response_event_get_dialog(event);
	const char *method;

	if (!client_transaction) {
		ms_warning("Discarding stateless response [%i] on op [%p]",code,op);
		return;
	}
	req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
	set_or_update_dialog(op,dialog);
	dialog_state=dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL;
	method=belle_sip_request_get_method(req);
	ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,dialog,belle_sip_dialog_state_to_string(dialog_state));
	/*to make sure no cb will destroy op*/
	sal_op_ref(op);
	switch(dialog_state) {
		case BELLE_SIP_DIALOG_NULL:
		case BELLE_SIP_DIALOG_EARLY: {
			if (strcmp("INVITE",method)==0 ) {
				if (op->state == SalOpStateTerminating) {
					/*check if CANCEL was sent before*/
					if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) {
						/*it wasn't sent */
						if (code<200) {
							cancelling_invite(op);
						}else{
							/* no need to send the INVITE because the UAS rejected the INVITE*/
							if (op->dialog==NULL) call_set_released(op);
						}
					} else {
						/*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);
						}
					}
				} else if (code >= 180 && code<200) {
					belle_sip_response_t *prev_response=belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response");
					if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){
						handle_sdp_from_response(op,response);
						op->base.root->callbacks.call_ringing(op);
					}
					belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref);
				} else if (code>=300){
					call_set_error(op,response);
					if (op->dialog==NULL) call_set_released(op);
				}
			} else if (code >=200
						&& code<300
						&& strcmp("UPDATE",belle_sip_request_get_method(req))==0) {
					handle_sdp_from_response(op,response);
					op->base.root->callbacks.call_accepted(op);
			}
		}
		break;
		case BELLE_SIP_DIALOG_CONFIRMED: {
			switch (op->state) {
				case SalOpStateEarly:/*invite case*/
				case SalOpStateActive: /*re-invite, INFO, UPDATE case*/
					if (strcmp("INVITE",method)==0){
						if (code >=200 && code<300) {
							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){
							call_set_error(op,response);
						}
					}else if (strcmp("INFO",method)==0){
						if (code == 491
							&& (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t))
							&& strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0
							&& strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) {
						unsigned int retry_in =1000*((float)rand()/RAND_MAX);
						belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry");
						ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in);
						belle_sip_object_unref(s);
						}else {
								/*ignoring*/
						}
					}else if (strcmp("UPDATE",method)==0){
						op->base.root->callbacks.call_accepted(op); /*INVITE*/
					}
				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));
			}
		}
		break;
		case BELLE_SIP_DIALOG_TERMINATED: {
			if (code >= 300){
				call_set_error(op,response);
			}
		}
		break;
		default: {
			ms_error("call op [%p] receive answer [%i] not implemented",op,code);
		}
		break;
	}
	sal_op_unref(op);
}
Example #11
0
static int belle_sip_refresher_refresh_internal(belle_sip_refresher_t* refresher, int expires, int auth_mandatory, belle_sip_list_t** auth_infos, belle_sip_uri_t *requri) {
	belle_sip_request_t*old_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(refresher->transaction));
	belle_sip_response_t*old_response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(refresher->transaction));
	belle_sip_dialog_t* dialog = refresher->dialog;
	belle_sip_client_transaction_t* client_transaction;
	belle_sip_request_t* request;
	belle_sip_header_expires_t* expires_header;
	belle_sip_uri_t* preset_route=refresher->transaction->preset_route;
	belle_sip_provider_t* prov=refresher->transaction->base.provider;
	belle_sip_header_contact_t* contact;

	/*first remove timer if any*/
	if (expires >=0) {
		refresher->target_expires=expires;
	} else {
		/*-1 keep last value*/
	}

	if (!dialog) {
		const belle_sip_transaction_state_t state=belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction));
		/*create new request*/
		if (belle_sip_transaction_state_is_transient(state)) {
			/*operation pending, cannot update authorization headers*/
			belle_sip_header_cseq_t* cseq;
			belle_sip_message("Refresher [%p] already has transaction [%p] in state [%s]"	,refresher
				,refresher->transaction
				,belle_sip_transaction_state_to_string(state));
			
			if (strcmp(belle_sip_request_get_method(old_request),"PUBLISH")==0) {
				belle_sip_message("Refresher [%p] new publish is delayed to end of ongoing transaction"	,refresher);
				refresher->publish_pending = TRUE;
				return 0;
			} else {
				request=belle_sip_request_clone_with_body(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(refresher->transaction)));
				cseq=belle_sip_message_get_header_by_type(request,belle_sip_header_cseq_t);
				belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
			}
		} else {
			request=belle_sip_client_transaction_create_authenticated_request(refresher->transaction,auth_infos,refresher->realm);
		}
		if (requri){
			/*case where we are redirected*/
			belle_sip_request_set_uri(request,requri);
			/*remove auth headers, they are not valid for new destination*/
			belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION);
			belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION);
		}
	} else  {
		switch (belle_sip_dialog_get_state(dialog)) {
			case BELLE_SIP_DIALOG_CONFIRMED: {
				if (belle_sip_dialog_request_pending(dialog)){
					belle_sip_message("Cannot refresh now, there is a pending request in the dialog.");
					return -1;
				}
				request=belle_sip_dialog_create_request_from(dialog,old_request);
				if (strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0) {
					belle_sip_header_content_type_t *content_type;
					/*put expire header*/
					if (!(expires_header = belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t))) {
						expires_header = belle_sip_header_expires_new();
						belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header));
					}
					if ((content_type = belle_sip_message_get_header_by_type(request, belle_sip_header_content_type_t))
						&& strcasecmp("application", belle_sip_header_content_type_get_type(content_type)) == 0
						&& strcasecmp("resource-lists+xml", belle_sip_header_content_type_get_subtype(content_type)) == 0) {
						/*rfc5367
						 3.2.  Subsequent SUBSCRIBE Requests
						 ...
						 At this point, there are no semantics associated with resource-list
						 bodies in subsequent SUBSCRIBE requests (although future extensions
						 can define them).  Therefore, UACs SHOULD NOT include resource-list
						 bodies in subsequent SUBSCRIBE requests to a resource list server.
						 */
						belle_sip_message("Removing body, content type and content length for refresher [%p]",refresher);
						belle_sip_message_set_body(BELLE_SIP_MESSAGE(request), NULL, 0);
						belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTENT_TYPE);
						belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTENT_LENGTH);
						
					}
				}
				belle_sip_provider_add_authorization(prov,request,old_response,NULL,auth_infos,refresher->realm);
				break;
			}
			case BELLE_SIP_DIALOG_TERMINATED: {
				if (refresher->first_acknoleged_request) {
					char tmp[11];
					belle_sip_message("Dialog [%p] is in state terminated, recreating a new one for refresher [%p]",dialog,refresher);
					request = refresher->first_acknoleged_request;
					belle_sip_header_cseq_set_seq_number(belle_sip_message_get_header_by_type(request,belle_sip_header_cseq_t)
														 ,20);
					belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(belle_sip_message_get_header_by_type(request,belle_sip_header_to_t)),"tag");
					
					belle_sip_header_call_id_set_call_id(	  belle_sip_message_get_header_by_type(request,belle_sip_header_call_id_t)
															, belle_sip_random_token(tmp,sizeof(tmp)));
					break;
				} /*else nop, error case*/
				
			}
			default: {
				belle_sip_error("Unexpected dialog state [%s] for dialog [%p], cannot refresh [%s]"
								,belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog))
								,dialog
								,belle_sip_request_get_method(old_request));
				return -1;
			}
		}
	}

	if (auth_mandatory && auth_infos && belle_sip_list_find_custom(*auth_infos, unfilled_auth_info, NULL)) {
		belle_sip_message("Auth info not found for this refresh operation on [%p]",refresher);
		if (request) belle_sip_object_unref(request);
		return -1;
	}

	refresher->on_io_error=0; /*reset this flag*/

	/*update expires in any cases*/
	expires_header = belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t);
	if (expires_header)
		belle_sip_header_expires_set_expires(expires_header,refresher->target_expires);
	contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t);
	if (contact && belle_sip_header_contact_get_expires(contact)>=0)
		belle_sip_header_contact_set_expires(contact,refresher->target_expires);

	/*update the Date header if it exists*/
	{
		belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(request,belle_sip_header_date_t);
		if (date){
			time_t curtime=time(NULL);
			belle_sip_header_date_set_time(date,&curtime);
		}
	}

	client_transaction = belle_sip_provider_create_client_transaction(prov,request);
	client_transaction->base.is_internal=1;
	belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),refresher);
	
	if (request ==  refresher->first_acknoleged_request) { /*request is now ref by transaction so no need to keepo it*/
		belle_sip_object_unref(refresher->first_acknoleged_request);
		refresher->first_acknoleged_request = NULL;
	}
	
	switch (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction))) {
	case BELLE_SIP_TRANSACTION_INIT:
	case BELLE_SIP_TRANSACTION_CALLING:
	case BELLE_SIP_TRANSACTION_TRYING:
		/*very early state, we can assume nobody will answer, stop retransmiting*/
		belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(refresher->transaction));
		break;
	default: /*we preserve the transaction "as is"*/
		break;
	}
	/*update reference transaction for next refresh*/
	belle_sip_object_unref(refresher->transaction);
	refresher->transaction=client_transaction;
	belle_sip_object_ref(refresher->transaction);

	if (belle_sip_client_transaction_send_request_to(client_transaction,requri?requri:preset_route)) { /*send imediatly to requri in case of redirect*/
		belle_sip_error("Cannot send refresh method [%s] for refresher [%p]"
				,belle_sip_request_get_method(request)
				,refresher);
		return -1;
	}
	if (expires==0) belle_sip_refresher_stop_internal(refresher,0); /*unregister transaction must be preserved*/
	return 0;
}
Example #12
0
belle_sip_request_t *belle_sip_dialog_create_request(belle_sip_dialog_t *obj, const char *method){
	belle_sip_request_t *req;

	if (obj->state != BELLE_SIP_DIALOG_CONFIRMED && obj->state != BELLE_SIP_DIALOG_EARLY) {
		belle_sip_error("belle_sip_dialog_create_request(): cannot create [%s] request from dialog [%p] in state [%s]",method,obj,belle_sip_dialog_state_to_string(obj->state));
		return NULL;
	}
	/*don't prevent to send a BYE in any case */
	if (strcmp(method,"BYE")!=0 && obj->last_transaction && belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state(obj->last_transaction))){

		if (obj->state != BELLE_SIP_DIALOG_EARLY && strcmp(method,"UPDATE")!=0) {
			belle_sip_error("belle_sip_dialog_create_request(): cannot create [%s] request from dialog [%p] while pending [%s] transaction in state [%s]",method,obj,belle_sip_transaction_get_method(obj->last_transaction), belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(obj->last_transaction)));
			return NULL;
		} /*else UPDATE transaction can be send in // */
	}
	belle_sip_dialog_update_local_cseq(obj,method);
	
	req=create_request(obj,method,TRUE);
	return req;
}
Example #13
0
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
	SalOp* op = (SalOp*)op_base;
	belle_sip_server_transaction_t* server_transaction=NULL;
	belle_sdp_session_description_t* sdp;
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_state_t dialog_state;
	belle_sip_response_t* resp;
	belle_sip_header_t* call_info;

	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);
		belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op);
		sal_op_ref(op);
	}

	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;
		belle_sip_object_ref(op->pending_server_trans);
	}

	if (!op->dialog) {
		set_or_update_dialog(op,belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)));
		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: {
		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");
			}

			process_sdp_for_invite(op,req);

			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");
				}
			}

			op->base.root->callbacks.call_received(op);

			break;
		} /* else same behavior as for EARLY state*/
	}
	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
						,sal_op_create_response_from_request(op,req,200));
				/*terminate invite transaction*/
				call_terminated(op
						,op->pending_server_trans
						,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487);


			} else {
				/*call leg does not exist*/
				belle_sip_server_transaction_send_response(server_transaction
							,sal_op_create_response_from_request(op,req,481));
			}
		} else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) {
			resp=sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
		} else {
			belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req));
			unsupported_method(server_transaction,req);
		}
		break;
	}
	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) {
			resp=sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
			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*/
		} 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);
		} else if (strcmp("INFO",belle_sip_request_get_method(req))==0){
			if (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);

				}
			}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);
		}else if (strcmp("REFER",belle_sip_request_get_method(req))==0) {
			sal_op_process_refer(op,event,server_transaction);
		} else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
			sal_op_call_process_notify(op,event,server_transaction);
		} else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) {
			resp=sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
		} else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) {
			/*call leg does not exist because 200ok already sent*/
			belle_sip_server_transaction_send_response(	server_transaction
														,sal_op_create_response_from_request(op,req,481));

		} else{
			ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog);
			unsupported_method(server_transaction,req);
		}
		break;
	default: {
		ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
	}
	/* no break */
	}

	if (server_transaction) belle_sip_object_unref(server_transaction);

}
Example #14
0
static void call_process_response(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;
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_request_t* req;
	belle_sip_response_t* response=belle_sip_response_event_get_response(event);
	int code = belle_sip_response_get_status_code(response);


	if (!client_transaction) {
		ms_warning("Discarding stateless response [%i] on op [%p]",code,op);
		return;
	}
	req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
	set_or_update_dialog(op,belle_sip_response_event_get_dialog(event));
	dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
	
	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));

	switch(dialog_state) {
		case BELLE_SIP_DIALOG_NULL:
		case BELLE_SIP_DIALOG_EARLY: {
			if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) {
				if (op->state == SalOpStateTerminating) {
					/*check if CANCEL was sent before*/
					if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) {
						/*it wasn't sent */
						if (code<200) {
							cancelling_invite(op);
						}else{
							/* no need to send the INVITE because the UAS rejected the INVITE*/
							if (op->dialog==NULL) call_set_released(op);
						}
					} else {
						/*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);
						}
					}
				} else if (code >= 180 && code<300) {
					handle_sdp_from_response(op,response);
					op->base.root->callbacks.call_ringing(op);
				} else if (code>=300){
					call_set_error(op,response);
					if (op->dialog==NULL) call_set_released(op);
				}
			}
		}
		break;
		case BELLE_SIP_DIALOG_CONFIRMED: {
			switch (op->state) {
				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*/
					}
				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));
			}
		}
		break;
		case BELLE_SIP_DIALOG_TERMINATED: {
			if (code >= 300){
				call_set_error(op,response);
			}
		}
		break;
		default: {
			ms_error("call op [%p] receive answer [%i] not implemented",op,code);
		}
		break;
	}
}