Add RPC caller and RPC caller session components
Change rpc_caller_interface to follow the new RPC protocol's primitives.
Introduce rpc_caller_session as a session layer built on top of the
rpc_caller_interface. An opened session is tied to an interface of an
RPC endpoint.
Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: Ibd75998d6a9d511b4adc79274cce34b59d9730f8
diff --git a/components/rpc/common/caller/rpc_caller_session.c b/components/rpc/common/caller/rpc_caller_session.c
new file mode 100644
index 0000000..d72a318
--- /dev/null
+++ b/components/rpc/common/caller/rpc_caller_session.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpc_caller_session.h"
+#include "util.h"
+#include <string.h>
+
+static rpc_status_t initalize_shared_memory(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ size_t shared_memory_size)
+{
+ if (shared_memory_size) {
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ status = rpc_caller_create_shared_memory(caller, shared_memory_size,
+ &session->shared_memory);
+ if (status) {
+ rpc_caller_close_session(caller);
+ return status;
+ }
+
+ session->shared_memory_policy = alloc_for_session;
+ } else {
+ session->shared_memory = (struct rpc_caller_shared_memory){ 0 };
+ session->shared_memory_policy = alloc_for_each_call;
+ }
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t rpc_caller_session_open(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id,
+ size_t shared_memory_size)
+{
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!session || !caller || !service_uuid)
+ return RPC_ERROR_INVALID_VALUE;
+
+ status = rpc_caller_open_session(caller, service_uuid, endpoint_id);
+ if (status)
+ return status;
+
+ status = initalize_shared_memory(session, caller, shared_memory_size);
+ if (status)
+ return status;
+
+ session->caller = caller;
+ session->is_call_transaction_in_progress = false;
+ session->request_length = 0;
+
+ return status;
+}
+
+rpc_status_t rpc_caller_session_find_and_open(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ size_t shared_memory_size)
+{
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!session || !caller || !service_uuid)
+ return RPC_ERROR_INVALID_VALUE;
+
+ status = rpc_caller_find_and_open_session(caller, service_uuid);
+ if (status)
+ return status;
+
+ status = initalize_shared_memory(session, caller, shared_memory_size);
+ if (status)
+ return status;
+
+ session->caller = caller;
+ session->is_call_transaction_in_progress = false;
+ session->request_length = 0;
+
+ return status;
+}
+
+rpc_status_t rpc_caller_session_close(struct rpc_caller_session *session)
+{
+ if (!session)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (session->is_call_transaction_in_progress)
+ return RPC_ERROR_INVALID_STATE;
+
+ if (session->shared_memory_policy == alloc_for_session) {
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ rpc_status = rpc_caller_release_shared_memory(session->caller,
+ &session->shared_memory);
+ if (rpc_status != RPC_SUCCESS)
+ return rpc_status;
+ }
+
+ return rpc_caller_close_session(session->caller);
+}
+
+rpc_call_handle rpc_caller_session_begin(struct rpc_caller_session *session,
+ uint8_t **request_buffer, size_t request_length,
+ size_t response_max_length)
+{
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+ size_t required_buffer_length = MAX(request_length, response_max_length);
+
+ if (required_buffer_length > UINT32_MAX)
+ return NULL;
+
+ if (!session || !request_buffer || session->is_call_transaction_in_progress)
+ return NULL;
+
+ switch (session->shared_memory_policy) {
+ case alloc_for_each_call:
+ if (session->shared_memory.buffer || session->shared_memory.size)
+ return NULL; /* There's already a shared memory */
+
+ status = rpc_caller_create_shared_memory(session->caller, required_buffer_length,
+ &session->shared_memory);
+ if (status)
+ return NULL; /* Failed to create shared memory */
+ break;
+
+ case alloc_for_session:
+ if (!session->shared_memory.buffer || !session->shared_memory.size)
+ return NULL; /* There's no shared memory */
+
+ if (session->shared_memory.size < required_buffer_length)
+ return NULL; /* The allocated shared memory is too small */
+ break;
+
+ default:
+ /* Invalid shared memory policy */
+ return NULL;
+ }
+
+ *request_buffer = session->shared_memory.buffer;
+
+ session->is_call_transaction_in_progress = true;
+ session->request_length = request_length;
+
+ return (rpc_call_handle)session;
+}
+
+rpc_status_t rpc_caller_session_invoke(rpc_call_handle handle, uint32_t opcode,
+ uint8_t **response_buffer, size_t *response_length,
+ service_status_t *service_status)
+{
+ struct rpc_caller_session *session = (struct rpc_caller_session *)handle;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!handle || !response_buffer || !response_length)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (!session->is_call_transaction_in_progress)
+ return RPC_ERROR_INVALID_STATE;
+
+ if (session->request_length &&
+ (!session->shared_memory.buffer || !session->shared_memory.size))
+ return RPC_ERROR_INVALID_STATE;
+
+ status = rpc_caller_call(session->caller, opcode, &session->shared_memory,
+ session->request_length, response_length, service_status);
+ if (status || *response_length > session->shared_memory.size) {
+ *response_buffer = NULL;
+ *response_length = 0;
+ return status;
+ }
+
+ *response_buffer = session->shared_memory.buffer;
+
+ return status;
+}
+
+rpc_status_t rpc_caller_session_end(rpc_call_handle handle)
+{
+ struct rpc_caller_session *session = (struct rpc_caller_session *)handle;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!handle)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (!session->is_call_transaction_in_progress)
+ return RPC_ERROR_INVALID_STATE;
+
+ if (session->request_length &&
+ (!session->shared_memory.buffer || !session->shared_memory.size))
+ return RPC_ERROR_INVALID_STATE; /* There's no shared memory */
+
+ switch (session->shared_memory_policy) {
+ case alloc_for_each_call:
+ status = rpc_caller_release_shared_memory(session->caller,
+ &session->shared_memory);
+ if (status)
+ return status; /* Failed to release shared memory */
+
+ session->shared_memory = (struct rpc_caller_shared_memory){ 0 };
+ break;
+
+ case alloc_for_session:
+ /* Nothing to do */
+ break;
+
+ default:
+ return RPC_ERROR_INVALID_STATE;
+ }
+
+ session->is_call_transaction_in_progress = false;
+ session->request_length = 0;
+
+ return RPC_SUCCESS;
+}