#pragma once /* ABSTRACT DEVICE COMPONENTS LIBRARY */ #include #include #include #include #if __has_include() // POSIX #define FORK_EXISTS 1 #include #include #include #endif #include namespace adc { namespace traits { // network server session implementation concept template concept adc_netserver_session_impl_c = requires(T t, const T t_const) { typename T::session_ident_t; { t_const.sessionIdent() } -> std::same_as; { t.start() } -> std::same_as; { t.stop() } -> std::same_as; }; } // namespace traits /* Server session */ template class AdcNetServerSession : std::enable_shared_from_this> { protected: ImplT _impl; public: typedef ImplT session_impl_t; typedef std::shared_ptr shared_ptr_t; typedef std::weak_ptr weak_ptr_t; using typename ImplT::session_ident_t; template AdcNetServerSession(ImplCtorArgTs&&... ctor_args) : _impl(std::forward(ctor_args)...) { } virtual ~AdcNetServerSession() = default; virtual session_ident_t sessionIdent() const { // return _impl._sessionIdent(); } virtual void start() { // _impl.start(); } virtual void stop() { // _impl.stop(); } }; namespace traits { // network server session concept template concept adc_netserver_session_c = requires { typename T::session_impl_t; std::derived_from>; }; } // namespace traits /* network server */ namespace traits { template concept adc_generic_netserver_impl_c = requires(T t, const T t_const) { typename T::server_ident_t; { t_const.serverIdent() } -> std::same_as; { t.start() } -> std::same_as; { t.stop() } -> std::same_as; }; template concept adc_netserver_impl_c = requires(T t, const T t_const) { typename T::server_ident_t; { t_const.serverIdent() } -> std::same_as; { t.start() } -> std::same_as; { t.stop() } -> std::same_as; { t.daemonize() } -> std::same_as; { t.daemonizePrepare() } -> std::same_as; { t.daemonizeFinalize() } -> std::same_as; }; } // namespace traits /* VERY GENERIC NETWORK SERVER INTERFACE */ template class AdcGenericNetServer { protected: ImplT _impl; public: typedef ImplT server_impl_t; using typename ImplT::server_ident_t; template AdcGenericNetServer(ImplCtorArgTs&&... ctor_args) : _impl(std::make_unique(ctor_args)...) { } virtual ~AdcGenericNetServer() = default; virtual server_ident_t serverIdent() const { // return _impl.serverIdent(); } virtual void start() { // _impl.start(); }; virtual void stop() { // _impl.stop(); }; }; template class AdcNetServer { protected: ImplT _impl; public: typedef ImplT server_impl_t; using typename ImplT::server_ident_t; template AdcNetServer(ImplCtorArgTs&&... ctor_args) : _impl(std::make_unique(ctor_args)...) { } virtual ~AdcNetServer() = default; virtual server_ident_t serverIdent() const { // return _impl.serverIdent(); } virtual void start() { // _impl.start(); }; virtual void stop() { // _impl.stop(); }; // run server as daemon (still only on POSIX OSes) virtual void daemonize() { daemonizePrepare(); // reference implementation of forking for POSIX OSes #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(); } protected: // started sessions waek pointers template static std::unordered_map> _serverSessions; std::vector> _stopSessionFunc; template void startSession(const typename SessionT::shared_ptr_t& sess_ptr) { auto res = _serverSessions[this].emplace(sess_ptr); if (res.second) { sess_ptr.start(); _stopSessionFunc.emplace_back([res]() { if (!res.first.expired()) { // session is still existing auto sess = res.first.lock(); sess->stop(); } }); } } void stopAllSessions() { for (auto& func : _stopSessionFunc) { func(); } } virtual void daemonizePrepare() { // _impl.daemonizePrepare(); }; virtual void daemonizeFinalize() { // _impl.daemonizeFinalize(); }; }; namespace traits { // network server concept template concept adc_netserver_c = requires { typename T::server_impl_t; std::derived_from>; }; } // namespace traits } // namespace adc