Enhance error handling on RMI
authorSangwan Kwon <sangwan.kwon@samsung.com>
Fri, 13 Dec 2019 06:04:33 +0000 (15:04 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Tue, 17 Dec 2019 01:42:45 +0000 (10:42 +0900)
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/vist/rmi/exposer.cpp
src/vist/rmi/remote.hpp
src/vist/rmi/tests/rmi.cpp
src/vist/transport/message.cpp
src/vist/transport/message.hpp
src/vist/transport/protocol.cpp

index 603a476ffd70ddebc31f85ff0564756d76872a2b..3c2a66b596571f1663c4badb959164e1a6143e70 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "exposer.hpp"
 
+#include <vist/exception.hpp>
 #include <vist/transport/message.hpp>
 #include <vist/transport/server.hpp>
 
@@ -40,7 +41,7 @@ public:
                        std::string function = message.signature;
                        auto iter = exposer.functorMap.find(function);
                        if (iter == exposer.functorMap.end())
-                               THROW(ErrCode::RuntimeError) << "Faild to find function.";
+                               THROW(ErrCode::ProtocolBroken) << "Not found function: " << function;
 
                        DEBUG(VIST) << "Remote method invokation: " << function;
 
index 63d131616174937c27420773f3e450ce2097cb7e..9a1206a7f6c74407e751a88fef7ecad9228acfd6 100644 (file)
@@ -22,6 +22,7 @@
 
 #pragma once
 
+#include <vist/exception.hpp>
 #include <vist/transport/message.hpp>
 
 #include <string>
@@ -60,6 +61,9 @@ R Remote::invoke(const std::string& method, Args&&... args)
        message.enclose(std::forward<Args>(args)...);
 
        Message reply = this->request(message);
+       if (reply.error())
+               THROW(ErrCode::RuntimeError) << reply.what();
+
        R result;
        reply.disclose(result);
 
index 61606b50f123a6182ebe1dff6313acd2f56bc46e..08eb727128f9aa6e0a27073968bc444c78644cd4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  See the License for the specific language governing permissions and
  *  limitations under the License
  */
+/*
+ * @file   rmi.cpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief  Testcases of rmi.
+ */
+
 
 #include <vist/rmi/exposer.hpp>
 #include <vist/rmi/remote.hpp>
@@ -42,6 +48,13 @@ struct Foo {
        std::string name;
 };
 
+struct Bar {
+       int plusTwo(int number)
+       {
+               return number + 2;
+       }
+};
+
 TEST(RmiTests, positive)
 {
        std::string sockPath = ("/tmp/test-exposer");
@@ -53,6 +66,9 @@ TEST(RmiTests, positive)
        exposer.expose(foo, "Foo::setName", &Foo::setName);
        exposer.expose(foo, "Foo::getName", &Foo::getName);
 
+       auto bar = std::make_shared<Bar>();
+       exposer.expose(bar, "Bar::plusTwo", &Bar::plusTwo);
+
        auto client = std::thread([&]() {
                // caller-side
                Remote remote(sockPath);
@@ -64,6 +80,39 @@ TEST(RmiTests, positive)
                std::string name = remote.invoke<std::string>("Foo::getName");
                EXPECT_EQ(name, param);
 
+               int num = remote.invoke<int>("Bar::plusTwo", 3);
+               EXPECT_EQ(num, 5);
+
+               exposer.stop();
+       });
+
+       exposer.start();
+
+       if (client.joinable())
+               client.join();
+}
+
+TEST(RmiTests, not_exist_method)
+{
+       std::string sockPath = ("/tmp/test-exposer");
+
+       // exposer-side
+       Exposer exposer(sockPath);
+
+       auto client = std::thread([&]() {
+               // caller-side
+               Remote remote(sockPath);
+
+               std::string param = "RMI-TEST";
+
+               bool rasied = false;
+               try {
+                       remote.invoke<bool>("Foo::NotExist", param);
+               } catch (const std::exception& e) {
+                       rasied = true;
+               }
+               EXPECT_TRUE(rasied);
+
                exposer.stop();
        });
 
index 7f750437f7f4fec31bd13b58eb28ff6b7049f6bf..3153cd6f2344e15698092347fb076678a91b2b79 100644 (file)
@@ -37,6 +37,21 @@ Message::Message(Header header) : header(header)
        this->buffer.resize(this->header.length);
 }
 
+bool Message::success() const noexcept
+{
+       return !error();
+}
+
+bool Message::error() const noexcept
+{
+       return this->header.type == Type::Error;
+}
+
+std::string Message::what() const noexcept
+{
+       return this->signature;
+}
+
 std::size_t Message::size(void) const noexcept
 {
        return this->header.length;
index 4e673fade8efab4a98200696a605b3d8dc313618..55dd5b54cc783702b19bb0e38b42bea6c61eadd0 100644 (file)
@@ -62,6 +62,10 @@ struct Message final {
        template<typename... Args>
        void disclose(Args&... args);
 
+       bool success() const noexcept;
+       bool error() const noexcept;
+       std::string what() const noexcept;
+
        std::size_t size(void) const noexcept;
        void resize(std::size_t size);
        std::vector<unsigned char>& getBuffer(void) noexcept;
index c160fb4a40f0a4897e08435b19eb516f30f1725e..acc030655d3c0158ce69a8149c272612808a8516 100644 (file)
@@ -97,9 +97,27 @@ void Protocol::Async::dispatch(const Task& task)
 
 void Protocol::Async::process(const Task& task)
 {
-       auto result = task(message);
-       /// catch
-       this->message = result;
+       bool raised = false;
+       std::string errMsg;
+       auto onError = [&raised, &errMsg](const std::string& message) {
+               ERROR(VIST) << "Failed to process task: " << message;
+               raised = true;
+               errMsg = message;
+       };
+
+       try {
+               /// Process dispatched task.
+               auto result = task(message);
+               this->message = result;
+       } catch (const vist::Exception<ErrCode>& e) {
+               onError(e.what());
+       } catch (const std::exception& e) {
+               onError(e.what());
+       }
+
+       if (raised)
+               this->message = Message(Message::Type::Error, errMsg);
+
        auto self = shared_from_this();
        const auto& headerBuffer = boost::asio::buffer(&this->message.header,
                                                                                                   sizeof(Message::Header));
@@ -113,7 +131,7 @@ void Protocol::Async::process(const Task& task)
                if (written != self->message.size())
                        THROW(ErrCode::ProtocolBroken) << "Failed to send message content.";
 
-               // Re-dispatch for next request.
+               /// Re-dispatch for next request.
                self->dispatch(task);
        };