Detach server-client interface on RMI
authorSangwan Kwon <sangwan.kwon@samsung.com>
Thu, 2 Jan 2020 05:57:05 +0000 (14:57 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Mon, 6 Jan 2020 10:00:56 +0000 (19:00 +0900)
This is for supporting both general service and on-demand service.

Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
14 files changed:
src/vist/rmi/CMakeLists.txt
src/vist/rmi/gateway.cpp
src/vist/rmi/impl/general/client.hpp [new file with mode: 0644]
src/vist/rmi/impl/general/protocol.cpp [new file with mode: 0644]
src/vist/rmi/impl/general/protocol.hpp [new file with mode: 0644]
src/vist/rmi/impl/general/server.hpp [new file with mode: 0644]
src/vist/rmi/impl/general/tests/protocol.cpp [new file with mode: 0644]
src/vist/rmi/impl/general/tests/server-client.cpp [new file with mode: 0644]
src/vist/rmi/impl/protocol.cpp [deleted file]
src/vist/rmi/impl/protocol.hpp [deleted file]
src/vist/rmi/impl/server.hpp
src/vist/rmi/impl/tests/protocol.cpp [deleted file]
src/vist/rmi/impl/tests/server-client.cpp [deleted file]
src/vist/rmi/remote.cpp

index f0c81e0d020651966f2ad1044a75c1efc53a86ec..833d53c012d21bea9ec96958cee0a00b526a1077 100644 (file)
@@ -16,7 +16,7 @@ SET(TARGET vist-rmi)
 SET(${TARGET}_SRCS gateway.cpp
                                   remote.cpp
                                   message.cpp
-                                  impl/protocol.cpp)
+                                  impl/general/protocol.cpp)
 
 ADD_LIBRARY(${TARGET} SHARED ${${TARGET}_SRCS})
 SET_TARGET_PROPERTIES(${TARGET} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
@@ -41,5 +41,5 @@ TARGET_LINK_LIBRARIES(${TARGET} ${TARGET_VIST_COMMON_LIB}
 FILE(GLOB RMI_TESTS "tests/*.cpp")
 ADD_VIST_TEST(${RMI_TESTS})
 
-FILE(GLOB RMI_IMPL_TESTS "impl/tests/*.cpp")
-ADD_VIST_TEST(${RMI_IMPL_TESTS})
+FILE(GLOB RMI_GENERAL_TESTS "impl/general/tests/*.cpp")
+ADD_VIST_TEST(${RMI_GENERAL_TESTS})
index e9fbdb8c6e3328d31b76af6f23e05f745872a92e..1d8bc448a9b21804f7375b69db5a1a2bac94fa44 100644 (file)
@@ -19,6 +19,7 @@
 #include <vist/exception.hpp>
 #include <vist/rmi/message.hpp>
 #include <vist/rmi/impl/server.hpp>
+#include <vist/rmi/impl/general/server.hpp>
 
 #include <string>
 
@@ -48,7 +49,7 @@ public:
                        return reply;
                };
 
-               this->server = std::make_unique<Server>(path, dispatcher);
+               this->server = std::make_unique<general::Server>(path, dispatcher);
        }
 
        inline void start()
@@ -62,7 +63,7 @@ public:
        }
 
 private:
-       std::unique_ptr<Server> server;
+       std::unique_ptr<impl::Server> server;
 };
 
 Gateway::Gateway(const std::string& path) : pImpl(std::make_unique<Impl>(*this, path))
