ADC/net/adc_netserver.h
Timur A. Fatkhullin 8aef1a7c25 rewrite SESSION_PROTO.search
rewrite ASIO NETSERVICE.asyncReceive
rewrite ASIO NETSESSION
2024-09-29 00:42:13 +03:00

157 lines
3.7 KiB
C++

#pragma once
/*
ABSTRACT DEVICE COMPONENTS LIBRARY
*/
#include <filesystem>
#include <functional>
#include <set>
#include <unordered_map>
#if __has_include(<unistd.h>) // POSIX
#define FORK_EXISTS 1
#include <sys/stat.h>
#include <unistd.h>
#include <cerrno>
#endif
#include "adc_net_concepts.h"
namespace adc
{
class AdcNetServer
{
protected:
public:
typedef std::string server_ident_t;
virtual ~AdcNetServer() = default;
virtual server_ident_t serverIdent() const
{
return _serverIdent;
}
template <interfaces::adc_netsession_c SessionT, typename... NetsrvCtorArgTs>
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<NetsrvCtorArgTs>(ctor_args)...);
netservice.asyncAccept(endpoint, [&endpoint, &id, sess_ctx, this](auto ec, auto...) {
if (!ec) {
auto sess = std::make_shared<SessionT>(id, std::forward<typename SessionT::netsession_ctx_t>(sess_ctx));
startSession(sess);
start(endpoint, id, sess_ctx);
}
});
};
virtual void stop()
{
stopAllSessions();
};
// 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:
server_ident_t _serverIdent;
// started sessions weak pointers
template <interfaces::adc_netsession_c SessionT>
static std::unordered_map<const AdcNetServer*, std::set<typename SessionT::weak_ptr_t>> _serverSessions;
std::vector<std::function<void()>> _stopSessionFunc;
template <interfaces::adc_netsession_c SessionT>
void startSession(const typename SessionT::shared_ptr_t& sess_ptr)
{
auto res = _serverSessions<SessionT>[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() = 0;
virtual void daemonizeFinalize() = 0;
};
} // namespace adc