diff --git a/cxx/CMakeLists.txt b/cxx/CMakeLists.txt index ab66677..ab77b2c 100644 --- a/cxx/CMakeLists.txt +++ b/cxx/CMakeLists.txt @@ -85,7 +85,7 @@ set(CNTR_PROTO_LIB_SRC set(CNTR_PROTO_LIB comm_proto) add_library(${CNTR_PROTO_LIB} STATIC ${CNTR_PROTO_LIB_SRC}) -set(MOUNT_SERVER_APP_SRC mount.h mount_server.cpp comm_server.h) +set(MOUNT_SERVER_APP_SRC mount.h mount_server.cpp comm_server.h comm_server_endpoint.h) set(MOUNT_SERVER_APP mount_server) add_executable(${MOUNT_SERVER_APP} ${MOUNT_SERVER_APP_SRC}) target_link_libraries(${MOUNT_SERVER_APP} ${CNTR_PROTO_LIB} spdlog::spdlog_header_only) diff --git a/cxx/comm_server.h b/cxx/comm_server.h index 08d17b7..481bf17 100644 --- a/cxx/comm_server.h +++ b/cxx/comm_server.h @@ -19,6 +19,15 @@ #include #include +#if __has_include() // POSIX +#define FORK_EXISTS 1 +#include +#include +#include +#endif + + + #include "comm_server_endpoint.h" #include "control_proto.h" #include "mount.h" @@ -38,25 +47,29 @@ concept mcc_endpoint_c = std::derived_from || std::derived template static constexpr bool is_serial_proto = std::derived_from; -template -static constexpr bool is_tcp_proto = std::derived_from; - -template -static constexpr bool is_local_stream_proto = - std::derived_from; - -template -static constexpr bool is_local_seqpack_proto = - std::derived_from; +// template +// static constexpr bool is_tcp_proto = std::derived_from; // template -// static constexpr bool is_tcp_proto = std::derived_from; +// static constexpr bool is_local_stream_proto = +// std::derived_from; // template -// static constexpr bool is_local_stream_proto = std::derived_from; +// static constexpr bool is_local_seqpack_proto = +// std::derived_from; -// template -// static constexpr bool is_local_seqpack_proto = std::derived_from; + +template +static constexpr bool is_tcp_proto = + std::derived_from || std::derived_from; + +template +static constexpr bool is_local_stream_proto = std::derived_from || + std::derived_from; + +template +static constexpr bool is_local_seqpack_proto = std::derived_from || + std::derived_from; template @@ -148,8 +161,8 @@ public: try { // std::stringstream st; - _serverLogger->debug("Create connection acceptor for endpoint <{}> ...", - epn.address().to_string()); + // _serverLogger->debug("Create connection acceptor for endpoint <{}> ...", + // epn.address().to_string()); acc = asio::ip::tcp::acceptor(_asioContext, epn); // st << acc.local_endpoint(); exit_flag = true; @@ -208,7 +221,7 @@ public: st << endpoint; _serverLogger->debug("Create connection acceptor for endpoint <{}> ...", st.str()); - auto acc = epn_t::protocol_type::acceptor(_asioContext, endpoint); + auto acc = typename epn_t::protocol_type::acceptor(_asioContext, endpoint); st.str(""); st << acc.local_endpoint(); @@ -240,6 +253,8 @@ public: } else { static_assert(false, "INVALID ENDPOINT!!!"); } + + co_return; } @@ -247,7 +262,6 @@ public: void stopListening() { std::error_code ec; - size_t N = 0, M = 0; _serverLogger->info("Close all listening endpoints ..."); @@ -291,6 +305,70 @@ public: void disconnectClients() {} + void daemonize() + { +#ifdef FORK_EXISTS + _serverLogger->info("Daemonize the server ..."); + + _asioContext.notify_fork(asio::execution_context::fork_prepare); + + auto tmp_path = std::filesystem::temp_directory_path(); + if (tmp_path.empty()) { + tmp_path = std::filesystem::current_path().root_path(); + } + + + if (pid_t pid = fork()) { + if (pid > 0) { + exit(0); + } else { + // throw std::system_error(errno, std::generic_category(), "CANNOT FORK 1-STAGE"); + _serverLogger->error("CANNOT FORK 1-STAGE! The server was not daemonized!"); + return; + } + } + + if (setsid() == -1) { + // throw std::system_error(errno, std::generic_category(), "CANNOT FORK SETSID"); + _serverLogger->error("CANNOT FORK SETSID! The server was not daemonized!"); + return; + } + + _serverLogger->info("Try to set the daemon current path to '{}' ...", tmp_path.string()); + + std::error_code ec{}; + + std::filesystem::current_path(tmp_path, ec); + if (!ec) { + _serverLogger->warn("Cannot change current path to '{}'! Ignore!", tmp_path.string()); + } + + umask(0); + + if (pid_t pid = fork()) { + if (pid > 0) { + exit(0); + } else { + // throw std::system_error(errno, std::generic_category(), "CANNOT FORK 2-STAGE"); + _serverLogger->error("CANNOT FORK 2-STAGE! The server was not daemonized!"); + return; + } + } + + // stdin, stdout, stderr + close(0); + close(1); + close(2); + + _asioContext.notify_fork(asio::io_context::fork_child); + + _serverLogger->info("The server was daemonized successfully!"); + +#else + _serverLogger->warn("Host platform is not POSIX one, so cannot daemonize the server!"); +#endif + } + private: asio::io_context& _asioContext; std::shared_ptr _serverLogger; @@ -345,10 +423,11 @@ private: } - template + template asio::awaitable startSession(auto socket, - RCVT&& rcv_timeout = DEFAULT_RCV_TIMEOUT, - SNDT&& snd_timeout = DEFAULT_SND_TIMEOUT) + const RCVT& rcv_timeout = DEFAULT_RCV_TIMEOUT, + const SNDT& snd_timeout = DEFAULT_SND_TIMEOUT) { using namespace asio::experimental::awaitable_operators; @@ -431,7 +510,7 @@ private: if constexpr (traits::is_local_seqpack_proto) { asio::socket_base::message_flags oflags; // nbytes = co_await socket.async_receive(buff, &oflags, asio::use_awaitable); - nbytes = co_await (socket.async_receive(buff, &oflags, asio::use_awaitable) && + nbytes = co_await (socket.async_receive(buff, oflags, asio::use_awaitable) && watchdog(std::chrono::steady_clock::now() + rcv_timeout)); if (!nbytes) { // EOF! diff --git a/cxx/comm_server_endpoint.h b/cxx/comm_server_endpoint.h index 8fd50be..69349a4 100644 --- a/cxx/comm_server_endpoint.h +++ b/cxx/comm_server_endpoint.h @@ -438,6 +438,9 @@ protected: idx = std::distance(other._endpoint.c_str(), other._path.data()); _path = std::string_view(_endpoint.c_str() + idx, other._path.size()); + idx = std::distance(other._endpoint.c_str(), other._portView.data()); + _portView = std::string_view(_endpoint.c_str() + idx, other._portView.size()); + _port = other._port; } else { _isValid = false; @@ -445,6 +448,7 @@ protected: _proto = std::string_view(); _host = std::string_view(); _path = std::string_view(); + _portView = std::string_view(); _port = -1; } } @@ -461,12 +465,14 @@ protected: _host = std::move(other._host); _path = std::move(other._path); _port = std::move(other._port); + _portView = std::move(other._portView); } else { _isValid = false; _endpoint = std::string(); _proto = std::string_view(); _host = std::string_view(); _path = std::string_view(); + _portView = std::string_view(); _port = -1; } } diff --git a/cxx/mount_server.cpp b/cxx/mount_server.cpp index 04b4e27..cac5542 100644 --- a/cxx/mount_server.cpp +++ b/cxx/mount_server.cpp @@ -7,8 +7,16 @@ int main() { asio::io_context ctx; - mcc::MccMountServer server(ctx, spdlog::stdout_color_mt("STDOUT_LOGGER")); + auto logger = spdlog::stdout_color_mt("STDOUT_LOGGER"); + logger->set_level(spdlog::level::debug); + logger->flush_on(spdlog::level::debug); + mcc::MccMountServer server(ctx, logger); + + mcc::MccServerEndpoint epn(std::string_view("local://seqpacket/tmp/BM700_SERVER_SOCK")); + // mcc::MccServerEndpoint epn(std::string_view("tcp://localhost:12345/tmp/BM700_SERVER_SOCK")); + + asio::co_spawn(ctx, server.listen(epn), asio::detached); ctx.run(); }