#include <osquery/system.h>
#include <osquery/utils/conversions/tryto.h>
+#include <osquery/logger.h>
+
namespace osquery {
FLAG(bool, enable_foreign, false, "Enable no-op foreign virtual tables");
if (document.HasParseError() || !document.IsArray())
throw std::runtime_error("Cannot parse request.");
- if (document.Size() != 1)
- throw std::runtime_error("Wrong request format.");
-
if (insert)
return std::string(document[0].GetString());
else
IF(DEFINED GBS_BUILD)
TARGET_LINK_LIBRARIES(${TARGET_VIST_COMMON_LIB} ${VIST_COMMON_DEPS_LIBRARIES}
- pthread glog gflags)
+ pthread glog gflags boost_system)
ELSE(DEFINED GBS_BUILD)
- TARGET_LINK_LIBRARIES(${TARGET_VIST_COMMON_LIB} pthread glog gflags)
+ TARGET_LINK_LIBRARIES(${TARGET_VIST_COMMON_LIB} pthread glog gflags boost_system)
ENDIF(DEFINED GBS_BUILD)
ADD_LIBRARY(${TARGET_VIST_LIB} STATIC ${${TARGET_VIST_LIB}_SRCS})
unsigned char* get(void) noexcept;
std::size_t size(void) const noexcept;
- void reserve(std::size_t size) noexcept;
+ void resize(std::size_t size);
+ std::vector<unsigned char>& getBuffer(void) noexcept;
protected:
void save(const void* bytes, std::size_t size);
#include "query.hpp"
#include <vist/logger.hpp>
-#include <vist/rmi/client.hpp>
+#include <vist/rmi/remote.hpp>
namespace {
const std::string SOCK_ADDR = "/tmp/.vist";
Rows Query::Execute(const std::string& statement)
{
INFO(VIST_CLIENT) << "Query execution: " << statement;
- rmi::Client client(SOCK_ADDR);
+ rmi::Remote remote(SOCK_ADDR);
- return client.invoke<Rows>("Vist::query", statement);
+ return remote.invoke<Rows>("Vist::query", statement);
}
} // namespace vist
return this->buffer.data();
}
+std::vector<unsigned char>& Archive::getBuffer(void) noexcept
+{
+ return this->buffer;
+}
+
std::size_t Archive::size(void) const noexcept
{
return this->buffer.size();
}
-void Archive::reserve(std::size_t size) noexcept
+void Archive::resize(std::size_t size)
{
- this->buffer.reserve(size);
+ this->buffer.resize(size);
}
void Archive::save(const void* bytes, std::size_t size)
LogicError = 0, /// Includes invalid_argument
RuntimeError,
BadCast,
- TypeUnsafed
+ TypeUnsafed,
+ ProtocolBroken
};
template <typename ErrCode>
# limitations under the License
ADD_VIST_COMMON_LIBRARY(vist_rmi client.cpp
- server.cpp)
+ server.cpp
+ exposer.cpp
+ remote.cpp)
FILE(GLOB RMI_TESTS "tests/*.cpp")
ADD_VIST_TEST(${RMI_TESTS})
--- /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
+ */
+/*
+ * @file exposer.cpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @author Jaemin Ryu (jm77.ryu@samsung.com)
+ * @brief Implementation of Server-side stub for exposing method.
+ */
+
+#include "exposer.hpp"
+
+#include <vist/transport/message.hpp>
+#include <vist/transport/server.hpp>
+
+#include <string>
+
+namespace vist {
+namespace rmi {
+
+using namespace vist::transport;
+
+class Exposer::Impl {
+public:
+ explicit Impl(Exposer& exposer, const std::string& path);
+
+ void start(void);
+ void stop(void);
+
+private:
+ std::unique_ptr<Server> server;
+};
+
+Exposer::Impl::Impl(Exposer& exposer, const std::string& path)
+{
+ auto dispatcher = [&exposer](Message message) -> Message {
+ std::string function = message.signature;
+ auto iter = exposer.functorMap.find(function);
+ if (iter == exposer.functorMap.end())
+ THROW(ErrCode::RuntimeError) << "Faild to find function.";
+
+ DEBUG(VIST) << "Remote method invokation: " << function;
+
+ auto functor = iter->second;
+ auto result = functor->invoke(message.buffer);
+
+ Message reply(Message::Type::Reply, function);
+ reply.enclose(result);
+
+ return reply;
+ };
+
+ this->server = std::make_unique<Server>(path, dispatcher);
+}
+
+void Exposer::Impl::start(void)
+{
+ this->server->run();
+}
+
+void Exposer::Impl::stop(void)
+{
+ this->server->stop();
+}
+
+Exposer::Exposer(const std::string& path) : pImpl(new Impl(*this, path))
+{
+}
+
+void Exposer::start(void)
+{
+ this->pImpl->start();
+}
+
+void Exposer::stop(void)
+{
+ this->pImpl->stop();
+}
+
+void Exposer::ImplDeleter::operator()(Impl* ptr)
+{
+ delete ptr;
+}
+
+} // 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
+ */
+/*
+ * @file exposer.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @author Jaemin Ryu (jm77.ryu@samsung.com)
+ * @brief Server-side stub for exposing method.
+ */
+
+#pragma once
+
+#include <vist/klass/functor.hpp>
+
+#include <memory>
+#include <string>
+
+namespace vist {
+namespace rmi {
+
+class Exposer final {
+public:
+ explicit Exposer(const std::string& path);
+
+ void start(void);
+ void stop(void);
+
+ template<typename O, typename F>
+ void expose(O&& object, const std::string& name, F&& func);
+
+private:
+ class Impl;
+ struct ImplDeleter
+ {
+ void operator()(Impl*);
+ };
+
+ klass::FunctorMap functorMap;
+ std::unique_ptr<Impl, ImplDeleter> pImpl;
+};
+
+template<typename O, typename F>
+void Exposer::expose(O&& object, const std::string& name, F&& func)
+{
+ auto functor = klass::make_functor_ptr(std::forward<O>(object), std::forward<F>(func));
+ this->functorMap[name] = functor;
+}
+
+} // namespace rmi
+} // namespace vist
--- /dev/null
+/*
+ * Copyright (c) 2018-present 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
+ */
+/*
+ * @file remote.cpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @author Jaemin Ryu (jm77.ryu@samsung.com)
+ * @brief Implementation of remote.
+ */
+
+#include "remote.hpp"
+
+#include <vist/transport/client.hpp>
+
+#include <string>
+#include <mutex>
+
+namespace vist {
+namespace rmi {
+
+using namespace vist::transport;
+
+class Remote::Impl {
+public:
+ explicit Impl(const std::string& path) : client(path)
+ {
+ }
+
+ Message request(Message message)
+ {
+ return this->client.request(message);
+ }
+
+private:
+ Client client;
+};
+
+Remote::Remote(const std::string& path) : pImpl(new Impl(path))
+{
+}
+
+Message Remote::request(Message message)
+{
+ return pImpl->request(message);
+}
+
+void Remote::ImplDeleter::operator()(Impl* ptr)
+{
+ delete ptr;
+}
+
+} // namespace rmi
+} // namespace vist
--- /dev/null
+/*
+ * Copyright (c) 2018-present 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
+ */
+/*
+ * @file remote.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @author Jaemin Ryu (jm77.ryu@samsung.com)
+ * @brief Client-side stub for invoking remote method.
+ */
+
+#pragma once
+
+#include <vist/transport/message.hpp>
+
+#include <string>
+#include <memory>
+
+namespace vist {
+namespace rmi {
+
+using namespace vist::transport;
+
+class Remote {
+public:
+ explicit Remote(const std::string& path);
+
+ template<typename R, typename... Args>
+ R invoke(const std::string& name, Args&&... args);
+
+private:
+ Message request(Message message);
+
+ class Impl;
+ /// Let compiler know how to destroy Impl
+ struct ImplDeleter
+ {
+ void operator()(Impl*);
+ };
+
+ std::unique_ptr<Impl, ImplDeleter> pImpl;
+};
+
+template<typename R, typename... Args>
+R Remote::invoke(const std::string& method, Args&&... args)
+{
+ Message message(Message::Type::MethodCall, method);
+ message.enclose(std::forward<Args>(args)...);
+
+ Message reply = this->request(message);
+ R result;
+ reply.disclose(result);
+
+ return result;
+}
+
+} // namespace rmi
+} // namespace vist
--- /dev/null
+/*
+ * Copyright (c) 2018-present 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/exposer.hpp>
+#include <vist/rmi/remote.hpp>
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+using namespace vist::rmi;
+
+// exposer side methods
+struct Foo {
+ bool setName(const std::string& name)
+ {
+ this->name = name;
+ return false;
+ }
+
+ std::string getName(void)
+ {
+ return this->name;
+ }
+
+ std::string name;
+};
+
+TEST(RmiTests, positive)
+{
+ std::string sockPath = ("/tmp/test-exposer");
+
+ // exposer-side
+ Exposer exposer(sockPath);
+
+ auto foo = std::make_shared<Foo>();
+ exposer.expose(foo, "Foo::setName", &Foo::setName);
+ exposer.expose(foo, "Foo::getName", &Foo::getName);
+
+ auto client = std::thread([&]() {
+ // caller-side
+ Remote remote(sockPath);
+
+ std::string param = "RMI-TEST";
+ bool ret = remote.invoke<bool>("Foo::setName", param);
+ EXPECT_EQ(ret, false);
+
+ std::string name = remote.invoke<std::string>("Foo::getName");
+ EXPECT_EQ(name, param);
+
+ exposer.stop();
+ });
+
+ exposer.start();
+
+ if (client.joinable())
+ client.join();
+}
#include "vist.hpp"
-#include <vist/rmi/server.hpp>
+#include <vist/rmi/exposer.hpp>
#include <vist/logger.hpp>
#include <vist/exception.hpp>
void Vist::start()
{
INFO(VIST) << "Vist daemon starts.";
- rmi::Server server;
- server.listen(SOCK_ADDR);
+ rmi::Exposer exposer(SOCK_ADDR);
- server.expose(this, "Vist::query", &Vist::query);
- server.start();
+ exposer.expose(this, "Vist::query", &Vist::query);
+ exposer.start();
}
Rows Vist::query(const std::string& statement)
ADD_VIST_COMMON_LIBRARY(vist_transport connection.cpp
socket.cpp
- message.cpp)
+ message.cpp
+ protocol.cpp)
FILE(GLOB TRANSPORT_TESTS "tests/*.cpp")
ADD_VIST_TEST(${TRANSPORT_TESTS})
--- /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
+ */
+/*
+ * @file client.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief Protocol compliant client.
+ */
+
+#pragma once
+
+#include <vist/exception.hpp>
+#include <vist/logger.hpp>
+#include <vist/transport/protocol.hpp>
+
+namespace vist {
+namespace transport {
+
+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 transport
+} // namespace vist
Message::Message(Header header) : header(header)
{
- this->buffer.reserve(this->header.length);
+ this->buffer.resize(this->header.length);
}
std::size_t Message::size(void) const noexcept
return this->header.length;
}
+void Message::resize(std::size_t size)
+{
+ this->buffer.resize(size);
+}
+
+std::vector<unsigned char>& Message::getBuffer(void) noexcept
+{
+ return this->buffer.getBuffer();
+}
+
} // namespace transport
} // namespace vist
void disclose(Args&... args);
std::size_t size(void) const noexcept;
+ void resize(std::size_t size);
+ std::vector<unsigned char>& getBuffer(void) noexcept;
Header header;
std::string signature;
--- /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 transport {
+
+Message Protocol::Recv(Socket& socket)
+{
+ 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)
+{
+ 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)
+{
+ auto result = task(message);
+ /// catch
+ this->message = result;
+ 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 transport
+} // 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
+ */
+/*
+ * @file protocol.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief Socket communication protocol between server and client.
+ */
+
+#pragma once
+
+#include <vist/transport/message.hpp>
+
+#include <functional>
+
+#include <boost/asio.hpp>
+
+namespace vist {
+namespace transport {
+
+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 transport
+} // 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
+ */
+/*
+ * @file server.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief Protocol compliant server.
+ */
+
+#pragma once
+
+#include <vist/exception.hpp>
+#include <vist/logger.hpp>
+#include <vist/transport/protocol.hpp>
+
+#include <memory>
+
+#include <unistd.h>
+#include <errno.h>
+
+namespace vist {
+namespace transport {
+
+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);
+
+ this->accept(task);
+ };
+ this->acceptor->async_accept(asyncSession->getSocket(), handler);
+ }
+
+ inline void run()
+ {
+ this->context.run();
+ }
+
+ inline void stop()
+ {
+ this->context.stop();
+ }
+
+private:
+ Protocol::Context context;
+ std::unique_ptr<Protocol::Acceptor> acceptor;
+};
+
+} // namespace transport
+} // 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/transport/protocol.hpp>
+
+#include <string>
+#include <thread>
+
+#include <gtest/gtest.h>
+#include <boost/asio.hpp>
+
+#include <unistd.h>
+
+using namespace vist::transport;
+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 = [&](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;
+ };
+
+ 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/transport/server.hpp>
+#include <vist/transport/client.hpp>
+
+#include <string>
+#include <thread>
+
+#include <boost/asio.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace vist::transport;
+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();
+}