diff options
author | Egor Tensin <Egor.Tensin@gmail.com> | 2019-12-07 03:36:21 +0300 |
---|---|---|
committer | Egor Tensin <Egor.Tensin@gmail.com> | 2019-12-07 03:36:21 +0300 |
commit | 00863566ec4601c65c435b74e575d49546a1c707 (patch) | |
tree | 479a0a6e96aba8191c7a65ea9bee2f4d5e3a4aba /server/main/server.cpp | |
parent | add stress_test.py (diff) | |
download | math-server-00863566ec4601c65c435b74e575d49546a1c707.tar.gz math-server-00863566ec4601c65c435b74e575d49546a1c707.zip |
split server into multiple components
In a vague attempt to make header files more readable, split server/
into a number of components.
Also, refactor the unit tests to use the "Data-driven test cases" of
Boost.Test.
Diffstat (limited to 'server/main/server.cpp')
-rw-r--r-- | server/main/server.cpp | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/server/main/server.cpp b/server/main/server.cpp new file mode 100644 index 0000000..3800144 --- /dev/null +++ b/server/main/server.cpp @@ -0,0 +1,112 @@ +#include "server.hpp" +#include "session.hpp" +#include "session_manager.hpp" +#include "settings.hpp" + +#include "../common/error.hpp" +#include "../common/log.hpp" + +#include <boost/asio.hpp> +#include <boost/system/error_code.hpp> +#include <boost/system/system_error.hpp> + +#include <cstddef> + +#include <exception> +#include <thread> +#include <vector> + +namespace math::server { +namespace { + +boost::asio::ip::tcp::endpoint make_endpoint(unsigned port) { + return {boost::asio::ip::tcp::v4(), port}; +} + +void configure_acceptor(boost::asio::ip::tcp::acceptor& acceptor, unsigned port) { + try { + const auto endpoint = make_endpoint(port); + acceptor.open(endpoint.protocol()); + acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor.bind(endpoint); + acceptor.listen(); + } catch (const boost::system::system_error& e) { + throw Error{e.what()}; + } +} + +} + +Server::Server(const Settings& settings) + : Server{settings.m_port, settings.m_threads} +{ } + +Server::Server(unsigned port, unsigned threads) + : m_numof_threads{threads} + , m_signals{m_io_context} + , m_acceptor{m_io_context} { + + wait_for_signal(); + configure_acceptor(m_acceptor, port); + + accept(); +} + +void Server::run() { + std::vector<std::thread> threads{m_numof_threads}; + for (std::size_t i = 0; i < m_numof_threads; ++i) { + threads[i] = std::thread{[this] () { m_io_context.run(); }}; + } + + for (std::size_t i = 0; i < m_numof_threads; ++i) { + threads[i].join(); + } +} + +void Server::wait_for_signal() { + try { + m_signals.add(SIGINT); + m_signals.add(SIGTERM); + + m_signals.async_wait([this] (const boost::system::error_code& ec, int signo) { + handle_signal(ec, signo); + }); + } catch (const boost::system::system_error& e) { + throw Error{e.what()}; + } +} + +void Server::handle_signal(const boost::system::error_code& ec, int signo) { + if (ec) { + log::error("%1%: %2%", __func__, ec.message()); + } + + log::log("Caught signal %1%", signo); + + try { + m_acceptor.close(); + m_session_mgr.stop_all(); + } catch (const std::exception& e) { + log::error(e.what()); + } +} + +void Server::accept() { + const auto session = m_session_mgr.make_session(m_io_context); + m_acceptor.async_accept(session->socket(), + [session, this] (const boost::system::error_code& ec) { + handle_accept(session, ec); + }); +} + +void Server::handle_accept(SessionPtr session, const boost::system::error_code& ec) { + if (ec) { + log::error("%1%: %2%", __func__, ec.message()); + return; + } + + m_session_mgr.start(session); + accept(); +} + +} |