Exemple #1
0
static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
	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;
	bool_t release_call=FALSE;

	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));
	}
	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))
			&& op->dialog==NULL) {
		release_call=TRUE;
	}
	if (server_transaction){
		if (op->pending_server_trans==server_transaction){
			belle_sip_object_unref(op->pending_server_trans);
			op->pending_server_trans=NULL;
		}
		if (op->pending_update_server_trans==server_transaction){
			belle_sip_object_unref(op->pending_update_server_trans);
			op->pending_update_server_trans=NULL;
		}
	}
	if (release_call) call_set_released(op);
}
static void client_process_response_event(void *obj, const belle_sip_response_event_t *event){
	//belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	endpoint_t* endpoint = (endpoint_t*)obj;
	int status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
	belle_sip_message("caller_process_response_event [%i]",status);
	switch (status) {
	case 200:
		endpoint->stat.twoHundredOk++;
		if (endpoint->connection_family!=AF_UNSPEC){
			const char *host;
			int family_found;
			belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(
				(belle_sip_message_t*)belle_sip_response_event_get_response(event),belle_sip_header_contact_t);
			CU_ASSERT_PTR_NOT_NULL_FATAL(ct);
			host=belle_sip_uri_get_host(belle_sip_header_address_get_uri((belle_sip_header_address_t*)ct));
			if (strchr(host,':')) family_found=AF_INET6;
			else family_found=AF_INET;
			CU_ASSERT_TRUE(family_found==endpoint->connection_family);
		}
		break;
	case 401:endpoint->stat.fourHundredOne++; break;
	default: break;
	}


}
static void testGenericMessage(void) {
	const char* raw_message = 	"SIP/2.0 180 Ringing\r\n"
			"Via: SIP/2.0/UDP 192.168.1.73:5060;branch=z9hG4bK.hhdJx4~kD;rport\r\n"
			"Record-Route: <sip:91.121.209.194;lr>\r\n"
			"Record-Route: <sip:[email protected]:5060;lr>\r\n"
			"From: <sip:[email protected]>;tag=5DuaoDRru\r\n"
			"To: <sip:[email protected]>;tag=PelIhu0\r\n"
			"Call-ID: e-2Q~fxwNs\r\n"
			"CSeq: 21 INVITE\r\n"
			"user-agent: Linphone/3.6.99 (belle-sip/1.2.4)\r\n"
			"supported: replaces\r\n"
			"supported: outbound\r\n"
			"Content-Length: 0\r\n"
			"\r\n";

	belle_sip_response_t* response;
	belle_sip_message_t* message = belle_sip_message_parse(raw_message);
	char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message));
	belle_sip_object_unref(BELLE_SIP_OBJECT(message));
	message = belle_sip_message_parse(encoded_message);
	response = BELLE_SIP_RESPONSE(message);
	CU_ASSERT_EQUAL(belle_sip_response_get_status_code(response),180);
