Add logging RPC caller

To help debug PSA API tests, a simple logging RPC caller has been
added that can be stacked on top of another rpc_caller to log
call requests and responses.  The logging_caller has been
integrated into the psa-api-test deployment.  Logging may
be enabled using '-l' command line switch.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ib71d9fb2d6efbd2b5f513dd62b47109aab7ef55d
diff --git a/components/rpc/common/logging/component.cmake b/components/rpc/common/logging/component.cmake
new file mode 100644
index 0000000..71c1e71
--- /dev/null
+++ b/components/rpc/common/logging/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/logging_caller.c"
+	)
diff --git a/components/rpc/common/logging/logging_caller.c b/components/rpc/common/logging/logging_caller.c
new file mode 100644
index 0000000..efc1184
--- /dev/null
+++ b/components/rpc/common/logging/logging_caller.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include "logging_caller.h"
+
+static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len);
+static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
+			 	int *opstatus, uint8_t **resp_buf, size_t *resp_len);
+static void call_end(void *context, rpc_call_handle handle);
+
+
+void logging_caller_init(
+	struct logging_caller *this_instance,
+	FILE *log_file)
+{
+	struct rpc_caller *base = &this_instance->rpc_caller;
+
+	rpc_caller_init(base, this_instance);
+	base->call_begin = call_begin;
+	base->call_invoke = call_invoke;
+	base->call_end = call_end;
+
+	this_instance->attached_caller = NULL;
+	this_instance->log_file = log_file;
+	this_instance->call_index = 0;
+}
+
+void logging_caller_deinit(
+	struct logging_caller *this_instance)
+{
+	this_instance->attached_caller = NULL;
+}
+
+struct rpc_caller *logging_caller_attach(
+	struct logging_caller *this_instance,
+	struct rpc_caller *attached_caller)
+{
+	this_instance->attached_caller = attached_caller;
+	return &this_instance->rpc_caller;
+}
+
+static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len)
+{
+	struct logging_caller *this_instance = (struct logging_caller*)context;
+	rpc_call_handle handle = NULL;
+
+	if (this_instance->attached_caller) {
+
+		handle = rpc_caller_begin(this_instance->attached_caller, req_buf, req_len);
+	}
+
+	fprintf(this_instance->log_file, "========================\n");
+	fprintf(this_instance->log_file, "index: %d\n", this_instance->call_index);
+	fprintf(this_instance->log_file, "req_len: %ld\n", req_len);
+
+	if (!handle) {
+
+		fprintf(this_instance->log_file, "ERROR: call_begin failed\n");
+	}
+
+	++this_instance->call_index;
+
+	return handle;
+}
+
+static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
+			 	int *opstatus, uint8_t **resp_buf, size_t *resp_len)
+{
+	struct logging_caller *this_instance = (struct logging_caller*)context;
+	rpc_status_t status = TS_RPC_ERROR_INVALID_TRANSACTION;
+
+	if (this_instance->attached_caller) {
+
+
+		status = rpc_caller_invoke(this_instance->attached_caller,
+			handle, opcode, opstatus,
+			resp_buf, resp_len);
+	}
+
+	fprintf(this_instance->log_file, "opcode: %d\n", opcode);
+	fprintf(this_instance->log_file, "rpc_status: %d\n", status);
+
+	if (status == TS_RPC_CALL_ACCEPTED) {
+
+		fprintf(this_instance->log_file, "op_status: %d\n", *opstatus);
+		fprintf(this_instance->log_file, "resp_len: %ld\n", *resp_len);
+	}
+
+	fprintf(this_instance->log_file, "------------------------\n");
+
+	return status;
+}
+
+static void call_end(void *context, rpc_call_handle handle)
+{
+	struct logging_caller *this_instance = (struct logging_caller*)context;
+
+	if (this_instance->attached_caller) {
+
+		rpc_caller_end(this_instance->attached_caller, handle);
+	}
+}
diff --git a/components/rpc/common/logging/logging_caller.h b/components/rpc/common/logging/logging_caller.h
new file mode 100644
index 0000000..e5e6cb2
--- /dev/null
+++ b/components/rpc/common/logging/logging_caller.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LOGGING_CALLER_H
+#define LOGGING_CALLER_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <rpc_caller.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * An rpc_caller that logs call requests and responses to a file.
+ * Can be stacked on top of another rpc_caller to allow call traffic to be
+ * observed without interferring with the call flow.  Intended to be used
+ * for debug and test purposes.
+ **/
+struct logging_caller
+{
+	struct rpc_caller rpc_caller;
+	struct rpc_caller *attached_caller;
+	uint32_t call_index;
+	FILE *log_file;
+};
+
+/**
+ * @brief      Initialises a logging_caller
+ *
+ * @param[in]  this_instance 	The RPC caller instance to initialize
+ * @param[in]  log_file			Log to this file (assumed to be open)
+ */
+void logging_caller_init(
+	struct logging_caller *this_instance,
+	FILE *log_file);
+
+/**
+ * @brief      De-initialises a logging_caller
+ *
+ * @param[in]  this_instance 	The RPC caller instance to deinitialize
+ */
+void logging_caller_deinit(
+	struct logging_caller *this_instance);
+
+/**
+ * @brief      Attach an rpc_caller to form a stack
+ *
+ * @param[in]  this_instance 	The RPC caller instance to initialize
+ * @param[in]  attached_caller 	Stacked over this rpc_caller
+ *
+ * @return     The base rpc_caller that a client may use
+ */
+struct rpc_caller *logging_caller_attach(
+	struct logging_caller *this_instance,
+	struct rpc_caller *attached_caller);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOGGING_CALLER_H */
diff --git a/deployments/psa-api-test/arch_test_runner.c b/deployments/psa-api-test/arch_test_runner.c
index 90ca304..43ca703 100644
--- a/deployments/psa-api-test/arch_test_runner.c
+++ b/deployments/psa-api-test/arch_test_runner.c
@@ -5,20 +5,43 @@
  */
 
 #include <stdint.h>
