From 2a1f04d2b0f459bae3295c3ae12aa9708a84fe80 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Fri, 20 Dec 2024 17:35:51 +0200 Subject: [PATCH] added support of client context --- src/cli/main.cpp | 5 ++ src/common/ipc/unix_socket_server.cpp | 82 ++++++++++++++++++++++----- src/common/ipc/unix_socket_server.hpp | 31 ++++++++-- 3 files changed, 99 insertions(+), 19 deletions(-) diff --git a/src/cli/main.cpp b/src/cli/main.cpp index e218287..9da8379 100644 --- a/src/cli/main.cpp +++ b/src/cli/main.cpp @@ -5,6 +5,8 @@ #include "ipc/unix_socket_client.hpp" +#include + int main(const int argc, const char** const argv) { (void) argc; @@ -18,6 +20,9 @@ int main(const int argc, const char** const argv) } client.send_message("Hello, world!"); + ::sleep(10); + client.send_message("Goodbye, world!"); + ::sleep(10); return 0; } \ No newline at end of file diff --git a/src/common/ipc/unix_socket_server.cpp b/src/common/ipc/unix_socket_server.cpp index 19cd8bd..2d88de1 100644 --- a/src/common/ipc/unix_socket_server.cpp +++ b/src/common/ipc/unix_socket_server.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -33,13 +34,57 @@ namespace constexpr int MaxConnections = 5; +class ClientContextImpl final : public UnixSocketServer::ClientContext +{ +public: + explicit ClientContextImpl(const int client_fd) + : client_fd_{client_fd} + { + CETL_DEBUG_ASSERT(client_fd != -1, ""); + + std::cout << "New client connection on fd=" << client_fd << ".\n"; + } + + ~ClientContextImpl() override + { + std::cout << "Closing connection on fd=" << client_fd_ << ".\n"; + + platform::posixSyscallError([this] { + // + return ::close(client_fd_); + }); + } + + ClientContextImpl(ClientContextImpl&&) = delete; + ClientContextImpl(const ClientContextImpl&) = delete; + ClientContextImpl& operator=(ClientContextImpl&&) = delete; + ClientContextImpl& operator=(const ClientContextImpl&) = delete; + + int getFd() const + { + return client_fd_; + } + + void setCallback(libcyphal::IExecutor::Callback::Any&& callback) + { + callback_ = std::move(callback); + } + +private: + const int client_fd_; + libcyphal::IExecutor::Callback::Any callback_; + +}; // ClientContextImpl + } // namespace UnixSocketServer::UnixSocketServer(libcyphal::IExecutor& executor, std::string socket_path) : executor_{executor} , socket_path_{std::move(socket_path)} , server_fd_{-1} + , posix_executor_ext_{cetl::rtti_cast(&executor_)} { + CETL_DEBUG_ASSERT(posix_executor_ext_ != nullptr, ""); } UnixSocketServer::~UnixSocketServer() @@ -102,7 +147,7 @@ bool UnixSocketServer::start() return true; } -void UnixSocketServer::accept() const +void UnixSocketServer::accept() { CETL_DEBUG_ASSERT(server_fd_ != -1, ""); @@ -116,15 +161,26 @@ void UnixSocketServer::accept() const return; } - handle_client(client_fd); + handle_client_connection(client_fd); +} - platform::posixSyscallError([this, client_fd] { - // - return ::close(client_fd); - }); +void UnixSocketServer::handle_client_connection(const int client_fd) +{ + CETL_DEBUG_ASSERT(client_fd != -1, ""); + CETL_DEBUG_ASSERT(client_contexts_.find(client_fd) == client_contexts_.end(), ""); + + auto client_context = std::make_unique(client_fd); + client_context->setCallback(posix_executor_ext_->registerAwaitableCallback( + [this, client_fd](const auto&) { + // + handle_client_request(client_fd); + }, + platform::IPosixExecutorExtension::Trigger::Readable{client_fd})); + + client_contexts_.emplace(client_fd, std::move(client_context)); } -void UnixSocketServer::handle_client(const int client_fd) +void UnixSocketServer::handle_client_request(const int client_fd) { CETL_DEBUG_ASSERT(client_fd != -1, ""); @@ -141,8 +197,11 @@ void UnixSocketServer::handle_client(const int client_fd) } if (bytes_read == 0) { + // EOF which means the client has closed the connection. + client_contexts_.erase(client_fd); return; } + buffer[bytes_read] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) std::cout << "Received: " << buffer.data() << "\n"; @@ -160,14 +219,9 @@ void UnixSocketServer::handle_client(const int client_fd) CETL_NODISCARD libcyphal::IExecutor::Callback::Any UnixSocketServer::registerListenCallback( libcyphal::IExecutor::Callback::Function&& function) const { - auto* const posix_executor_ext = cetl::rtti_cast(&executor_); - if (nullptr == posix_executor_ext) - { - return {}; - } - CETL_DEBUG_ASSERT(udp_handle_.fd >= 0, ""); - return posix_executor_ext->registerAwaitableCallback( // + + return posix_executor_ext_->registerAwaitableCallback( // std::move(function), platform::IPosixExecutorExtension::Trigger::Readable{server_fd_}); } diff --git a/src/common/ipc/unix_socket_server.hpp b/src/common/ipc/unix_socket_server.hpp index a53e787..aa2fee9 100644 --- a/src/common/ipc/unix_socket_server.hpp +++ b/src/common/ipc/unix_socket_server.hpp @@ -6,10 +6,14 @@ #ifndef OCVSMD_COMMON_IPC_UNIX_SOCKET_SERVER_HPP_INCLUDED #define OCVSMD_COMMON_IPC_UNIX_SOCKET_SERVER_HPP_INCLUDED +#include "platform/posix_executor_extension.hpp" + #include #include +#include #include +#include namespace ocvsmd { @@ -35,14 +39,31 @@ class UnixSocketServer final CETL_NODISCARD libcyphal::IExecutor::Callback::Any registerListenCallback( libcyphal::IExecutor::Callback::Function&& function) const; - void accept() const; + void accept(); + + class ClientContext + { + public: + ClientContext() = default; + + ClientContext(ClientContext&&) = delete; + ClientContext(const ClientContext&) = delete; + ClientContext& operator=(ClientContext&&) = delete; + ClientContext& operator=(const ClientContext&) = delete; + + virtual ~ClientContext() = default; + + }; // ClientContext private: - static void handle_client(const int client_fd); + void handle_client_connection(const int client_fd); + void handle_client_request(const int client_fd); - libcyphal::IExecutor& executor_; - std::string socket_path_; - int server_fd_; + libcyphal::IExecutor& executor_; + const std::string socket_path_; + int server_fd_; + platform::IPosixExecutorExtension* const posix_executor_ext_; + std::unordered_map> client_contexts_; }; // UnixSocketServer