diff --git a/net/adc_netserver.h b/net/adc_netserver.h index 717be7b..190cd00 100644 --- a/net/adc_netserver.h +++ b/net/adc_netserver.h @@ -25,51 +25,20 @@ namespace adc { -class AdcNetServer +/* SOME USEFULL PRIVITIVES */ + +// Ageneric implementation pf POSIX OS daemon +class AdcPosixGenericDaemon { -protected: public: - typedef std::string server_ident_t; - - - virtual ~AdcNetServer() = default; - - - virtual server_ident_t serverIdent() const - { - return _serverIdent; - } - - template - void start(const typename SessionT::netservice_t::endpoint_t& endpoint, - const typename SessionT::netsession_ident_t& id, - typename SessionT::netsession_ctx_t&& sess_ctx, - NetsrvCtorArgTs&&... ctor_args) - { - typename SessionT::netservice_t netservice(std::forward(ctor_args)...); - - netservice.asyncAccept(endpoint, [&endpoint, &id, sess_ctx, this](auto ec, auto...) { - if (!ec) { - auto sess = std::make_shared(id, std::forward(sess_ctx)); - startSession(sess); - - start(endpoint, id, sess_ctx); - } - }); - }; - - virtual void stop() - { - stopAllSessions(); - }; - + virtual ~AdcPosixGenericDaemon() = default; // run server as daemon (still only on POSIX OSes) - virtual void daemonize() + void daemonize() { daemonizePrepare(); - // reference implementation of forking for POSIX OSes +// reference implementation of forking for POSIX OSes #ifdef FORK_EXISTS // get TEMP directory in OS @@ -108,23 +77,38 @@ public: close(1); close(2); - // _ioContext.notify_fork(asio::io_context::fork_child); +// _ioContext.notify_fork(asio::io_context::fork_child); #endif daemonizeFinalize(); } +protected: + virtual void daemonizePrepare() = 0; + virtual void daemonizeFinalize() = 0; +}; + + +// a basic network session manager (basic start and stop functionality) + +class AdcNetSessionManager +{ +public: + virtual ~AdcNetSessionManager() = default; protected: - server_ident_t _serverIdent; - + template + constexpr static bool anySessionPredicate(const typename SessionT::netsession_ident_t&) + { + return true; + } // started sessions weak pointers template - static std::unordered_map> _serverSessions; - std::vector> _stopSessionFunc; + static std::unordered_map>> _serverSessions; + std::vector> _stopSessionFunc; template - void startSession(const typename SessionT::shared_ptr_t& sess_ptr) + void startSession(std::shared_ptr& sess_ptr) { auto res = _serverSessions[this].emplace(sess_ptr); if (res.second) { @@ -134,22 +118,99 @@ protected: if (!res.first.expired()) { // session is still existing auto sess = res.first.lock(); sess->stop(); + return true; + } else { + return false; } }); } } - void stopAllSessions() + template PredT = decltype(anySessionPredicate)> + size_t stopSessions(PredT&& comp_func = anySessionPredicate()) { - for (auto& func : _stopSessionFunc) { - func(); + size_t N = 0; + + for (auto& wptr : _serverSessions[this]) { + if (std::shared_ptr sptr = wptr.lock()) { + if constexpr (std::same_as)>) { + sptr->stop(); + ++N; + } else { + if (std::forward(comp_func)(sptr->ident())) { + sptr->stop(); + ++N; + } + } + } } + + return N; } - virtual void daemonizePrepare() = 0; - virtual void daemonizeFinalize() = 0; + size_t stopAllSessions() + { + size_t N = 0; + + for (auto& func : _stopSessionFunc) { + func() ? ++N : 0; + } + + return N; + } +}; + + + +/* very generic network server */ + +class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager +{ +protected: +public: + typedef std::string server_ident_t; + + + virtual ~AdcGenericNetServer() = default; + + + virtual server_ident_t ident() const + { + return _serverIdent; + } + + template + void start(const typename SessionT::netservice_t::endpoint_t& endpoint, + const typename SessionT::netsession_ident_t& id, + typename SessionT::netsession_ctx_t&& sess_ctx, + NetsrvCtorArgTs&&... ctor_args) + { + typename SessionT::netservice_t netservice(std::forward(ctor_args)...); + + netservice.asyncAccept(endpoint, [&endpoint, &id, sess_ctx, this](auto ec, auto...) { + if (!ec) { + auto sess = std::make_shared(id, std::forward(sess_ctx)); + startSession(sess); + + start(endpoint, id, sess_ctx); + } + }); + }; + + virtual void start() = 0; + + virtual void stop() + { + stopAllSessions(); + }; + + + +protected: + server_ident_t _serverIdent; }; diff --git a/net/asio/adc_netservice_asio.h b/net/asio/adc_netservice_asio.h index 09b2c1a..f161368 100644 --- a/net/asio/adc_netservice_asio.h +++ b/net/asio/adc_netservice_asio.h @@ -219,6 +219,9 @@ public: _socket(std::move(other._socket)), _streamBuffer() { + if (*this == other) + return; + auto bytes = asio::buffer_copy(_streamBuffer.prepare(other._streamBuffer.size()), other._streamBuffer.data()); _streamBuffer.commit(bytes); }; @@ -228,6 +231,29 @@ public: virtual ~AdcNetServiceASIOBase() {} + AdcNetServiceASIOBase& operator=(const AdcNetServiceASIOBase&) = delete; + + AdcNetServiceASIOBase& operator=(AdcNetServiceASIOBase&& other) + { + if (*this != other) { + close(); + _streamBuffer.consume(_streamBuffer.size()); + + auto bytes = + asio::buffer_copy(_streamBuffer.prepare(other._streamBuffer.size()), other._streamBuffer.data()); + _streamBuffer.commit(bytes); + + _ioContext = other._ioContext; + _receiveStrand = std::move(other._receiveStrand), _socket = std::move(other._socket); + _acceptor = std::move(other._acceptor); + + _receiveQueue = other._receiveQueue; + } + + return *this; + } + + constexpr netservice_ident_t ident() const { return _ident;