+#include <stdbool.h>
 #include <stdio.h>
+#include <string.h>
 #include <service_locator.h>
+#include <rpc/common/logging/logging_caller.h>
 #include "service_under_test.h"
 
 int32_t val_entry(void);
 
+static bool option_selected(const char *option_switch, int argc, char *argv[])
+{
+    bool selected = false;
+
+    for (int i = 1; (i < argc) && !selected; ++i) {
+
+        selected = (strcmp(argv[i], option_switch) == 0);
+    }
+
+    return selected;
+}
+
 int main(int argc, char *argv[])
 {
     int rval = -1;
+    struct logging_caller *selected_call_logger = NULL;
+    struct logging_caller call_logger;
 
+    logging_caller_init(&call_logger, stdout);
     service_locator_init();
 
-    rval = locate_service_under_test();
+    /* Check command line options */
+    if (option_selected("-l", argc, argv)) selected_call_logger = &call_logger;
 
+    /* Locate service under test */
+    rval = locate_service_under_test(selected_call_logger);
+
+    /* Run tests */
     if (!rval) {
 
         rval = val_entry();
@@ -30,5 +53,7 @@
         printf("Failed to locate service under test.  Error code: %d\n", rval);
     }
 
+    logging_caller_deinit(&call_logger);
+
     return rval;
 }
diff --git a/deployments/psa-api-test/crypto/crypto_locator.c b/deployments/psa-api-test/crypto/crypto_locator.c
index 8571b23..609c525 100644
--- a/deployments/psa-api-test/crypto/crypto_locator.c
+++ b/deployments/psa-api-test/crypto/crypto_locator.c
@@ -14,8 +14,7 @@
 static rpc_session_handle session_handle = NULL;
 static struct service_context *crypto_service_context = NULL;
 
-
-int locate_service_under_test(void)
+int locate_service_under_test(struct logging_caller *call_logger)
 {
 	int status = -1;
 
@@ -33,7 +32,15 @@
 
 			if (session_handle) {
 
-				psa_crypto_client_init(caller);
+				if (call_logger) {
+
+					psa_crypto_client_init(logging_caller_attach(call_logger, caller));
+				}
+				else {
+
+					psa_crypto_client_init(caller);
+				}
+
 				status = 0;
 			}
 			else {
diff --git a/deployments/psa-api-test/psa-api-test.cmake b/deployments/psa-api-test/psa-api-test.cmake
index 357abd1..a1262c2 100644
--- a/deployments/psa-api-test/psa-api-test.cmake
+++ b/deployments/psa-api-test/psa-api-test.cmake
@@ -28,6 +28,8 @@
 	COMPONENTS
 		"components/common/tlv"
 		"components/service/common/include"
+		"components/rpc/common/caller"
+		"components/rpc/common/logging"
 )
 
 target_sources(psa-api-test PRIVATE
diff --git a/deployments/psa-api-test/service_under_test.h b/deployments/psa-api-test/service_under_test.h
index 85dc81f..29f99f7 100644
--- a/deployments/psa-api-test/service_under_test.h
+++ b/deployments/psa-api-test/service_under_test.h
@@ -7,6 +7,8 @@
 #ifndef SERVICE_UNDER_TEST_H
 #define SERVICE_UNDER_TEST_H
 
+#include <rpc/common/logging/logging_caller.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -17,7 +19,7 @@
  * associate an RPC Caller with the singleton PSA API client used by
  * the API tests.
  */
-int locate_service_under_test(void);
+int locate_service_under_test(struct logging_caller *call_logger);
 
 /**
  * Reliquish the RPC session when the test run is complete.