#include // Support both boost in Debian unstable (BOOST_LATEST) and in stable (boost 1.67) #if BOOST_VERSION >= 107100 #define BOOST_LATEST #endif #include #include #include #ifdef BOOST_LATEST #include #else #include #include #endif #include #include #include #include #include #include #include #include #include #include "server.h" #include "http.h" #include "https.h" #include "privileges.h" #include "statistics.h" namespace beast = boost::beast; // from namespace http = beast::http; // from namespace net = boost::asio; // from namespace ssl = boost::asio::ssl; // from using tcp = boost::asio::ip::tcp; // from const std::string Server::VersionString{ "Reichwein.IT Webserver "s + std::string{VERSION} }; namespace { const int32_t stats_timer_seconds { 24 * 60 * 60 }; // save stats once a day } // anonymous namespace Server::Server(Config& config, boost::asio::io_context& ioc, const Socket& socket, plugins_container_type& plugins, Statistics& statistics) : m_config(config) , m_ioc(ioc) , m_socket(socket) , m_plugins(plugins) , m_statistics(statistics) { } Server::~Server() { } int run_server(Config& config, plugins_container_type& plugins) { Statistics stats; auto const threads = std::max(1, config.Threads()); boost::asio::io_context ioc{threads}; // for now, just terminate on SIGINT, SIGHUP and SIGTERM boost::asio::signal_set signals(ioc, SIGINT, SIGTERM, SIGHUP); signals.async_wait([&](const boost::system::error_code& error, int signal_number){ std::cout << "Terminating via signal " << signal_number << std::endl; ioc.stop(); }); // Save stats once a day boost::asio::steady_timer stats_save_timer(ioc, boost::asio::chrono::seconds(stats_timer_seconds)); std::function stats_callback = [&](const boost::system::error_code& error){ stats.save(); stats_save_timer.expires_at(stats_save_timer.expires_at() + boost::asio::chrono::seconds(stats_timer_seconds)); stats_save_timer.async_wait(stats_callback); }; stats_save_timer.async_wait(stats_callback); std::vector> servers; const auto& sockets {config.Sockets()}; for (const auto& socket: sockets) { if (socket.protocol == SocketProtocol::HTTP) { servers.push_back(std::make_shared(config, ioc, socket, plugins, stats)); } else { servers.push_back(std::make_shared(config, ioc, socket, plugins, stats)); } servers.back()->start(); } // set UID, GID drop_privileges(config); // Run the I/O service on the requested number of threads std::vector v; v.reserve(threads - 1); for (auto i = threads - 1; i > 0; --i) { v.emplace_back( [&ioc] { ioc.run(); }); } ioc.run(); for (auto& t: v) { t.join(); } return EXIT_SUCCESS; } Config& Server::GetConfig() { return m_config; } const Socket& Server::GetSocket() { return m_socket; } plugin_type Server::GetPlugin(const std::string& name) { try { return m_plugins.at(name); } catch (const std::out_of_range& ex) { std::cout << "Out of range at Server::GetPlugin(): " << name << std::endl; std::rethrow_exception(std::current_exception()); } catch (...) { std::cout << "Unknown exception at Server::GetPlugin(): " << name << std::endl; std::rethrow_exception(std::current_exception()); } } Statistics& Server::GetStatistics() { return m_statistics; }