#ifndef XRPL_SERVER_SERVERIMPL_H_INCLUDED #define XRPL_SERVER_SERVERIMPL_H_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include namespace ripple { using Endpoints = std::unordered_map; /** A multi-protocol server. This server maintains multiple configured listening ports, with each listening port allows for multiple protocols including HTTP, HTTP/S, WebSocket, Secure WebSocket, and the Peer protocol. */ class Server { public: /** Destroy the server. The server is closed if it is not already closed. This call blocks until the server has stopped. */ virtual ~Server() = default; /** Returns the Journal associated with the server. */ virtual beast::Journal journal() = 0; /** Set the listening port settings. This may only be called once. */ virtual Endpoints ports(std::vector const& v) = 0; /** Close the server. The close is performed asynchronously. The handler will be notified when the server has stopped. The server is considered stopped when there are no pending I/O completion handlers and all connections have closed. Thread safety: Safe to call concurrently from any thread. */ virtual void close() = 0; }; template class ServerImpl : public Server { private: using clock_type = std::chrono::system_clock; enum { historySize = 100 }; Handler& handler_; beast::Journal const j_; boost::asio::io_context& io_context_; boost::asio::strand strand_; std::optional> work_; std::mutex m_; std::vector ports_; std::vector>> list_; int high_ = 0; std::array hist_; io_list ios_; public: ServerImpl( Handler& handler, boost::asio::io_context& io_context, beast::Journal journal); ~ServerImpl(); beast::Journal journal() override { return j_; } Endpoints ports(std::vector const& ports) override; void close() override; io_list& ios() { return ios_; } boost::asio::io_context& get_io_context() { return io_context_; } bool closed(); private: static int ceil_log2(unsigned long long x); }; template ServerImpl::ServerImpl( Handler& handler, boost::asio::io_context& io_context, beast::Journal journal) : handler_(handler) , j_(journal) , io_context_(io_context) , strand_(boost::asio::make_strand(io_context_)) , work_(std::in_place, boost::asio::make_work_guard(io_context_)) { } template ServerImpl::~ServerImpl() { // Handler::onStopped will not be called work_ = std::nullopt; ios_.close(); ios_.join(); } template Endpoints ServerImpl::ports(std::vector const& ports) { if (closed()) Throw("ports() on closed Server"); ports_.reserve(ports.size()); Endpoints eps; eps.reserve(ports.size()); for (auto const& port : ports) { ports_.push_back(port); auto& internalPort = ports_.back(); if (auto sp = ios_.emplace>( handler_, io_context_, internalPort, j_)) { list_.push_back(sp); auto ep = sp->get_endpoint(); if (!internalPort.port) internalPort.port = ep.port(); eps.emplace(port.name, std::move(ep)); sp->run(); } } return eps; } template void ServerImpl::close() { ios_.close([&] { work_ = std::nullopt; handler_.onStopped(*this); }); } template bool ServerImpl::closed() { return ios_.closed(); } } // namespace ripple #endif