Add client-side logic of DCM ext API 49/254649/15
authorTomasz Swierczek <t.swierczek@samsung.com>
Fri, 5 Mar 2021 13:51:19 +0000 (14:51 +0100)
committerTomasz Swierczek <t.swierczek@samsung.com>
Thu, 1 Apr 2021 11:51:35 +0000 (13:51 +0200)
Change-Id: I2f1c806122118534adf634f5b3dbea958fc295bd

src/dcm-client/CMakeLists.txt
src/dcm-client/dcm_support.proto
src/dcm-client/device_certificate_manager_ext.cpp
src/dcm-daemon/dcm-ext-backend-api.h

index 4f7f60d..e29b59e 100644 (file)
@@ -46,8 +46,10 @@ ADD_LIBRARY(${TARGET_CLIENT}
 ADD_LIBRARY(${TARGET_CLIENT_EXT}
        SHARED
        device_certificate_manager_ext.cpp
+       ../shared/protobuf_asio.cpp
        ../shared/log.cpp
-       )
+       ${PROTO_SRCS}
+       ${PROTO_HDRS})
 
 TARGET_LINK_LIBRARIES(${TARGET_CLIENT}
        ${Boost_SYSTEM_LIBRARY}
@@ -57,6 +59,7 @@ TARGET_LINK_LIBRARIES(${TARGET_CLIENT}
 
 TARGET_LINK_LIBRARIES(${TARGET_CLIENT_EXT}
        ${Boost_SYSTEM_LIBRARY}
+       ${PROTOBUF_LITE_LIBRARIES}
        ${CLIENT_DEPS_LIBRARIES}
        ${CMAKE_THREAD_LIBS_INIT})
 
index 6a7e96d..50a2f43 100644 (file)
@@ -59,11 +59,24 @@ message SignResponse
        optional bytes signature = 2;
 }
 
+message ExtCallRequest
+{
+       required string method_name = 1;
+       optional bytes input_data = 2;
+}
+
+message ExtCallResponse
+{
+       required int32 result = 1;
+       optional bytes output_data = 2;
+}
+
 message RequestMessage {
        oneof request_oneof {
                AssociateKeyContext associate_context = 1;
                RequestCertificateChain request_chain = 2;
                SignRequest sign_data = 3;
+               ExtCallRequest ext_call = 4;
        }
 }
 
@@ -72,5 +85,6 @@ message ResponseMessage {
                AssociateKeyContextResponse associate_context = 1;
                RequestCertificateChainResponse request_chain = 2;
                SignResponse sign_data = 3;
+               ExtCallResponse ext_call = 4;
        }
 }
index ce3c4f8..c92ae47 100644 (file)
  *
  ******************************************************************/
 
+#include <cstring>
+#include <mutex>
+#include <vector>
+
+#include <boost/asio.hpp>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/coded_stream.h>
+
+#include "dcm_support.pb.h"
 #include "device_certificate_manager_ext.h"
 #include "log.h"
+#include "protobuf_asio.h"
 
 #ifndef API_DEVICE_CERTIFICATE_MANAGER_EXT_EXPORT
 #define API_DEVICE_CERTIFICATE_MANAGER_EXT_EXPORT __attribute__((visibility("default")))
 #endif
 
