#pragma once /* ABSTRACT DEVICE COMPONENTS LIBRARY */ #include #if __has_include() // POSIX #define FORK_EXISTS 1 #include #include #include #endif #include namespace adc { /* Server session and its abstract decorator */ template class AdcNetServerSession : std::enable_shared_from_this> { public: using shared_ptr_t = std::shared_ptr; using weak_ptr_t = std::weak_ptr; template AdcNetServerSession(ImplCtorArgTs&&... ctor_args) : _implUptr(std::forward(ctor_args)...) { } virtual ~AdcNetServerSession() = default; auto sessionIdent() const { // return _implUptr->_sessionIdent(); } virtual void start() { // _implUptr->start(); } virtual void stop() { // _implUptr->stop(); } protected: std::unique_ptr _implUptr; }; template > SessionT> class AdcNetServerSessionDecorator : public SessionT { public: using SessionT::sessionIdent; template AdcNetServerSessionDecorator(ImplCtorArgTs&&... ctor_args) : SessionT(std::forward(ctor_args)...) { } virtual ~AdcNetServerSessionDecorator() = default; virtual std::invoke_result_t sessionIdent() const = 0; virtual void start() = 0; virtual void stop() = 0; }; /* Server */ template class AdcNetServer { protected: std::unique_ptr _implUptr; public: template AdcNetServer(ImplCtorArgTs&&... ctor_args) : _implUptr(std::make_unique(ctor_args)...) { } virtual ~AdcNetServer() = default; virtual void start() = 0; virtual void stop() = 0; template void start() {}; template void stop() {}; // run server as daemon (still only on POSIX OSes) void daemonize() { daemonizePrepare(); #ifdef FORK_EXISTS // get TEMP directory in OS auto tmp_path = std::filesystem::temp_directory_path(); if (tmp_path.empty()) { tmp_path = std::filesystem::current_path().root_path(); } // _ioContext.notify_fork(asio::execution_context::fork_prepare); if (pid_t pid = fork()) { if (pid > 0) { exit(0); } else { throw std::system_error(errno, std::generic_category(), "CANNOT FORK 1-STAGE"); } } if (setsid() == -1) { throw std::system_error(errno, std::generic_category(), "CANNOT FORK SETSID"); } std::filesystem::current_path(tmp_path); 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"); } } close(0); close(1); close(2); // _ioContext.notify_fork(asio::io_context::fork_child); #endif daemonizeFinalize(); } virtual void daemonizePrepare() = 0; virtual void daemonizeFinalize() = 0; }; } // namespace adc