140 lines
3.0 KiB
C++
140 lines
3.0 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_netservice_c SRVT>
|
|
void start(SRVT&& netservice, const typename SRVT::endpoint_t& endpoint) {};
|
|
|
|
virtual void 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:
|
|
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
|