/*	CU_ASSERT_STRING_EQUAL(belle_sip_response_get_reason_phrase(response),"Unauthorized");
	CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"WWW-Authenticate"));
	check_uri_and_headers(message);*/
	belle_sip_object_unref(message);
	belle_sip_free(encoded_message);
}
static void caller_process_response_event(void *user_ctx, const belle_sip_response_event_t *event){
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_header_from_t* from=belle_sip_message_get_header_by_type(belle_sip_response_event_get_response(event),belle_sip_header_from_t);
	belle_sip_header_cseq_t* invite_cseq=belle_sip_message_get_header_by_type(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)),belle_sip_header_cseq_t);
	belle_sip_request_t* ack;
	belle_sip_dialog_t* dialog;
	int status;
	if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)))) {
		belle_sip_message("Message [%p] not for caller, skipping",belle_sip_response_event_get_response(event));
		return; /*not for the caller*/
	}

	status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
	belle_sip_message("caller_process_response_event [%i]",status);
	if (BC_ASSERT_PTR_NOT_NULL(client_transaction)) {
		dialog = belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(client_transaction));
		if (BC_ASSERT_PTR_NOT_NULL(dialog)) {
			BC_ASSERT_PTR_EQUAL(caller_dialog,dialog);
			if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_NULL) {
				BC_ASSERT_EQUAL(status,100, int, "%d");
			} else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_EARLY){
				BC_ASSERT_EQUAL(status,180, int, "%d");
				/*send 200ok from callee*/
				belle_sip_server_transaction_send_response(inserv_transaction,ok_response);
				belle_sip_object_unref(ok_response);
				ok_response=NULL;
			} else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED) {
static void presence_response_event(void *op_base, const belle_sip_response_event_t *event){
	SalOp* op = (SalOp*)op_base;
	belle_sip_dialog_state_t dialog_state;
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_response_t* response=belle_sip_response_event_get_response(event);
	belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
	int code = belle_sip_response_get_status_code(response);
	char reason[256]={0};
	SalError error=SalErrorUnknown;
	SalReason sr=SalReasonUnknown;
	belle_sip_header_expires_t* expires;

	if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) {
		ms_error("subscription to [%s] rejected reason  [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr));
		op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/
		return;
	}
	set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event));
	if (!op->dialog) {
		ms_message("presence op [%p] receive out of dialog answer [%i]",op,code);
		return;
	}
	dialog_state=belle_sip_dialog_get_state(op->dialog);

	switch(dialog_state) {
		case BELLE_SIP_DIALOG_NULL:
		case BELLE_SIP_DIALOG_EARLY: {
			ms_error("presence op [%p] receive an unexpected answer [%i]",op,code);
			break;
		}
		case BELLE_SIP_DIALOG_CONFIRMED: {
			if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0) {
				expires=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t);
				if(op->refresher) {
					belle_sip_refresher_stop(op->refresher);
					belle_sip_object_unref(op->refresher);
					op->refresher=NULL;
				}
				if (expires>0){
					op->refresher=belle_sip_client_transaction_create_refresher(client_transaction);
					belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op);
				}
			}
			break;
		}
		case BELLE_SIP_DIALOG_TERMINATED:
			if (op->refresher) {
				belle_sip_refresher_stop(op->refresher);
				belle_sip_object_unref(op->refresher);
				op->refresher=NULL;
			}
		break;
		default: {
			ms_error("presence op [%p] receive answer [%i] not implemented",op,code);
		}
		/* no break */
	}


}
static void bad_req_process_response_event(void *user_ctx, const belle_sip_response_event_t *event){
	int *bad_request_response_received=(int*)user_ctx;
	belle_sip_response_t *resp=belle_sip_response_event_get_response(event);
	CU_ASSERT_TRUE(resp && belle_sip_response_get_status_code(resp)==400);
	*bad_request_response_received=1;
	belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack));
}
static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){
	SalOp *op=(SalOp*)userctx;
	int code=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
	SalError err;
	SalReason reason;
	sal_compute_sal_errors_from_code(code,&err,&reason);
	op->base.root->callbacks.on_publish_response(op,err,reason);
}
static void test_sipfrag(void) {
	const char* raw_message = 	"SIP/2.0 100 Trying\r\n";
	belle_sip_response_t* response;
	belle_sip_message_t* message = belle_sip_message_parse(raw_message);
	response = BELLE_SIP_RESPONSE(message);
	CU_ASSERT_EQUAL(belle_sip_response_get_status_code(response),100);
	CU_ASSERT_STRING_EQUAL(belle_sip_response_get_reason_phrase(response),"Trying");
	belle_sip_object_unref(message);
}
static void testMalformedFrom_process_response_cb(void *user_ctx, const belle_sip_response_event_t *event){
	int status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));

	belle_sip_message("testMalformedFrom_process_response_cb [%i]",status);

	(*(int*)user_ctx) += 1; // increment the call counter

	CU_ASSERT( status == 400 );
}
Exemple #10
0
static void notify_last_response(SalOp *op, SalOp *newcall){
	belle_sip_client_transaction_t *tr=newcall->pending_client_trans;
	belle_sip_response_t *resp=NULL;
	if (tr){
		resp=belle_sip_transaction_get_response((belle_sip_transaction_t*)tr);
	}
	if (resp==NULL){
		send_notify_for_refer(op, 100, "Trying");
	}else{
		send_notify_for_refer(op, belle_sip_response_get_status_code(resp), belle_sip_response_get_reason_phrase(resp));
	}
}
Exemple #11
0
void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){
	int code = belle_sip_response_get_status_code(response);
	const char *reason_phrase=belle_sip_response_get_reason_phrase(response);
	/*Remark: the reason header is to be used mainly in SIP requests, thus the use and prototype of this function should be changed.*/
	belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
	belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning");
	SalErrorInfo *ei=&op->error_info;
	const char *warnings;

	warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL;
	if (warnings==NULL) warnings=reason_header ? belle_sip_header_get_unparsed_value(reason_header) : NULL;
	sal_error_info_set(ei,SalReasonUnknown,code,reason_phrase,warnings);
}
static void process_message_response_event(void *user_ctx, const belle_sip_response_event_t *event){
	int status;
	BELLESIP_UNUSED(user_ctx);
	CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_response(event));
	belle_sip_message("process_response_event [%i] [%s]"
					,status=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event))
					,belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event)));

	if (status >= 200){
		is_register_ok=status;
		belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack));
	}
}
Exemple #13
0
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);
	}
}
static void process_response_event(void *op_base, const belle_sip_response_event_t *event){
	SalOp* op = (SalOp*)op_base;
	int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
	SalTextDeliveryStatus status;
	sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event));
	
	if (code>=100 && code <200)
		status=SalTextDeliveryInProgress;
	else if (code>=200 && code <300)
		status=SalTextDeliveryDone;
	else
		status=SalTextDeliveryFailed;
	
	op->base.root->callbacks.text_delivery_update(op,status);
}
Exemple #15
0
void belle_sip_client_transaction_notify_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
	belle_sip_response_event_t event;
	belle_sip_dialog_t *dialog=base->dialog;
	int status_code =  belle_sip_response_get_status_code(resp);
	if (base->last_response)
		belle_sip_object_unref(base->last_response);
	base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp);

	if (dialog){
		if (status_code>=101 && status_code<300
			&& strcmp(method,"INVITE")==0
			&& (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){
			/*make sure this response matches the current dialog, or creates a new one*/
			if (!belle_sip_dialog_match(dialog,(belle_sip_message_t*)resp,FALSE)){
				dialog=belle_sip_provider_find_dialog_from_message(t->base.provider,(belle_sip_message_t*)resp,FALSE);
				if (!dialog){
					dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);/*belle_sip_dialog_new(base);*/
					belle_sip_message("Handling response creating a new dialog !");
				}
			}
		}
	} else if (should_dialog_be_created(t,resp)) {
		dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);
	}

	if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) {
		/* retransmition, just return*/
		belle_sip_message("[%p] is a 200 ok retransmition on dialog [%p], skiping",resp,dialog);
		return;
	}

	event.source=(belle_sip_object_t*)base->provider;
	event.client_transaction=t;
	event.dialog=dialog;
	event.response=(belle_sip_response_t*)resp;
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event);
	/*check that 200Ok for INVITEs have been acknowledged by listener*/
	if (dialog && strcmp(method,"INVITE")==0){
		belle_sip_dialog_check_ack_sent(dialog);
	}
	/*report a server having internal errors for REGISTER to the channel, in order to go to a fallback IP*/
	if (status_code == 500 && strcmp(method,"REGISTER") == 0){
		belle_sip_channel_notify_server_error(base->channel);
	}
}
Exemple #16
0
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) {
		int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t);
		belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED);
		if (t->dialog && (!t->last_response || belle_sip_response_get_status_code(t->last_response)<200)){
			/*inform the dialog if a transaction terminates without final response.*/
			belle_sip_dialog_update(t->dialog,t,!is_client);
		}
		belle_sip_message("%s%s %s transaction [%p] terminated"	,is_client ? "Client":"Server"
									,t->is_internal ? " internal":""
									,belle_sip_request_get_method(belle_sip_transaction_get_request(t))
									,t);
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
		belle_sip_provider_set_transaction_terminated(t->provider,t);
	}
}
Exemple #17
0
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
	belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to");
	belle_sip_dialog_t *dialog=base->dialog;
	int status_code;

	belle_sip_object_ref(resp);
	if (!base->last_response){
		belle_sip_hop_t* hop=belle_sip_response_get_return_hop(resp);
		base->channel=belle_sip_provider_get_channel(base->provider,hop);
		belle_sip_object_unref(hop);
		if (!base->channel){
			belle_sip_error("Transaction [%p]: No channel available for sending response.",t);
			return;
		}
		belle_sip_object_ref(base->channel);
		belle_sip_channel_add_listener(base->channel, BELLE_SIP_CHANNEL_LISTENER(t));
	}
	status_code=belle_sip_response_get_status_code(resp);
	if (status_code!=100){
		if (belle_sip_header_to_get_tag(to)==NULL){
			//add a random to tag
			belle_sip_header_to_set_tag(to,t->to_tag);
		}
		/*12.1 Creation of a Dialog
		   Dialogs are created through the generation of non-failure responses
		   to requests with specific methods.  Within this specification, only
		   2xx and 101-199 responses with a To tag, where the request was
		   INVITE, will establish a dialog.*/
		if (dialog && status_code>100 && status_code<300){
			belle_sip_response_fill_for_dialog(resp,base->request);
		}
	}
	if (BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->send_new_response(t,resp)==0){
		if (base->last_response)
			belle_sip_object_unref(base->last_response);
		base->last_response=resp;
	}
	if (dialog)
		belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),TRUE);
}
Exemple #18
0
/*return TRUE if error code*/
bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) {
	int code = belle_sip_response_get_status_code(response);
	belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
	*sal_err=SalErrorUnknown;
	*sal_reason = SalReasonUnknown;

	if (reason_header){
		snprintf(reason
				,reason_size
				,"%s %s"
				,belle_sip_response_get_reason_phrase(response)
				,belle_sip_header_get_unparsed_value(reason_header));
	} else {
		strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size);
	}
	if (code>=400) {
		sal_compute_sal_errors_from_code(code,sal_err,sal_reason);
		return TRUE;
	} else {
		return FALSE;
	}
}
Exemple #19
0
static void ict_on_response(belle_sip_ict_t *obj, belle_sip_response_t *resp){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	int code=belle_sip_response_get_status_code(resp);
	const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);

	switch (base->state){
		case BELLE_SIP_TRANSACTION_CALLING:
			belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING);
			/* no break*/
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			if (code>=300){
				belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED);
				belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)make_ack(obj,resp));
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
				obj->timer_D=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_D,obj,cfg->T1*64);
				belle_sip_transaction_start_timer(base,obj->timer_D);
			}else if (code>=200){
				obj->timer_M=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_M,obj,cfg->T1*64);
				belle_sip_transaction_start_timer(base,obj->timer_M);
				belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_ACCEPTED);
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
			}else if (code>=100){
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
			}
		break;
		case BELLE_SIP_TRANSACTION_ACCEPTED:
			if (code>=200 && code<300){
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
			}
		break;
		case BELLE_SIP_TRANSACTION_COMPLETED:
			if (code>=300 && obj->ack){
				belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)obj->ack);
			}
		break;
		default:
		break;
	}
}
static void test401ResponseWithoutResponsePhrase(void) {
	const char* raw_message = 	"SIP/2.0 401 \r\n"
								"Call-ID: 577586163\r\n"
								"CSeq: 21 REGISTER\r\n"
								"From: <sip:[email protected]>;tag=1790643209\r\n"
								"Server: Cirpack/v4.42x (gw_sip)\r\n"
								"To: <sip:[email protected]>;tag=00-08075-24212984-22e348d97\r\n"
								"Via: SIP/2.0/UDP 192.168.0.18:5062;received=81.56.113.2;rport=5062;branch=z9hG4bK1939354046\r\n"
								"WWW-Authenticate: Digest realm=\"sip.ovh.net\",\r\n   nonce=\"24212965507cde726e8bc37e04686459\",opaque=\"241b9fb347752f2\",stale=false,algorithm=MD5\r\n"
								"Content-Length: 0\r\n\r\n";
	belle_sip_response_t* response;
	belle_sip_message_t* message = belle_sip_message_parse(raw_message);
	char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message));
	belle_sip_object_unref(BELLE_SIP_OBJECT(message));
	message = belle_sip_message_parse(encoded_message);
	response = BELLE_SIP_RESPONSE(message);
	CU_ASSERT_EQUAL(belle_sip_response_get_status_code(response),401);
	CU_ASSERT_PTR_NULL(belle_sip_response_get_reason_phrase(response));
	CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"WWW-Authenticate"));
	check_uri_and_headers(message);
	belle_sip_object_unref(message);
	belle_sip_free(encoded_message);
}
Exemple #21
0
static void nict_on_response(belle_sip_nict_t *obj, belle_sip_response_t *resp){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	int code=belle_sip_response_get_status_code(resp);
	
	switch(base->state){
		case BELLE_SIP_TRANSACTION_TRYING:
			if (code<200){
				belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING);
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
			}
			else {
				nict_set_completed(obj,resp);
			}
		break;
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			if (code>=200){
				nict_set_completed(obj,resp);
			}
		break;
		default:
		break;
	}
}
Exemple #22
0
void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction){
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
	belle_sip_header_t* header_event=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event");
	belle_sip_header_content_type_t* content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t);
	belle_sip_response_t* resp;

	ms_message("Receiving NOTIFY request on op [%p]",op);
	if (header_event
	&& strncasecmp(belle_sip_header_get_unparsed_value(header_event),"refer",strlen("refer"))==0
	&& content_type
	&& strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0
	&& strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0
	&& body){
		belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body));

		if (sipfrag){
			int code=belle_sip_response_get_status_code(sipfrag);
			SalReferStatus status=SalReferFailed;
			if (code<200){
				status=SalReferTrying;
			}else if (code<300){
				status=SalReferSuccess;
			}else if (code>=400){
				status=SalReferFailed;
			}
			belle_sip_object_unref(sipfrag);
			resp = sal_op_create_response_from_request(op,req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
			op->base.root->callbacks.notify_refer(op,status);
		}
	}else{
		ms_error("Notify without sipfrag, trashing");
		resp = sal_op_create_response_from_request(op,req,501);
		belle_sip_server_transaction_send_response(server_transaction,resp);
	}
}
static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){
	int status;
	belle_sip_request_t* request;
	BELLESIP_UNUSED(user_ctx);
	CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_response(event));
	belle_sip_message("process_response_event [%i] [%s]"
					,status=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event))
					,belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event)));


	if (status==401){
		belle_sip_header_cseq_t* cseq;
		belle_sip_client_transaction_t *t;
		belle_sip_uri_t *dest;
		// CU_ASSERT_NOT_EQUAL_FATAL(number_of_challenge,2);
		CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_client_transaction(event)); /*require transaction mode*/
		dest=belle_sip_client_transaction_get_route(belle_sip_response_event_get_client_transaction(event));
		request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(belle_sip_response_event_get_client_transaction(event)));
		cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ);
		belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
		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);
		CU_ASSERT_TRUE_FATAL(belle_sip_provider_add_authorization(prov,request,belle_sip_response_event_get_response(event),NULL,NULL,auth_domain));

		t=belle_sip_provider_create_client_transaction(prov,request);
		belle_sip_client_transaction_send_request_to(t,dest);
		number_of_challenge++;
		authorized_request=request;
		belle_sip_object_ref(authorized_request);
	}  else {
		CU_ASSERT_EQUAL(status,200);
		is_register_ok=1;
		using_transaction=belle_sip_response_event_get_client_transaction(event)!=NULL;
		belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack));
	}
}
Exemple #24
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);
}
static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_response_t* response = belle_sip_response_event_get_response(event);
	int response_code = belle_sip_response_get_status_code(response);
	if (!client_transaction) {
		ms_warning("Discarding stateless response [%i]",response_code);
		return;
	} else {
		SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
		belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
		belle_sip_header_contact_t* original_contact;
		belle_sip_header_address_t* contact_address=NULL;
		belle_sip_header_via_t* via_header;
		belle_sip_uri_t* contact_uri;
		unsigned int contact_port;
		const char* received;
		int rport;
		bool_t contact_updated=FALSE;
		char* new_contact;

		if (op->state == SalOpStateTerminated) {
			belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code);
			return;
		}
		if (!op->base.remote_ua) {
			sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response));
		}
		if (!op->base.call_id) {
			op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t))));
		}

		sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);
		
		if (op->callbacks.process_response_event) {

			if (op->base.root->nat_helper_enabled) {
				/*Fix contact if needed*/
				via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA);
				received = belle_sip_header_via_get_received(via_header);
				rport = belle_sip_header_via_get_rport(via_header);
				if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) {
					/*update contact with sent values in any cases*/
					contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact)));
					sal_op_set_contact_address(op,(const SalAddress *)contact_address);
					belle_sip_object_unref(contact_address);
				}
				if (sal_op_get_contact(op)){
					if (received!=NULL || rport>0) {
						contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op)));
						contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address));
						if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) {
							/*need to update host*/
							belle_sip_uri_set_host(contact_uri,received);
							contact_updated=TRUE;
						}
						contact_port =  belle_sip_uri_get_port(contact_uri);
						if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) {
							/*need to update port*/
							belle_sip_uri_set_port(contact_uri,rport);
							contact_updated=TRUE;
						}

						/*try to fix transport if needed (very unlikely)*/
						if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) {
							if (!belle_sip_uri_get_transport_param(contact_uri)
									||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) {
								belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header));
								contact_updated=TRUE;
							}
						} else {
							if (belle_sip_uri_get_transport_param(contact_uri)) {
								contact_updated=TRUE;
								belle_sip_uri_set_transport_param(contact_uri,NULL);
							}
						}
						if (contact_updated) {
							char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op)));
							new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address));
							ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op);
							sal_op_set_contact_address(op,(const SalAddress *)contact_address);
							belle_sip_free(new_contact);
							belle_sip_free(old_contact);
						}
						if (contact_address)belle_sip_object_unref(contact_address);
					}
				}
			}
			
			/*handle authorization*/
			switch (response_code) {
				case 200: {
					break;
				}
				case 401:
				case 407:{
					
					/*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/
					if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) {
						/*only bye are completed*/
						belle_sip_message("Op is in state terminating, nothing else to do ");
					} else {
						if (op->pending_auth_transaction){
							belle_sip_object_unref(op->pending_auth_transaction);
							op->pending_auth_transaction=NULL;
						}
						op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
						sal_process_authentication(op);
						return;
					}
				}
			}
			op->callbacks.process_response_event(op,event);
		} else {
			ms_error("Unhandled event response [%p]",event);
		}
	}

}
Exemple #26
0
static void process_response_event(belle_sip_listener_t *user_ctx, const belle_sip_response_event_t *event){
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_response_t* response = belle_sip_response_event_get_response(event);
	belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
	int response_code = belle_sip_response_get_status_code(response);
	belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx;
	belle_sip_header_contact_t *contact;


	if (refresher && (client_transaction !=refresher->transaction))
		return; /*not for me*/

	set_or_update_dialog(refresher,belle_sip_response_event_get_dialog(event));
	/*success case:*/
	if (response_code>=200 && response_code<300){
		refresher->auth_failures=0;
		refresher->number_of_retry=0;
		/*great, success*/
		if (strcmp(belle_sip_request_get_method(request),"PUBLISH")==0) {
			/*search for etag*/
			belle_sip_header_t* etag=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"SIP-ETag");
			if (etag) {
				belle_sip_header_t* sip_if_match = belle_sip_header_create("SIP-If-Match",belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(etag)));
				/*update request for next refresh*/
				belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),"SIP-If-Match");
				belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),sip_if_match);
			} else if (refresher->target_expires > 0){
				belle_sip_warning("Refresher [%p] received 200ok to a publish without etag",refresher);
			}
		}
		/*update expire if needed*/
		set_expires_from_trans(refresher);

		if (refresher->target_expires<=0) {
			belle_sip_refresher_stop(refresher); /*doesn't not make sense to refresh if expire =0;*/
		} else {
			/*remove all contact with expire = 0 from request if any, because no need to refresh them*/
			const belle_sip_list_t * contact_list= belle_sip_message_get_headers(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT);
			belle_sip_list_t *iterator, *head;
			if (contact_list) {
				for (iterator=head=belle_sip_list_copy(contact_list);iterator!=NULL;iterator=iterator->next) {
					belle_sip_header_contact_t *contact_for_expire = (belle_sip_header_contact_t *)(iterator->data);
					if (belle_sip_header_contact_get_expires(contact_for_expire) == 0) {
						belle_sip_message_remove_header_from_ptr(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact_for_expire));
					}
				}
				belle_sip_list_free(head);
			}
		}

		if (refresher->state==started) {
			if (!refresher->first_acknoleged_request)
				belle_sip_object_ref(refresher->first_acknoleged_request = request);
			if (is_contact_address_acurate(refresher,request)) {
				schedule_timer(refresher); /*re-arm timer*/
			} else {
				belle_sip_message("belle_sip_refresher_start(): refresher [%p] is resubmitting request because contact sent was not correct in original request.",refresher);
				belle_sip_refresher_refresh(refresher,refresher->target_expires);
				return;
			}
		}
		else belle_sip_message("Refresher [%p] not scheduling next refresh, because it was stopped",refresher);
	}else{/*special error cases*/
		switch (response_code) {
		case 301:
		case 302:
			contact=belle_sip_message_get_header_by_type(response,belle_sip_header_contact_t);
			if (contact){
				belle_sip_uri_t *uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact));
				if (uri && belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,uri)==0)
					return;
			}
			break;
		case 401:
		case 407:
			refresher->auth_failures++;
			if (refresher->auth_failures>1){
				/*avoid looping with 407 or 401 */
				belle_sip_warning("Authentication is failing constantly, %s",(refresher->target_expires>0)? "will retry later":"giving up.");
				if (refresher->target_expires>0) retry_later(refresher);
				refresher->auth_failures=0; /*reset auth failure*/
				break;
			}
			if (refresher->auth_events) {
				refresher->auth_events=belle_sip_list_free_with_data(refresher->auth_events,(void (*)(void*))belle_sip_auth_event_destroy);
			}
			if (belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,NULL)==0)
				return; /*ok, keep 401 internal*/
			break; /*Else notify user of registration failure*/
		case 403:
			/*In case of 403, we will retry later, just in case*/
			if (refresher->target_expires>0) retry_later(refresher);
			break;
		case 412:
			if (strcmp(belle_sip_request_get_method(request),"PUBLISH")==0) {
				belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),"SIP-If-Match");
				if (refresher->target_expires>0) {
					retry_later_on_io_error(refresher);
					return; /*do not notify this kind of error*/
				}
			} else {
				if (refresher->target_expires>0) retry_later(refresher);
			}
			break;
		case 423:{
			belle_sip_header_extension_t *min_expires=BELLE_SIP_HEADER_EXTENSION(belle_sip_message_get_header((belle_sip_message_t*)response,"Min-Expires"));
			if (min_expires){
				const char *value=belle_sip_header_extension_get_value(min_expires);
				if (value){
					int new_expires=atoi(value);
					if (new_expires>0 && refresher->state==started){
						refresher->target_expires=new_expires;
						belle_sip_refresher_refresh(refresher,refresher->target_expires);
						return;
					}
				}
			}else belle_sip_warning("Receiving 423 but no min-expires header.");
			break;
		}
		case 491: {
			if (refresher->target_expires>0) {
				retry_later_on_io_error(refresher);
				return; /*do not notify this kind of error*/
			}
		}
		case 505:
		case 501:
			/*irrecoverable errors, probably no need to retry later*/
			break;
		
		default:
			/*for all other errors, retry later*/
			if (refresher->target_expires>0) retry_later(refresher);
			break;
		}
	}
	if (refresher->listener) refresher->listener(refresher,refresher->user_data,response_code, belle_sip_response_get_reason_phrase(response));

}
Exemple #27
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;
	}
}
Exemple #28
0
/*
 * return 0 if message should be delivered to the next listener, otherwise, its a retransmision, just keep it
 * */