diff --git a/src/vist/rmi/impl/general/client.hpp b/src/vist/rmi/impl/general/client.hpp
new file mode 100644 (file)
index 0000000..920ca86
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#pragma once
+
+#include "protocol.hpp"
+
+#include <vist/exception.hpp>
+#include <vist/logger.hpp>
+
+namespace vist {
+namespace rmi {
+namespace impl {
+namespace general {
+
+using boost::asio::local::stream_protocol;
+
+class Client {
+public:
+       Client(const std::string& path) : socket(this->context)
+       {
+               try {
+                       this->socket.connect(Protocol::Endpoint(path));
+               }  catch(const std::exception& e) {
+                       ERROR(VIST) << "Failed to connect socket: " << e.what();
+                       std::rethrow_exception(std::current_exception());
+               }
+       }
+
+       inline Message request(Message& message)
+       {
+               return Protocol::Request(this->socket, message);
+       }
+
+private:
+       Protocol::Context context;
+       Protocol::Socket socket;
+};
+
+} // namespace general
+} // namespace impl
+} // namespace rmi
+} // namespace vist
diff --git a/src/vist/rmi/impl/general/protocol.cpp b/src/vist/rmi/impl/general/protocol.cpp
new file mode 100644 (file)
index 0000000..c80394e
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include "protocol.hpp"
+
+#include <vist/exception.hpp>
+#include <vist/logger.hpp>
+
+namespace vist {
+namespace rmi {
+namespace impl {
+namespace general {
+
+Message Protocol::Recv(Socket& socket)
+{
+       DEBUG(VIST) << "Socket read event occured.";
+       Message::Header header;
+       const auto& headerBuffer = boost::asio::buffer(&header, sizeof(Message::Header));
+       auto readen = boost::asio::read(socket, headerBuffer);
+       if (readen != sizeof(Message::Header))
+               THROW(ErrCode::ProtocolBroken) << "Failed to receive message header.";
+
+       Message content(header);
+       const auto& contentBuffer = boost::asio::buffer(content.getBuffer());
+       readen = boost::asio::read(socket, contentBuffer);
+       if (readen != content.size())
+               THROW(ErrCode::ProtocolBroken) << "Failed to receive message content.";
+
+       content.disclose(content.signature);
+
+       return content;
+}
+
+void Protocol::Send(Socket& socket, Message& message)
+{ 
+       DEBUG(VIST) << "Socket write event occured.";
+       const auto& headerBuffer = boost::asio::buffer(&message.header,
+                                                                                                  sizeof(Message::Header));
+       auto written = boost::asio::write(socket, headerBuffer);
+       if (written != sizeof(Message::Header))
+               THROW(ErrCode::ProtocolBroken) << "Failed to send message header.";
+
+       const auto& contentBuffer = boost::asio::buffer(message.getBuffer(), message.size());
+       written = boost::asio::write(socket, contentBuffer);
+       if (written != message.size())
+               THROW(ErrCode::ProtocolBroken) << "Failed to send message content.";
+}
+
+Message Protocol::Request(Socket& socket, Message& message)
+{
+       Protocol::Send(socket, message);
+       return Protocol::Recv(socket);
+}
+
+void Protocol::Async::dispatch(const Task& task)
+{
+       auto self = shared_from_this();
+       const auto& header = boost::asio::buffer(&this->message.header,
+                                                                                        sizeof(Message::Header));
+       auto handler = [self, task](const auto& error, std::size_t size) {
+               if (error) {
+                       if (error == boost::asio::error::eof) {
+                               DEBUG(VIST) << "Socket EoF event occured.";
+                               return;
+                       } else {
+                               THROW(ErrCode::RuntimeError) << error.message();
+                       }
+               }
+
+               if (size != sizeof(Message::Header))
+                       THROW(ErrCode::ProtocolBroken) << error.message();
+
+               /// Resize message buffer to revieved header length.
+               self->message.resize(self->message.size());
+
+               const auto& contentBuffer = boost::asio::buffer(self->message.getBuffer());
+               auto readen = boost::asio::read(self->socket, contentBuffer);
+               if (readen != self->message.size())
+                       THROW(ErrCode::ProtocolBroken) << "Failed to receive message content."
+                               << readen << ", " << self->message.size();
+
+               self->message.disclose(self->message.signature);
+               self->process(task);
+       };
+
+       boost::asio::async_read(self->socket, header, handler);
+}
+
+void Protocol::Async::process(const Task& task)
+{
+       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));
+       auto handler = [self, task](const auto& error, std::size_t size) {
+               if (error || size != sizeof(Message::Header))
+                       THROW(ErrCode::ProtocolBroken) << "Failed to send message header: "
+                                                                                  << error.message();
+
+               const auto& contentBuffer = boost::asio::buffer(self->message.getBuffer());
+               auto written = boost::asio::write(self->socket, contentBuffer);
+               if (written != self->message.size())
+                       THROW(ErrCode::ProtocolBroken) << "Failed to send message content.";
+
+               /// Re-dispatch for next request.
+               self->dispatch(task);
+       };
+
+       boost::asio::async_write(self->socket, headerBuffer, handler);
+}
+
+} // namespace general
+} // namespace impl
+} // namespace rmi
+} // namespace vist
diff --git a/src/vist/rmi/impl/general/protocol.hpp b/src/vist/rmi/impl/general/protocol.hpp
new file mode 100644 (file)
index 0000000..613af2c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#pragma once
+
+#include <vist/rmi/message.hpp>
+#include <vist/rmi/impl/server.hpp>
+
+#include <boost/asio.hpp>
+
+namespace vist {
+namespace rmi {
+namespace impl {
+namespace general {
+
+struct Protocol {
+       using Acceptor = boost::asio::local::stream_protocol::acceptor;
+       using Context = boost::asio::io_service;
+       using Endpoint = boost::asio::local::stream_protocol::endpoint;
+       using Socket = boost::asio::local::stream_protocol::socket;
+
+       static Message Recv(Socket& socket);
+       static void Send(Socket& socket, Message& message);
+
+       static Message Request(Socket& socket, Message& message);
+
+       /// Passing shared_from_this() to lambda() guarantees
+       /// that the lambda() always refer to a live object.
+       class Async : public std::enable_shared_from_this<Async> {
+       public:
+               explicit Async(Context& context) : socket(context) {}
+               void dispatch(const Task& task);
+               void process(const Task& task);
+
+               inline Socket& getSocket()
+               {
+                       return this->socket;
+               }
+
+       private:
+               Message message; 
+               Socket socket;
+       };
+};
+
+} // namespace general
+} // namespace impl
+} // namespace rmi
+} // namespace vist
diff --git a/src/vist/rmi/impl/general/server.hpp b/src/vist/rmi/impl/general/server.hpp
new file mode 100644 (file)
index 0000000..690f9dd
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#pragma once
+
+#include "protocol.hpp"
+
+#include <vist/exception.hpp>
+#include <vist/logger.hpp>
+
+#include <chrono>
+#include <memory>
+#include <thread>
+
+#include <errno.h>
+#include <unistd.h>
+
+namespace vist {
+namespace rmi {
+namespace impl {
+namespace general {
+
+class Server : public impl::Server {
+public:
+       Server(const std::string& path, const Task& task) : impl::Server(path, task)
+       {
+               errno = 0;
+               if (::unlink(path.c_str()) == -1 && errno != ENOENT)
+                       THROW(ErrCode::RuntimeError) << "Failed to remove file."; 
+
+               this->acceptor = std::make_unique<Protocol::Acceptor>(this->context,
+                                                                                                                         Protocol::Endpoint(path));
+               this->accept(task);
+       }
+       virtual ~Server() = default;
+
+       Server(const Server&) = delete;
+       Server& operator=(const Server&) = delete;
+
+       Server(Server&&) = default;
+       Server& operator=(Server&&) = default;
+
+       void run() override
+       {
+               this->context.run();
+       }
+
+       void stop() override
+       {
+               this->context.stop();
+       }
+
+private:
+       void accept(const Task& task) override
+       {
+               auto asyncSession = std::make_shared<Protocol::Async>(this->context);
+               auto handler = [this, asyncSession, task](const auto& error) {
+                       DEBUG(VIST) << "New session is accepted.";
+
+                       if (error)
+                               THROW(ErrCode::RuntimeError) << error.message();
+
+                       asyncSession->dispatch(task);
+
+                       this->accept(task);
+               };
+               this->acceptor->async_accept(asyncSession->getSocket(), handler);
+       }
+
+       Protocol::Context context;
+       std::unique_ptr<Protocol::Acceptor> acceptor;
+};
+
+} // namespace general
+} // namespace impl
+} // namespace rmi
+} // namespace vist
diff --git a/src/vist/rmi/impl/general/tests/protocol.cpp b/src/vist/rmi/impl/general/tests/protocol.cpp
new file mode 100644 (file)
index 0000000..a67d7d5
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include <vist/rmi/message.hpp>
+#include <vist/rmi/impl/general/protocol.hpp>
+
+#include <string>
+#include <thread>
+
+#include <gtest/gtest.h>
+#include <boost/asio.hpp>
+
+#include <unistd.h>
+
+using namespace vist::rmi;
+using namespace vist::rmi::impl::general;
+using boost::asio::local::stream_protocol;
+
+namespace {
+
+/// Request variables
+std::string requestSignature = "request signature";
+int request1 = 100;
+bool request2 = true;
+std::string request3 = "request argument";
+
+/// Response variables
+std::string responseSignature = "response signature";
+int response1 = 300;
+bool response2 = false;
+std::string response3 = "response argument";
+
+} // anonymous namespace
+
+TEST(ProtocolTests, sync_server_sync_client)
+{
+       std::string sockPath = "vist-test.sock";
+       ::unlink(sockPath.c_str());
+
+       /// Server configuration
+       boost::asio::io_service context;
+       stream_protocol::acceptor acceptor(context, stream_protocol::endpoint(sockPath));
+       stream_protocol::socket sock(context);
+
+       auto handler = [&](const auto& error) {
+               EXPECT_EQ(error, boost::system::errc::success);
+
+               Message request = Protocol::Recv(sock);
+               EXPECT_EQ(request.signature, requestSignature);
+
+               int recv1;
+               bool recv2;
+               std::string recv3;
+               request.disclose(recv1, recv2, recv3);
+               EXPECT_EQ(request1, recv1);
+               EXPECT_EQ(request2, recv2);
+               EXPECT_EQ(request3, recv3);
+
+               Message reply(Message::Type::Reply, responseSignature);
+               reply.enclose(response1, response2, response3);
+               Protocol::Send(sock, reply);
+       };
+       acceptor.async_accept(sock, handler);
+
+       auto serverThread = std::thread([&]() {
+               context.run(); 
+       });
+
+       { /// Client configuration
+               boost::asio::io_service context;
+               stream_protocol::socket sock(context);
+               sock.connect(stream_protocol::endpoint(sockPath));
+
+               Message request(Message::Type::MethodCall, requestSignature);
+               request.enclose(request1, request2, request3);
+
+               auto reply = Protocol::Request(sock, request);
+               EXPECT_EQ(reply.signature, responseSignature);
+
+               int recv1;
+               bool recv2;
+               std::string recv3;
+               reply.disclose(recv1, recv2, recv3);
+               EXPECT_EQ(response1, recv1);
+               EXPECT_EQ(response2, recv2);
+               EXPECT_EQ(response3, recv3);
+       }
+
+       context.stop();
+
+       if (serverThread.joinable())
+               serverThread.join();
+}
+
+TEST(ProtocolTests, async_server_sync_client)
+{
+       std::string sockPath = "vist-test.sock";
+       ::unlink(sockPath.c_str());
+
+       /// Server configuration
+       boost::asio::io_service context;
+       stream_protocol::acceptor acceptor(context, stream_protocol::endpoint(sockPath));
+
+       auto async = std::make_shared<Protocol::Async>(context);
+       auto handler = [&](const auto& error) {
+               EXPECT_EQ(error, boost::system::errc::success);
+               auto task = [&](auto& message) -> Message {
+                       EXPECT_EQ(message.signature, requestSignature);
+
+                       int recv1;
+                       bool recv2;
+                       std::string recv3;
+                       message.disclose(recv1, recv2, recv3);
+                       EXPECT_EQ(request1, recv1);
+                       EXPECT_EQ(request2, recv2);
+                       EXPECT_EQ(request3, recv3);
+
+                       Message reply(Message::Type::Reply, responseSignature);
+                       reply.enclose(response1, response2, response3);
+                       return reply;
+               };
+
+               async->dispatch(task);
+       };
+       acceptor.async_accept(async->getSocket(), handler);
+
+       auto serverThread = std::thread([&]() {
+               context.run(); 
+       });
+
+       { /// Client configuration
+               boost::asio::io_service context;
+               stream_protocol::socket sock(context);
+               sock.connect(stream_protocol::endpoint(sockPath));
+
+               Message request(Message::Type::MethodCall, requestSignature);
+               request.enclose(request1, request2, request3);
+
+               auto requestClosure = [&]() {
+                       auto reply = Protocol::Request(sock, request);
+                       EXPECT_EQ(reply.signature, responseSignature);
+
+                       int recv1;
+                       bool recv2;
+                       std::string recv3;
+                       reply.disclose(recv1, recv2, recv3);
+                       EXPECT_EQ(response1, recv1);
+                       EXPECT_EQ(response2, recv2);
+                       EXPECT_EQ(response3, recv3);
+               };
+
+               for (int i = 0; i < 3; i++)
+                       requestClosure();
+       }
+
+       context.stop();
+
+       if (serverThread.joinable())
+               serverThread.join();
+}
diff --git a/src/vist/rmi/impl/general/tests/server-client.cpp b/src/vist/rmi/impl/general/tests/server-client.cpp
new file mode 100644 (file)
index 0000000..b8e0407
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include <vist/rmi/message.hpp>
+#include <vist/rmi/impl/general/server.hpp>
+#include <vist/rmi/impl/general/client.hpp>
+
+#include <string>
+#include <thread>
+
+#include <boost/asio.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace vist::rmi;
+using namespace vist::rmi::impl::general;
+using boost::asio::local::stream_protocol;
+
+namespace {
+
+/// Request variables
+std::string requestSignature = "request signature";
+int request1 = 100;
+bool request2 = true;
+std::string request3 = "request argument";
+
+/// Response variables
+std::string responseSignature = "response signature";
+int response1 = 300;
+bool response2 = false;
+std::string response3 = "response argument";
+
+} // anonymous namespace
+
+TEST(ServerClientTests, server)
+{
+       std::string sockPath = "vist-test.sock";
+
+       auto task = [&](Message& message) -> Message {
+               EXPECT_EQ(message.signature, requestSignature);
+
+               int recv1;
+               bool recv2;
+               std::string recv3;
+               message.disclose(recv1, recv2, recv3);
+               EXPECT_EQ(request1, recv1);
+               EXPECT_EQ(request2, recv2);
+               EXPECT_EQ(request3, recv3);
+
+               Message reply(Message::Type::Reply, responseSignature);
+               reply.enclose(response1, response2, response3);
+               return reply;
+       };
+
+       Server server(sockPath, task); 
+       auto serverThread = std::thread([&]() {
+               server.run(); 
+       });
+
+       { /// Client configuration
+               auto clientClosure = [&]() {
+                       Client client(sockPath);
+
+                       Message message(Message::Type::MethodCall, requestSignature);
+                       message.enclose(request1, request2, request3);
+
+                       for (int i = 0; i < 3; i++) {
+                               auto reply = client.request(message);
+                               EXPECT_EQ(reply.signature, responseSignature);
+
+                               int recv1;
+                               bool recv2;
+                               std::string recv3;
+                               reply.disclose(recv1, recv2, recv3);
+                               EXPECT_EQ(response1, recv1);
+                               EXPECT_EQ(response2, recv2);
+                               EXPECT_EQ(response3, recv3);
+                       }
+               };
+
+               for (int i = 0; i < 3; i++)
+                       clientClosure();
+       }
+
+       server.stop();
+
+       if (serverThread.joinable())
+               serverThread.join();
+}
diff --git a/src/vist/rmi/impl/protocol.cpp b/src/vist/rmi/impl/protocol.cpp
deleted file mode 100644 (file)
index 70e1cb4..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *  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.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-
-#include "protocol.hpp"
-
-#include <vist/exception.hpp>
-#include <vist/logger.hpp>
-
-namespace vist {
-namespace rmi {
-namespace impl {
-
-Message Protocol::Recv(Socket& socket)
-{
-       DEBUG(VIST) << "Socket read event occured.";
-       Message::Header header;
-       const auto& headerBuffer = boost::asio::buffer(&header, sizeof(Message::Header));
-       auto readen = boost::asio::read(socket, headerBuffer);
-       if (readen != sizeof(Message::Header))
-               THROW(ErrCode::ProtocolBroken) << "Failed to receive message header.";
-
-       Message content(header);
-       const auto& contentBuffer = boost::asio::buffer(content.getBuffer());
-       readen = boost::asio::read(socket, contentBuffer);
-       if (readen != content.size())
-               THROW(ErrCode::ProtocolBroken) << "Failed to receive message content.";
-
-       content.disclose(content.signature);
-
-       return content;
-}
-
-void Protocol::Send(Socket& socket, Message& message)
-{ 
-       DEBUG(VIST) << "Socket write event occured.";
-       const auto& headerBuffer = boost::asio::buffer(&message.header,
-                                                                                                  sizeof(Message::Header));
-       auto written = boost::asio::write(socket, headerBuffer);
-       if (written != sizeof(Message::Header))
-               THROW(ErrCode::ProtocolBroken) << "Failed to send message header.";
-
-       const auto& contentBuffer = boost::asio::buffer(message.getBuffer(), message.size());
-       written = boost::asio::write(socket, contentBuffer);
-       if (written != message.size())
-               THROW(ErrCode::ProtocolBroken) << "Failed to send message content.";
-}
-
-Message Protocol::Request(Socket& socket, Message& message)
-{
-       Protocol::Send(socket, message);
-       return Protocol::Recv(socket);
-}
-
-void Protocol::Async::dispatch(const Task& task)
-{
-       auto self = shared_from_this();
-       const auto& header = boost::asio::buffer(&this->message.header,
-                                                                                        sizeof(Message::Header));
-       auto handler = [self, task](const auto& error, std::size_t size) {
-               if (error) {
-                       if (error == boost::asio::error::eof) {
-                               DEBUG(VIST) << "Socket EoF event occured.";
-                               return;
-                       } else {
-                               THROW(ErrCode::RuntimeError) << error.message();
-                       }
-               }
-
-               if (size != sizeof(Message::Header))
-                       THROW(ErrCode::ProtocolBroken) << error.message();
-
-               /// Resize message buffer to revieved header length.
-               self->message.resize(self->message.size());
-
-               const auto& contentBuffer = boost::asio::buffer(self->message.getBuffer());
-               auto readen = boost::asio::read(self->socket, contentBuffer);
-               if (readen != self->message.size())
-                       THROW(ErrCode::ProtocolBroken) << "Failed to receive message content."
-                               << readen << ", " << self->message.size();
-
-               self->message.disclose(self->message.signature);
-               self->process(task);
-       };
-
-       boost::asio::async_read(self->socket, header, handler);
-}
-
-void Protocol::Async::process(const Task& task)
-{
-       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));
-       auto handler = [self, task](const auto& error, std::size_t size) {
-               if (error || size != sizeof(Message::Header))
-                       THROW(ErrCode::ProtocolBroken) << "Failed to send message header: "
-                                                                                  << error.message();
-
-               const auto& contentBuffer = boost::asio::buffer(self->message.getBuffer());
-               auto written = boost::asio::write(self->socket, contentBuffer);
-               if (written != self->message.size())
-                       THROW(ErrCode::ProtocolBroken) << "Failed to send message content.";
-
-               /// Re-dispatch for next request.
-               self->dispatch(task);
-       };
-
-       boost::asio::async_write(self->socket, headerBuffer, handler);
-}
-
-} // namespace impl
-} // namespace rmi
-} // namespace vist
diff --git a/src/vist/rmi/impl/protocol.hpp b/src/vist/rmi/impl/protocol.hpp
deleted file mode 100644 (file)
index eff3505..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  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.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-
-#pragma once
-
-#include <vist/rmi/message.hpp>
-
-#include <functional>
-
-#include <boost/asio.hpp>
-
-namespace vist {
-namespace rmi {
-namespace impl {
-
-struct Protocol {
-       using Acceptor = boost::asio::local::stream_protocol::acceptor;
-       using Context = boost::asio::io_service;
-       using Endpoint = boost::asio::local::stream_protocol::endpoint;
-       using Socket = boost::asio::local::stream_protocol::socket;
-       using Task = std::function<Message(Message&)>;
-
-       static Message Recv(Socket& socket);
-       static void Send(Socket& socket, Message& message);
-
-       static Message Request(Socket& socket, Message& message);
-
-       /// Passing shared_from_this() to lambda() guarantees
-       /// that the lambda() always refer to a live object.
-       class Async : public std::enable_shared_from_this<Async> {
-       public:
-               explicit Async(Context& context) : socket(context) {}
-               void dispatch(const Task& task);
-               void process(const Task& task);
-
-               inline Socket& getSocket()
-               {
-                       return this->socket;
-               }
-
-       private:
-               Message message; 
-               Socket socket;
-       };
-};
-
-} // namespace impl
-} // namespace rmi
-} // namespace vist
index 098e69db379b38be775446a77211fb903d3a9006..3e5d5907111dc5c1ea47086c5ca78243288af689 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2020 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.
 
 #pragma once
 
