This is for supporting both general service and on-demand service.
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
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")
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})
#include <vist/exception.hpp>
#include <vist/rmi/message.hpp>
#include <vist/rmi/impl/server.hpp>
+#include <vist/rmi/impl/general/server.hpp>
#include <string>
return reply;
};
- this->server = std::make_unique<Server>(path, dispatcher);
+ this->server = std::make_unique<general::Server>(path, dispatcher);
}
inline void start()
}
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))
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
/*
- * 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
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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();
-}
#include "remote.hpp"
-#include <vist/rmi/impl/client.hpp>
+#include <vist/rmi/impl/general/client.hpp>
#include <string>
#include <mutex>
namespace vist {
namespace rmi {
-using namespace vist::rmi::impl;
+using namespace vist::rmi::impl::general;
class Remote::Impl {
public: