Beispiel #1
0
void linphone_xml_rpc_session_send_request(LinphoneXmlRpcSession *session, LinphoneXmlRpcRequest *request) {
	belle_http_request_listener_callbacks_t cbs = { 0 };
	belle_http_request_listener_t *l;
	belle_generic_uri_t *uri;
	belle_http_request_t *req;
	belle_sip_memory_body_handler_t *bh;
	const char *data;
	linphone_xml_rpc_request_ref(request);

	uri = belle_generic_uri_parse(session->url);
	if (!uri) {
		ms_error("Could not send request, URL %s is invalid", session->url);
		process_io_error_from_post_xml_rpc_request(request, NULL);
		return;
	}
	req = belle_http_request_create("POST", uri, belle_sip_header_content_type_create("text", "xml"), NULL);
	if (!req) {
		belle_sip_object_unref(uri);
		process_io_error_from_post_xml_rpc_request(request, NULL);
		return;
	}
	data = linphone_xml_rpc_request_get_content(request);
	bh = belle_sip_memory_body_handler_new_copy_from_buffer(data, strlen(data), NULL, NULL);
	belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh));
	cbs.process_response = process_response_from_post_xml_rpc_request;
	cbs.process_io_error = process_io_error_from_post_xml_rpc_request;
	cbs.process_auth_requested = process_auth_requested_from_post_xml_rpc_request;
	l = belle_http_request_listener_create_from_callbacks(&cbs, request);
	belle_http_provider_send_request(session->core->http_provider, req, l);
	/*ensure that the listener object will be destroyed with the request*/
	belle_sip_object_data_set(BELLE_SIP_OBJECT(request), "listener", l, belle_sip_object_unref);
	/*prevent destruction of the session while there are still pending http requests*/
	belle_sip_object_data_set(BELLE_SIP_OBJECT(request), "session", belle_sip_object_ref(session), belle_sip_object_unref);
}
void belle_sip_object_data_merge( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func)
{
	struct _belle_sip_list* list = src->data_store;
	struct belle_sip_object_data* it = NULL;
	void* cloned_data = NULL;

	while( list ){
		it = list->data;
		if( it ){
			cloned_data = (clone_func)? clone_func( it->name, it->data ) : it->data;
			belle_sip_object_data_set(dst, it->name, cloned_data, it->destroy_func);
		}
		list = list->next;
	}
}
Beispiel #3
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 test_object_data(void)
{
	belle_sip_object_t*    obj = belle_sip_object_new(belle_sip_object_t);
	belle_sip_object_t* cloned = belle_sip_object_new(belle_sip_object_t);
	int i = 123;
	const char* str = "toto", *str2 = "titi";

	/* normal insertion with no destroy callback */

	// should return 0
	BC_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_i", INT_TO_VOIDPTR(i), NULL), 0, int, "%d");
	// should return the value we put in it
	BC_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), i, int, "%d");


	/*
	 * Overwriting insertion
	 */


	// overwrite data: should return 1 when set()
	i = 124;
	BC_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_i", INT_TO_VOIDPTR(i), NULL), 1 , int, "%d");
	// should return the new value we put in it
	BC_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), i, int, "%d");


	/*
	 * normal insertion with destroy callback
	 */

	BC_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_str",
											  (void*)belle_sip_strdup(str),
											  test_object_data_string_destroy),
					0, int, "%d");

	// we should get back the same string
	BC_ASSERT_STRING_EQUAL( (const char*)belle_sip_object_data_get(obj, "test_str"),
							str );

	BC_ASSERT_EQUAL(belle_sip_object_data_remove(obj, "test_str"),0, int, "%d");
	// we expect the destroy() function to be called on removal
	BC_ASSERT_EQUAL(destroy_called, 1, int, "%d");
	destroy_called = 0;

	/*
	 * string insertion and replace
	 */
	belle_sip_object_data_set(obj, "test_str",
							  (void*)belle_sip_strdup(str),
							  test_object_data_string_destroy);
	belle_sip_object_data_set(obj, "test_str",
							  (void*)belle_sip_strdup(str2),
							  test_object_data_string_destroy);
	BC_ASSERT_EQUAL(destroy_called, 1, int, "%d"); // we expect the dtor to have been called to free the first string


	/*
	 * Get non-existent key
	 */
	BC_ASSERT_PTR_NULL(belle_sip_object_data_get(obj, "non-exist"));

	/*
	 * test cloning the dictionary
	 */
	belle_sip_object_data_clone(obj, cloned, test_object_data_string_clone);
	BC_ASSERT_EQUAL(clone_called,2,int,"%d"); // we expect the clone function to be called for "test_i" and "test_st, int, "%d"r"

	// the values should be equal
	BC_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")),
					 VOIDPTR_TO_INT(belle_sip_object_data_get(cloned, "test_i"))
					 , int, "%d");

	BC_ASSERT_STRING_EQUAL( (const char*)belle_sip_object_data_get(obj, "test_str"),
							(const char*)belle_sip_object_data_get(cloned, "test_str"));
	// but the pointers should be different
	BC_ASSERT_PTR_NOT_EQUAL( belle_sip_object_data_get(obj, "test_str"),
							belle_sip_object_data_get(cloned, "test_str"));


	/*
	 * Foreach test
	 */
	belle_sip_object_data_foreach(obj, test_object_data_foreach_cb, NULL);
	BC_ASSERT_EQUAL( foreach_called, 2 , int, "%d");

	belle_sip_object_unref(obj);
	belle_sip_object_unref(cloned);

}