+static std::mutex g_mutex;
+
 API_DEVICE_CERTIFICATE_MANAGER_EXT_EXPORT
 int dcm_ext_call_api(const char* method_name, const char* input_data, size_t input_len,
-                     char** output_data, size_t* output_len)
+                                        char** output_data, size_t* output_len)
 {
-    (void) method_name;
-    (void) input_data;
-    (void) input_len;
-    (void) output_data;
-    (void) output_len;
-    LOGE("No implementation yet - TODO");
-    return DCM_EXT_ERROR_UNKNOWN;
+       if(!method_name) {
+               LOGE("Invalid input parameters");
+               return DCM_EXT_ERROR_INVALID_PARAMETER;
+       }
+
+       std::lock_guard<std::mutex> locker(g_mutex);
+       std::unique_ptr<boost::asio::local::stream_protocol::socket> socket;
+       boost::asio::io_service ioService;
+
+       try {
+               socket.reset(new boost::asio::local::stream_protocol::socket(ioService));
+               boost::asio::local::stream_protocol::endpoint endpoint(DCM_UNIX_SOCKET_PATH);
+               socket->connect(endpoint);
+       } catch(std::exception& ex) {
+               LOGE("Caught exception \"%s\" when connecting from client-ext library to DCM daemon", ex.what());
+               return DCM_EXT_ERROR_SOCKET;
+       } catch(...) {
+               LOGE("Caught unknown exception when connecting from client-ext library to DCM daemon");
+               return DCM_EXT_ERROR_SOCKET;
+       }
+
+       try {
+               RequestMessage request;
+               ResponseMessage response;
+
+               auto* req = request.mutable_ext_call();
+               req->set_method_name(std::string(method_name));
+
+               if(input_data)
+                       req->set_input_data(input_data, input_len);
+
+               protobuf_sync_message_serialization(*socket).encodeMessage(request);
+               protobuf_sync_message_deserialization(*socket).decodeMessage(response);
+
+               if(!response.has_ext_call()) {
+                       LOGE("Response for ext-api malformed, exiting");
+                       return DCM_EXT_ERROR_UNKNOWN;
+               }
+
+               auto& ext_resp(response.ext_call());
+
+               if(ext_resp.result() != DCM_EXT_ERROR_NONE) {
+                       switch(ext_resp.result()) {
+                               case DCM_EXT_ERROR_INVALID_PARAMETER:
+                               case DCM_EXT_ERROR_OUT_OF_MEMORY:
+                               case DCM_EXT_ERROR_PERMISSION_DENIED:
+                               case DCM_EXT_ERROR_NOT_SUPPORTED:
+                               case DCM_EXT_ERROR_UNKNOWN:
+                               case DCM_EXT_ERROR_SOCKET:
+                                       LOGE("Ext API call received error %d", ext_resp.result());
+                                       return ext_resp.result();
+                               default:
+                                       LOGE("Ext API call received non-standard error %d", ext_resp.result());
+                                       return DCM_EXT_ERROR_UNKNOWN;
+                       }
+               }
+
+               const auto& out = ext_resp.output_data();
+
+               if(!out.empty()) {
+                       if(!output_data || !output_len) {
+                               LOGE("Daemon returned response but ext_call API didn't get buffer pointers to return it");
+                               socket.reset();
+                               return DCM_EXT_ERROR_INVALID_PARAMETER;
+                       }
+
+                       *output_data = (char*) malloc(sizeof(char) * out.size());
+
+                       if(*output_data == NULL) {
+                               LOGE("Can't allocate enough memory for response from ext API call - required buffer in bytes: %d", out.size());
+                               socket.reset();
+                               return DCM_EXT_ERROR_OUT_OF_MEMORY;
+                       }
+
+                       memcpy(*output_data, out.c_str(), out.size());
+                       *output_len = out.size();
+               }
+       } catch(std::exception& ex) {
+               LOGE("Caught exception \"%s\" when connecting from client-ext library to DCM daemon", ex.what());
+               socket.reset();
+               return DCM_EXT_ERROR_SOCKET;
+       } catch(...) {
+               LOGE("Caught unknown exception when connecting from client-ext library to DCM daemon");
+               socket.reset();
+               return DCM_EXT_ERROR_SOCKET;
+       }
+
+       return DCM_EXT_ERROR_NONE;
 }
index 3a9038a..6c79749 100644 (file)
@@ -50,6 +50,9 @@ int dcm_ext_backend_call_api(const std::string& method_name,
  * Returns 0 in case of success or other code in case of error.
  *
  * This function should not throw exceptions.
+ *
+ * Nonzero error code returned by function will be treated as invalid
+ * method name (and returned to DCM EXT client as invalid parameter error).
  */
 API_DCM_EXT_BACKEND_EXPORT
 int dcm_ext_backend_get_api_privilege(const std::string& method_name,