-#include "protocol.hpp"
+#include <vist/rmi/message.hpp>
 
-#include <vist/exception.hpp>
-#include <vist/logger.hpp>
-
-#include <chrono>
-#include <memory>
-#include <thread>
-
-#include <errno.h>
-#include <unistd.h>
+#include <functional>
 
 namespace vist {
 namespace rmi {
 namespace impl {
 
+using Task = std::function<Message(Message&)>;
+
 class Server {
 public:
-       Server(const std::string& path, const Protocol::Task& task)
-       {
-               errno = 0;
-               if (::unlink(path.c_str()) == -1 && errno != ENOENT)
-                       THROW(ErrCode::RuntimeError) << "Failed to remove file."; 
-
-               this->acceptor = std::make_unique<Protocol::Acceptor>(this->context,
-                                                                                                                         Protocol::Endpoint(path));
-               this->accept(task);
-       }
-
-       inline void accept(const Protocol::Task& task)
-       {
-               auto asyncSession = std::make_shared<Protocol::Async>(this->context);
-               auto handler = [this, asyncSession, task](const auto& error) {
-                       DEBUG(VIST) << "New session is accepted.";
-
-                       if (error)
-                               THROW(ErrCode::RuntimeError) << error.message();
-
-                       asyncSession->dispatch(task);
+       Server(const std::string&, const Task&) {}
+       virtual ~Server() = default;
 
-                       this->accept(task);
-               };
-               this->acceptor->async_accept(asyncSession->getSocket(), handler);
-       }
+       Server(const Server&) = delete;
+       Server& operator=(const Server&) = delete;
 
-       inline void run()
-       {
-               this->context.run();
-       }
+       Server(Server&&) = default;
+       Server& operator=(Server&&) = default;
 
-       inline void stop()
-       {
-               this->context.stop();
-       }
+       virtual void run() = 0;
+       virtual void stop() = 0;
 
 private:
-       Protocol::Context context;
-       std::unique_ptr<Protocol::Acceptor> acceptor;
+       virtual void accept(const Task& task) = 0;
 };
 
 } // namespace impl
diff --git a/src/vist/rmi/impl/tests/protocol.cpp b/src/vist/rmi/impl/tests/protocol.cpp
deleted file mode 100644 (file)
index 5e03689..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- *  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.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-
-#include <vist/rmi/message.hpp>
-#include <vist/rmi/impl/protocol.hpp>
-
-#include <string>
-#include <thread>
-
-#include <gtest/gtest.h>
-#include <boost/asio.hpp>
-
-#include <unistd.h>
-
-using namespace vist::rmi;
-using namespace vist::rmi::impl;
-using boost::asio::local::stream_protocol;
-
-namespace {
-
-/// Request variables
-std::string requestSignature = "request signature";
-int request1 = 100;
-bool request2 = true;
-std::string request3 = "request argument";
-
-/// Response variables
-std::string responseSignature = "response signature";
-int response1 = 300;
-bool response2 = false;
-std::string response3 = "response argument";
-
-} // anonymous namespace
-
-TEST(ProtocolTests, sync_server_sync_client)
-{
-       std::string sockPath = "vist-test.sock";
-       ::unlink(sockPath.c_str());
-
-       /// Server configuration
-       boost::asio::io_service context;
-       stream_protocol::acceptor acceptor(context, stream_protocol::endpoint(sockPath));
-       stream_protocol::socket sock(context);
-
-       auto handler = [&](const auto& error) {
-               EXPECT_EQ(error, boost::system::errc::success);
-
-               Message request = Protocol::Recv(sock);
-               EXPECT_EQ(request.signature, requestSignature);
-
-               int recv1;
-               bool recv2;
-               std::string recv3;
-               request.disclose(recv1, recv2, recv3);
-               EXPECT_EQ(request1, recv1);
-               EXPECT_EQ(request2, recv2);
-               EXPECT_EQ(request3, recv3);
-
-               Message reply(Message::Type::Reply, responseSignature);
-               reply.enclose(response1, response2, response3);
-               Protocol::Send(sock, reply);
-       };
-       acceptor.async_accept(sock, handler);
-
-       auto serverThread = std::thread([&]() {
-               context.run(); 
-       });
-
-       { /// Client configuration
-               boost::asio::io_service context;
-               stream_protocol::socket sock(context);
-               sock.connect(stream_protocol::endpoint(sockPath));
-
-               Message request(Message::Type::MethodCall, requestSignature);
-               request.enclose(request1, request2, request3);
-
-               auto reply = Protocol::Request(sock, request);
-               EXPECT_EQ(reply.signature, responseSignature);
-
-               int recv1;
-               bool recv2;
-               std::string recv3;
-               reply.disclose(recv1, recv2, recv3);
-               EXPECT_EQ(response1, recv1);
-               EXPECT_EQ(response2, recv2);
-               EXPECT_EQ(response3, recv3);
-       }
-
-       context.stop();
-
-       if (serverThread.joinable())
-               serverThread.join();
-}
-
-TEST(ProtocolTests, async_server_sync_client)
-{
-       std::string sockPath = "vist-test.sock";
-       ::unlink(sockPath.c_str());
-
-       /// Server configuration
-       boost::asio::io_service context;
-       stream_protocol::acceptor acceptor(context, stream_protocol::endpoint(sockPath));
-
-       auto async = std::make_shared<Protocol::Async>(context);
-       auto handler = [&](const auto& error) {
-               EXPECT_EQ(error, boost::system::errc::success);
-               auto task = [&](auto& message) -> Message {
-                       EXPECT_EQ(message.signature, requestSignature);
-
-                       int recv1;
-                       bool recv2;
-                       std::string recv3;
-                       message.disclose(recv1, recv2, recv3);
-                       EXPECT_EQ(request1, recv1);
-                       EXPECT_EQ(request2, recv2);
-                       EXPECT_EQ(request3, recv3);
-
-                       Message reply(Message::Type::Reply, responseSignature);
-                       reply.enclose(response1, response2, response3);
-                       return reply;
-               };
-
-               async->dispatch(task);
-       };
-       acceptor.async_accept(async->getSocket(), handler);
-
-       auto serverThread = std::thread([&]() {
-               context.run(); 
-       });
-
-       { /// Client configuration
-               boost::asio::io_service context;
-               stream_protocol::socket sock(context);
-               sock.connect(stream_protocol::endpoint(sockPath));
-
-               Message request(Message::Type::MethodCall, requestSignature);
-               request.enclose(request1, request2, request3);
-
-               auto requestClosure = [&]() {
-                       auto reply = Protocol::Request(sock, request);
-                       EXPECT_EQ(reply.signature, responseSignature);
-
-                       int recv1;
-                       bool recv2;
-                       std::string recv3;
-                       reply.disclose(recv1, recv2, recv3);
-                       EXPECT_EQ(response1, recv1);
-                       EXPECT_EQ(response2, recv2);
-                       EXPECT_EQ(response3, recv3);
-               };
-
-               for (int i = 0; i < 3; i++)
-                       requestClosure();
-       }
-
-       context.stop();
-
-       if (serverThread.joinable())
-               serverThread.join();
-}
diff --git a/src/vist/rmi/impl/tests/server-client.cpp b/src/vist/rmi/impl/tests/server-client.cpp
deleted file mode 100644 (file)
index 17058cb..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *  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.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-
-#include <vist/rmi/message.hpp>
-#include <vist/rmi/impl/server.hpp>
-#include <vist/rmi/impl/client.hpp>
-
-#include <string>
-#include <thread>
-
-#include <boost/asio.hpp>
-
-#include <gtest/gtest.h>
-
-using namespace vist::rmi;
-using namespace vist::rmi::impl;
-using boost::asio::local::stream_protocol;
-
-namespace {
-
-/// Request variables
-std::string requestSignature = "request signature";
-int request1 = 100;
-bool request2 = true;
-std::string request3 = "request argument";
-
-/// Response variables
-std::string responseSignature = "response signature";
-int response1 = 300;
-bool response2 = false;
-std::string response3 = "response argument";
-
-} // anonymous namespace
-
-TEST(ServerClientTests, server)
-{
-       std::string sockPath = "vist-test.sock";
-
-       auto task = [&](Message& message) -> Message {
-               EXPECT_EQ(message.signature, requestSignature);
-
-               int recv1;
-               bool recv2;
-               std::string recv3;
-               message.disclose(recv1, recv2, recv3);
-               EXPECT_EQ(request1, recv1);
-               EXPECT_EQ(request2, recv2);
-               EXPECT_EQ(request3, recv3);
-
-               Message reply(Message::Type::Reply, responseSignature);
-               reply.enclose(response1, response2, response3);
-               return reply;
-       };
-
-       Server server(sockPath, task); 
-       auto serverThread = std::thread([&]() {
-               server.run(); 
-       });
-
-       { /// Client configuration
-               auto clientClosure = [&]() {
-                       Client client(sockPath);
-
-                       Message message(Message::Type::MethodCall, requestSignature);
-                       message.enclose(request1, request2, request3);
-
-                       for (int i = 0; i < 3; i++) {
-                               auto reply = client.request(message);
-                               EXPECT_EQ(reply.signature, responseSignature);
-
-                               int recv1;
-                               bool recv2;
-                               std::string recv3;
-                               reply.disclose(recv1, recv2, recv3);
-                               EXPECT_EQ(response1, recv1);
-                               EXPECT_EQ(response2, recv2);
-                               EXPECT_EQ(response3, recv3);
-                       }
-               };
-
-               for (int i = 0; i < 3; i++)
-                       clientClosure();
-       }
-
-       server.stop();
-
-       if (serverThread.joinable())
-               serverThread.join();
-}
index d2ff1e689c7a130ef51be96b11eba8ce707ad31a..575a987db25b1a8afb55c3b10b27101570becd50 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "remote.hpp"
 
-#include <vist/rmi/impl/client.hpp>
+#include <vist/rmi/impl/general/client.hpp>
 
 #include <string>
 #include <mutex>
@@ -24,7 +24,7 @@
 namespace vist {
 namespace rmi {
 
-using namespace vist::rmi::impl;
+using namespace vist::rmi::impl::general;
 
 class Remote::Impl {
 public: