Files
rippled/include/xrpl/server/detail/ServerImpl.h
Bart 1d42c4f6de refactor: Remove unnecessary copyright notices already covered by LICENSE.md (#5929)
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d).

This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
2025-11-04 08:33:42 +00:00

195 lines
4.3 KiB
C++

#ifndef XRPL_SERVER_SERVERIMPL_H_INCLUDED
#define XRPL_SERVER_SERVERIMPL_H_INCLUDED
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/core/List.h>
#include <xrpl/server/detail/Door.h>
#include <xrpl/server/detail/io_list.h>
#include <boost/asio.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/io_context.hpp>
#include <array>
#include <chrono>
#include <mutex>
#include <optional>
#include <unordered_map>
namespace ripple {
using Endpoints =
std::unordered_map<std::string, boost::asio::ip::tcp::endpoint>;
/** 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<Port> 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 Handler>
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<boost::asio::io_context::executor_type> strand_;
std::optional<boost::asio::executor_work_guard<
boost::asio::io_context::executor_type>>
work_;
std::mutex m_;
std::vector<Port> ports_;
std::vector<std::weak_ptr<Door<Handler>>> list_;
int high_ = 0;
std::array<std::size_t, 64> 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<Port> 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 <class Handler>
ServerImpl<Handler>::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 <class Handler>
ServerImpl<Handler>::~ServerImpl()
{
// Handler::onStopped will not be called
work_ = std::nullopt;
ios_.close();
ios_.join();
}
template <class Handler>
Endpoints
ServerImpl<Handler>::ports(std::vector<Port> const& ports)
{
if (closed())
Throw<std::logic_error>("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<Door<Handler>>(
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 <class Handler>
void
ServerImpl<Handler>::close()
{
ios_.close([&] {
work_ = std::nullopt;
handler_.onStopped(*this);
});
}
template <class Handler>
bool
ServerImpl<Handler>::closed()
{
return ios_.closed();
}
} // namespace ripple
#endif