Beispiel #1
0
/*
 * return 0 if dialog handle the 200ok
 * */
static int belle_sip_dialog_handle_200Ok(belle_sip_dialog_t *obj, belle_sip_response_t *msg){
	if (obj->last_out_ack){
		belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(msg,belle_sip_header_cseq_t);
		if (cseq){
			belle_sip_header_cseq_t *ack_cseq=belle_sip_message_get_header_by_type(obj->last_out_ack,belle_sip_header_cseq_t);
			if (belle_sip_header_cseq_get_seq_number(cseq)==belle_sip_header_cseq_get_seq_number(ack_cseq)){
				/*pass for retransmission*/
				belle_sip_message("Dialog retransmitting last ack automatically");
				belle_sip_provider_send_request(obj->provider,obj->last_out_ack);
				return 0;
			}else belle_sip_message("No already created ACK matching 200Ok for dialog [%p]",obj);
		}
	}
	return -1;
}
void unregister_user(belle_sip_stack_t * stack
					,belle_sip_provider_t *prov
					,belle_sip_request_t* initial_request
					,int use_transaction) {
	belle_sip_request_t *req;
	belle_sip_header_cseq_t* cseq;
	belle_sip_header_expires_t* expires_header;
	int i;
	belle_sip_provider_add_sip_listener(prov,l);
	is_register_ok=0;
	using_transaction=0;
	req=(belle_sip_request_t*)belle_sip_object_clone((belle_sip_object_t*)initial_request);
	cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header((belle_sip_message_t*)req,BELLE_SIP_CSEQ);
	belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+2); /*+2 if initial reg was challenged*/
	expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_EXPIRES);
	belle_sip_header_expires_set_expires(expires_header,0);
	if (use_transaction){
		belle_sip_client_transaction_t *t;
		belle_sip_provider_add_authorization(prov,req,NULL,NULL,NULL,NULL); /*just in case*/
		t=belle_sip_provider_create_client_transaction(prov,req);
		belle_sip_client_transaction_send_request(t);
	}else belle_sip_provider_send_request(prov,req);
	for(i=0;!is_register_ok && i<2 ;i++)
		belle_sip_stack_sleep(stack,5000);
	CU_ASSERT_EQUAL(is_register_ok,1);
	CU_ASSERT_EQUAL(using_transaction,use_transaction);
	belle_sip_provider_remove_sip_listener(prov,l);
}
Beispiel #3
0
int belle_sip_dialog_check_incoming_request_ordering(belle_sip_dialog_t *obj, belle_sip_request_t *req){
	belle_sip_header_cseq_t *cseqh=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
	unsigned int cseq=belle_sip_header_cseq_get_seq_number(cseqh);
	if (obj->remote_cseq==0){
		obj->remote_cseq=cseq;
	}else if (cseq>obj->remote_cseq){
			return 0;
	}
	belle_sip_warning("Ignoring request because cseq is inconsistent.");
	return -1;
}
Beispiel #4
0
int belle_sip_dialog_handle_ack(belle_sip_dialog_t *obj, belle_sip_request_t *ack){
	belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(ack,belle_sip_header_cseq_t);
	if (obj->needs_ack && belle_sip_header_cseq_get_seq_number(cseq)==obj->remote_cseq){
		belle_sip_message("Incoming INVITE has ACK, dialog is happy");
		obj->needs_ack=FALSE;
		belle_sip_dialog_stop_200Ok_retrans(obj);
		belle_sip_dialog_process_queue(obj);
		return 0;
	}
	belle_sip_message("Dialog ignoring incoming ACK (surely a retransmission)");
	return -1;
}
Beispiel #5
0
static int belle_sip_dialog_init_as_uac(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){
	const belle_sip_list_t *elem;
	belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t);
	belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
	belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t);
	belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t);
	belle_sip_uri_t *requri=belle_sip_request_get_uri(req);

	if (!to){
		belle_sip_error("No to in response.");
		return -1;
	}
	if (!cseq){
		belle_sip_error("No cseq in request.");
		return -1;
	}
	if (!via){
		belle_sip_error("No via in request.");
		return -1;
	}

	if (strcasecmp(belle_sip_header_via_get_protocol(via),"TLS")==0
	    && belle_sip_uri_is_secure(requri)){
		obj->is_secure=TRUE;
	}
	/**12.1.2
	 *  The route set MUST be set to the list of URIs in the Record-Route
   	 *header field from the response, taken in reverse order and preserving
   	 *all URI parameters.  If no Record-Route header field is present in
   	 *the response, the route set MUST be set to the empty set.
   	 **/
	obj->route_set=belle_sip_list_free_with_data(obj->route_set,belle_sip_object_unref);
	for(elem=belle_sip_message_get_headers((belle_sip_message_t*)resp,BELLE_SIP_RECORD_ROUTE);elem!=NULL;elem=elem->next){
		obj->route_set=belle_sip_list_prepend(obj->route_set,belle_sip_object_ref(belle_sip_header_route_create(
		                                     (belle_sip_header_address_t*)elem->data)));
	}

	check_route_set(obj->route_set);
	/*contact might be provided later*/
	if (ct)
		obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct);

	obj->local_cseq=belle_sip_header_cseq_get_seq_number(cseq);
	/*call id is already set */
	/*local_tag is already set*/
	obj->remote_party=(belle_sip_header_address_t*)belle_sip_object_ref(to);
	/*local party is already set*/
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){
		set_last_out_invite(obj,req);
	}
	return 0;
}
Beispiel #6
0
belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos,const char* realm) {
	belle_sip_request_t* initial_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	belle_sip_request_t* req=belle_sip_request_clone_with_body(initial_request);
	belle_sip_header_cseq_t* cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
	belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_COMPLETED
		&& belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_TERMINATED) {
		belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED"
					,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)))
					,t);
		belle_sip_object_unref(req);
		return NULL;
	}
	/*remove auth headers*/
	belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_AUTHORIZATION);
	belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_PROXY_AUTHORIZATION);

	/*put auth header*/
	belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm);
	return req;
}
Beispiel #7
0
static belle_sip_request_t *make_ack(belle_sip_ict_t *obj, belle_sip_response_t *resp){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	if (obj->ack==NULL){
		obj->ack=belle_sip_request_new();
		belle_sip_object_ref(obj->ack);
		belle_sip_request_set_method(obj->ack,"ACK");
		belle_sip_request_set_uri(obj->ack,belle_sip_request_get_uri(base->request));
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_VIA,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_CALL_ID,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_FROM,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)resp,(belle_sip_message_t*)obj->ack,BELLE_SIP_TO,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_CONTACT,TRUE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_ROUTE,TRUE);
		belle_sip_message_add_header((belle_sip_message_t*)obj->ack,
		(belle_sip_header_t*)belle_sip_header_cseq_create(
			belle_sip_header_cseq_get_seq_number((belle_sip_header_cseq_t*)belle_sip_message_get_header((belle_sip_message_t*)base->request,BELLE_SIP_CSEQ)),
		    "ACK"));
	}

	return obj->ack;
}
Beispiel #8
0
belle_sip_request_t *belle_sip_dialog_create_ack(belle_sip_dialog_t *obj, unsigned int cseq){
	belle_sip_header_cseq_t *cseqh;
	belle_sip_request_t *invite=obj->last_out_invite;
	belle_sip_request_t *ack;
	
	if (!invite){
		belle_sip_error("No INVITE to ACK.");
		return NULL;
	}
	cseqh=belle_sip_message_get_header_by_type(invite,belle_sip_header_cseq_t);
	if (belle_sip_header_cseq_get_seq_number(cseqh)!=cseq){
		belle_sip_error("No INVITE with cseq %i to create ack for.",cseq);
		return NULL;
	}
	ack=create_request(obj,"ACK",TRUE);
/*
22 Usage of HTTP Authentication
22.1 Framework
   While a server can legitimately challenge most SIP requests, there
   are two requests defined by this document that require special
   handling for authentication: ACK and CANCEL.
   Under an authentication scheme that uses responses to carry values
   used to compute nonces (such as Digest), some problems come up for
   any requests that take no response, including ACK.  For this reason,
   any credentials in the INVITE that were accepted by a server MUST be
   accepted by that server for the ACK.  UACs creating an ACK message
   will duplicate all of the Authorization and Proxy-Authorization
   header field values that appeared in the INVITE to which the ACK
   corresponds.  Servers MUST NOT attempt to challenge an ACK.
  */
	if (ack){
		const belle_sip_list_t *aut=belle_sip_message_get_headers((belle_sip_message_t*)obj->last_out_invite,"Authorization");
		const belle_sip_list_t *prx_aut=belle_sip_message_get_headers((belle_sip_message_t*)obj->last_out_invite,"Proxy-Authorization");
		if (aut)
			belle_sip_message_add_headers((belle_sip_message_t*)ack,aut);
		if (prx_aut)
			belle_sip_message_add_headers((belle_sip_message_t*)ack,prx_aut);
	}
	return ack;
}
Beispiel #9
0
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){
	belle_sip_message_t *orig=(belle_sip_message_t*)t->base.request;
	belle_sip_request_t *req;
	const char *orig_method=belle_sip_request_get_method((belle_sip_request_t*)orig);
	if (strcmp(orig_method,"ACK")==0 || strcmp(orig_method,"INVITE")!=0){
		belle_sip_error("belle_sip_client_transaction_create_cancel() cannot be used for ACK or non-INVITE transactions.");
		return NULL;
	}
	if (t->base.state!=BELLE_SIP_TRANSACTION_PROCEEDING){
		belle_sip_error("belle_sip_client_transaction_create_cancel() can only be used in state BELLE_SIP_TRANSACTION_PROCEEDING"
		               " but current transaction state is %s",belle_sip_transaction_state_to_string(t->base.state));
		return NULL;
	}
	req=belle_sip_request_new();
	belle_sip_request_set_method(req,"CANCEL");
/*	9.1 Client Behavior
	   Since requests other than INVITE are responded to immediately,
	   sending a CANCEL for a non-INVITE request would always create a
	   race condition.
	   The following procedures are used to construct a CANCEL request.  The
	   Request-URI, Call-ID, To, the numeric part of CSeq, and From header
	   fields in the CANCEL request MUST be identical to those in the
	   request being cancelled, including tags.  A CANCEL constructed by a
	   client MUST have only a single Via header field value matching the
	   top Via value in the request being cancelled.*/
	belle_sip_request_set_uri(req,(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri((belle_sip_request_t*)orig)));
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"via",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"call-id",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"from",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"to",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"route",TRUE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE);
	belle_sip_message_add_header((belle_sip_message_t*)req,
		(belle_sip_header_t*)belle_sip_header_cseq_create(
			belle_sip_header_cseq_get_seq_number((belle_sip_header_cseq_t*)belle_sip_message_get_header(orig,"cseq")),
		    "CANCEL"));
	return req;
}
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));
	}
}
Beispiel #11
0
void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) {
	belle_sip_header_cseq_t* 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);
	sal_op_send_request(op,request);
}
Beispiel #12
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;
}
Beispiel #13
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;
}
void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req);
	belle_sip_header_address_t* address;
	belle_sip_header_from_t* from_header;
	belle_sip_header_content_type_t* content_type;
	belle_sip_response_t* resp;
	int errcode=500;
	belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t);
	belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
	belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t);
	char* from;
	bool_t plain_text=FALSE;
	bool_t external_body=FALSE;
	bool_t cipher_xml=FALSE;
	bool_t rcs_filetransfer=FALSE;
	uint8_t *decryptedMessage = NULL;

	from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
	content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
	/* check if we have a xml/cipher message to be decrypted */
	if (content_type && (cipher_xml=is_cipher_xml(content_type))) {
		/* access the zrtp cache to get keys needed to decipher the message */
		LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
		FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+");
		if (CACHEFD == NULL) {
			ms_warning("Unable to access ZRTP ZID cache to decrypt message");
			goto error;
		} else {
			size_t cacheSize;
			char *cacheString;
			int retval;
			xmlDocPtr cacheXml;
			
			cacheString=ms_load_file_content(CACHEFD, &cacheSize);
			if (!cacheString){
				ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
				goto error;
			}
			cacheString[cacheSize] = '\0';
			cacheSize += 1;
			fclose(CACHEFD);
			cacheXml = xmlParseDoc((xmlChar*)cacheString);
			ms_free(cacheString);
			retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage);
			if (retval != 0) {
				ms_warning("Unable to decrypt message, reason : %s - op [%p]", lime_error_code_to_string(retval), op);
				free(decryptedMessage);
				xmlFreeDoc(cacheXml);
				errcode = 488;
				goto error;
			} else {
				/* dump updated cache to a string */
				xmlChar *xmlStringOutput;
				int xmlStringLength;
				xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0);
				/* write it to the cache file */
				CACHEFD = fopen(lc->zrtp_secrets_cache, "wb+");
				if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
					ms_warning("Fail to write cache");
				}
				xmlFree(xmlStringOutput);
				fclose(CACHEFD);
			}

			xmlFreeDoc(cacheXml);
		}

	}

	rcs_filetransfer=is_rcs_filetransfer(content_type);
	if (content_type && ((plain_text=is_plain_text(content_type))
						|| (external_body=is_external_body(content_type))
						|| (decryptedMessage!=NULL) 
						|| rcs_filetransfer)) {
		SalMessage salmsg;
		char message_id[256]={0};
	
		if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
		op->pending_server_trans=server_transaction;
		belle_sip_object_ref(op->pending_server_trans);
	
		address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
				,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
		from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
		snprintf(message_id,sizeof(message_id)-1,"%s%i"
				,belle_sip_header_call_id_get_call_id(call_id)
				,belle_sip_header_cseq_get_seq_number(cseq));
		salmsg.from=from;
		/* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/
		if (cipher_xml) {
			salmsg.text = (char *)decryptedMessage;
		} else { /* message body wasn't ciphered */
			salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
		}
		salmsg.url=NULL;
		salmsg.content_type = NULL;
		if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */
			salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml";
		}
		if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) {
			size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"));
			salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/
			((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/
		}
		salmsg.message_id=message_id;
		salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL);
		op->base.root->callbacks.text_received(op,&salmsg);

		free(decryptedMessage);
		belle_sip_object_unref(address);
		belle_sip_free(from);
		if (salmsg.url) ms_free((char*)salmsg.url);
	} else if (content_type && is_im_iscomposing(content_type)) {
		SalIsComposing saliscomposing;
		address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
				,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
		from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
		saliscomposing.from=from;
		saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
		op->base.root->callbacks.is_composing_received(op,&saliscomposing);
		resp = belle_sip_response_create_from_request(req,200);
		belle_sip_server_transaction_send_response(server_transaction,resp);
		belle_sip_object_unref(address);
		belle_sip_free(from);
	} else {
		ms_error("Unsupported MESSAGE (content-type not recognized)");
		resp = belle_sip_response_create_from_request(req,415);
		add_message_accept((belle_sip_message_t*)resp);
		belle_sip_server_transaction_send_response(server_transaction,resp);
		sal_op_release(op);
		return;
	}
	return;