int belle_sip_dialog_update(belle_sip_dialog_t *obj, belle_sip_transaction_t* transaction, int as_uas){
	int is_retransmition=FALSE;
	int delete_dialog=FALSE;
	belle_sip_request_t *req=belle_sip_transaction_get_request(transaction);
	belle_sip_response_t *resp=belle_sip_transaction_get_response(transaction);
	int code=-1;

	belle_sip_message("Dialog [%p]: now updated by transaction [%p].",obj, transaction);
	
	belle_sip_object_ref(transaction);
	if (obj->last_transaction) belle_sip_object_unref(obj->last_transaction);
	obj->last_transaction=transaction;
	
	if (!as_uas){
		belle_sip_header_privacy_t *privacy_header=belle_sip_message_get_header_by_type(req,belle_sip_header_privacy_t);
		SET_OBJECT_PROPERTY(obj,privacy,privacy_header);
	}
	
	if (!resp)
		return 0;


	/*first update local/remote cseq*/
	if (as_uas) {
		belle_sip_header_cseq_t* cseq=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_cseq_t);
		obj->remote_cseq=belle_sip_header_cseq_get_seq_number(cseq);
	}

	code=belle_sip_response_get_status_code(resp);
	switch (obj->state){
		case BELLE_SIP_DIALOG_NULL:
			/*alway establish a dialog*/
			if (code>100 && code<300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0)) {
				belle_sip_dialog_establish(obj,req,resp);
				if (code<200){
					set_state(obj,BELLE_SIP_DIALOG_EARLY);
					break;
				}/* no break  for code >200 because need to call belle_sip_dialog_establish_full*/
			}/* no break*/
		case BELLE_SIP_DIALOG_EARLY:
			/*don't terminate dialog for UPDATE*/
			if (code>=300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0)) {
				/*12.3 Termination of a Dialog
			   	   Independent of the method, if a request outside of a dialog generates
			   	   a non-2xx final response, any early dialogs created through
			   	   provisional responses to that request are terminated.  The mechanism
			   	   for terminating confirmed dialogs is method specific.*/
					belle_sip_dialog_delete(obj);
					break;
			}
			if (code>=200 && code<300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0))
				belle_sip_dialog_establish_full(obj,req,resp);
			break;
		case BELLE_SIP_DIALOG_CONFIRMED:
			code=belle_sip_response_get_status_code(resp);
			if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){
				if (code>=200 && code<300){
					/*refresh the remote_target*/
					belle_sip_header_contact_t *ct;
					if (as_uas){
						ct=belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t);

					}else{
						set_last_out_invite(obj,req);
						ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t);
					}
					if (ct){
						belle_sip_object_unref(obj->remote_target);
						obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct);
					}
					/*handle possible retransmission of 200Ok */
					if (!as_uas && (is_retransmition=(belle_sip_dialog_handle_200Ok(obj,resp)==0))) {
						return is_retransmition;
					} else {
						obj->needs_ack=TRUE; /*REINVITE case, ack needed by both uas and uac*/
					}
				}else if (code>=300){
					/*final response, ack will be automatically sent by transaction layer*/
					obj->needs_ack=FALSE;
				}
			} else if (strcmp(belle_sip_request_get_method(req),"BYE")==0 && (/*(*/code>=200 /*&& code<300) || code==481 || code==408*/)){
				/*15.1.1 UAC Behavior

				   A BYE request is constructed as would any other request within a
				   dialog, as described in Section 12.

				   Once the BYE is constructed, the UAC core creates a new non-INVITE
				   client transaction, and passes it the BYE request.  The UAC MUST
				   consider the session terminated (and therefore stop sending or
				   listening for media) as soon as the BYE request is passed to the
				   client transaction.  If the response for the BYE is a 481
				   (Call/Transaction Does Not Exist) or a 408 (Request Timeout) or no
				   response at all is received for the BYE (that is, a timeout is
				   returned by the client transaction), the UAC MUST consider the
				   session and the dialog terminated. */
				/*what should we do with other reponse >300 ?? */
				obj->needs_ack=FALSE; /*no longuer need ACK*/
				if (obj->terminate_on_bye) delete_dialog=TRUE;
			}
		break;
		case BELLE_SIP_DIALOG_TERMINATED:
			/*ignore*/
		break;
	}
	if (delete_dialog) belle_sip_dialog_delete(obj);
	else {
		belle_sip_dialog_process_queue(obj);
	}
	return 0;
}
Exemple #29
0
static unsigned int should_dialog_be_created(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
	int status_code = belle_sip_response_get_status_code(resp);
	return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0);
}
Exemple #30
0
static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_response_t* response = belle_sip_response_event_get_response(event);
	int response_code = belle_sip_response_get_status_code(response);

	if (!client_transaction) {
		ms_warning("Discarding stateless response [%i]",response_code);
		return;
	} else {
		SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
		belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
		belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t);

		if (op->state == SalOpStateTerminated) {
			belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code);
			return;
		}
		/*do it all the time, since we can receive provisional responses from a different instance than the final one*/
		sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response));

		if(remote_contact) {
			__sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact)));
		}

		if (!op->base.call_id) {
			op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t))));
		}

		sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);

		if (op->callbacks && op->callbacks->process_response_event) {
			/*handle authorization*/
			switch (response_code) {
				case 200:
					break;
				case 401:
				case 407:
					if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) {
						/*only bye are completed*/
						belle_sip_message("Op is in state terminating, nothing else to do ");
					} else {
						if (op->pending_auth_transaction){
							belle_sip_object_unref(op->pending_auth_transaction);
							op->pending_auth_transaction=NULL;
						}
						if (++op->auth_requests > 2) {
							ms_warning("Auth info cannot be found for op [%s/%s] after 2 attempts, giving up",sal_op_get_from(op)
																												,sal_op_get_to(op));
							op->base.root->callbacks.auth_failure(op,op->auth_info);
							sal_remove_pending_auth(op->base.root,op);
						} else {
							op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
							sal_process_authentication(op);
							return;
						}
					}
					break;
				case 403:
					if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info);
					break;
			}
			if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) {
				/*not an auth request*/
				op->auth_requests=0;
			}
			op->callbacks->process_response_event(op,event);
		} else {
			ms_error("Unhandled event response [%p]",event);
		}
	}
}