error:
	resp = belle_sip_response_create_from_request(req, errcode);
	belle_sip_server_transaction_send_response(server_transaction,resp);
	sal_op_release(op);
}
Beispiel #15
0
void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req);
	belle_sip_header_address_t* address;
	belle_sip_header_from_t* from_header;
	belle_sip_header_content_type_t* content_type;
	belle_sip_response_t* resp;
	belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t);
	belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
	belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t);
	char* from;
	bool_t plain_text=FALSE;
	bool_t external_body=FALSE;

	from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
	content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
	if (content_type && ((plain_text=is_plain_text(content_type))
						|| (external_body=is_external_body(content_type)))) {
		SalMessage salmsg;
		char message_id[256]={0};
	
		if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
		op->pending_server_trans=server_transaction;
		belle_sip_object_ref(op->pending_server_trans);
	
		address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
				,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
		from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
		snprintf(message_id,sizeof(message_id)-1,"%s%i"
				,belle_sip_header_call_id_get_call_id(call_id)
				,belle_sip_header_cseq_get_seq_number(cseq));
		salmsg.from=from;
		salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
		salmsg.url=NULL;
		if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) {
			size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"));
			salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/
			((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/
		}
		salmsg.message_id=message_id;
		salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL);
		op->base.root->callbacks.text_received(op,&salmsg);
		belle_sip_object_unref(address);
		belle_sip_free(from);
		if (salmsg.url) ms_free((char*)salmsg.url);
	} else if (content_type && is_im_iscomposing(content_type)) {
		SalIsComposing saliscomposing;
		address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
				,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
		from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
		saliscomposing.from=from;
		saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
		op->base.root->callbacks.is_composing_received(op,&saliscomposing);
		resp = belle_sip_response_create_from_request(req,200);
		belle_sip_server_transaction_send_response(server_transaction,resp);
		belle_sip_object_unref(address);
		belle_sip_free(from);
	} else {
		ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type)
				,belle_sip_header_content_type_get_subtype(content_type));
		resp = belle_sip_response_create_from_request(req,415);
		add_message_accept((belle_sip_message_t*)resp);
		belle_sip_server_transaction_send_response(server_transaction,resp);
		return;
	}
}