42#include "librats/util/rats_export.h"
43#include "librats/transport/connection.h"
44#include "librats/transport/reactor_pool.h"
46#include "librats/peer/peer_table.h"
49#include "librats/security/identity.h"
50#include "librats/security/handshaker.h"
54#include "librats/node/dialer.h"
59#include "librats/wire/message_router.h"
62#include <condition_variable>
78class RATS_API
Node final :
public ConnectionDelegate,
100 static_assert(std::is_base_of<Subsystem, T>::value,
"T must derive from Subsystem");
101 T* raw = subsystem.get();
102 subsystems_.push_back(std::move(subsystem));
119 uint16_t
listen_port() const noexcept
override {
return listen_port_; }
124 uint8_t
transports() const noexcept
override {
return transports_; }
127 const std::string&
protocol() const noexcept
override {
return config_.protocol; }
145 void connect(
const std::string& host, uint16_t port);
150 std::vector<PeerInfo>
peers()
const override {
return peers_.snapshot(); }
168 const DialProfile& profile)
override;
173 ConnRole role,
bool connected)
override;
178 size_t max_peers() const noexcept {
return max_peers_.load(std::memory_order_relaxed); }
179 void set_max_peers(
size_t n)
noexcept { max_peers_.store(n, std::memory_order_relaxed); }
181 const size_t cap = max_peers_.load(std::memory_order_relaxed);
182 return cap != 0 && peers_.size() >= cap;
250 void on(std::string_view channel, MessageRouter::Handler cb) { router_.on_channel(channel, std::move(cb)); }
257 for (
auto& s : subsystems_)
if (
auto* p =
dynamic_cast<T*
>(s.get()))
return p;
274 bool admit_inbound()
override;
275 void on_established(Connection& conn)
override;
276 void on_frame(Connection& conn,
const Frame& frame)
override;
277 void on_closed(Connection& conn, CloseReason reason)
override;
278 void on_writable_changed(Connection& conn,
bool writable)
override;
279 void on_dial_aborted(uint8_t reactor_index, ConnId
id,
280 const std::string& host, uint16_t port)
override;
284 bool open_listeners();
286 void report_dial_failed(
const std::string& host, uint16_t port);
288 Peer make_peer(
const PeerId&
id, PeerRoute route) {
return Peer(
id, route, *
this); }
290 std::shared_ptr<std::atomic<size_t>> owed =
nullptr);
294 size_t send_low_water() const noexcept;
295 void route_close(PeerRoute route);
298 void send_identify(Connection& conn);
299 void handle_identify(Connection& conn, const
Frame& frame);
300 std::vector<
Address> advertised_addresses() const;
301 void rebuild_advertised_addresses(const
std::vector<
std::
string>& local_ips);
302 void record_observed_address(const
Address& addr);
305 bool is_own_endpoint(const
Address& addr) const;
307 void start_network_monitor();
308 void stop_network_monitor();
309 void maintenance_loop();
313 std::unique_ptr<SecurityProvider> security_;
315 MessageRouter router_;
318 std::unique_ptr<ReactorPool> reactors_;
319 std::unique_ptr<Dialer> dialer_;
326 std::unique_ptr<NetworkMonitor> monitor_;
327 std::thread maintenance_thread_;
328 std::mutex maintenance_mutex_;
329 std::condition_variable maintenance_cv_;
330 std::vector<
std::
string> pending_addresses_;
331 bool maintenance_pending_ = false;
332 bool maintenance_stop_ = false;
334 socket_t listen_socket_ = RATS_INVALID_SOCKET;
335 socket_t udp_socket_ = RATS_INVALID_SOCKET;
336 uint16_t listen_port_ = 0;
337 uint8_t transports_ = 0;
338 std::atomic<
bool> running_{
false};
339 std::atomic<size_t> max_peers_{0};
341 std::vector<PeerNetwork::PeerEventHandler> peer_connected_;
342 std::vector<PeerNetwork::PeerDisconnectHandler> peer_disconnected_;
343 std::vector<PeerNetwork::DialFailedHandler> dial_failed_;
344 std::vector<PeerNetwork::PeerEventHandler> peer_writable_;
347 mutable std::mutex observed_mutex_;
348 std::vector<Address> observed_addresses_;
354 NatStatus nat_status_;
360 mutable std::mutex advertised_mutex_;
361 std::vector<Address> advertised_addresses_;
A dialable transport endpoint: a numeric IP + port.
Turning a relayed byte stream into a peer connection — the capability a relay module needs and PeerNe...
Non-owning view over a contiguous run of bytes.
MessageJson * json() noexcept
The JSON messaging module if one was attached (add_subsystem<MessageJson>), else nullptr.
void wake_circuit(PeerRoute route, uint32_t events) override
Deliver poll-equivalent events (PollIn / PollOut / PollErr, see core/io_poller.h) to a circuit connec...
Node(NodeConfig config)
Construct a node from its configuration (see NodeConfig).
std::vector< Address > observed_addresses() const
Our own addresses as remote peers reported observing us at — their observed IP paired with our listen...
Node & operator=(const Node &)=delete
ServiceRegistry & services() noexcept
std::optional< PeerRoute > adopt_circuit(const PeerId &carrier, std::unique_ptr< Link > link, ConnRole role, bool connected) override
Adopt link as a connection carried by the peer carrier, on the reactor that owns the carrier's own co...
void connect(const Address &address) override
Dial a peer.
const std::string & protocol() const noexcept override
Application protocol identity bound into the handshake (see NodeConfig).
bool peer_writable(const PeerId &id) const override
Whether a peer's send queue has room for more.
bool peer_limit_reached() const noexcept
T * add_subsystem(std::unique_ptr< T > subsystem)
Attach a subsystem (DHT, GossipSub, PingService…).
void on_peer_disconnected(PeerNetwork::PeerDisconnectHandler cb) override
Subscribe to peer-disconnected events. The handler runs on a reactor thread.
void on_peer_connected(PeerNetwork::PeerEventHandler cb) override
Subscribe to peer-connected events. The handler runs on a reactor thread.
void on_dial_failed(PeerNetwork::DialFailedHandler cb) override
Subscribe to failed-outbound-dial events. The handler runs on a reactor thread.
const PeerId & local_id() const noexcept override
Our self-certifying peer identity (the public key peers authenticate).
uint8_t transports() const noexcept override
Transports this node is actually running, as a PeerTransports bitmask.
~Node() override
Stops the node if still running, then releases all resources.
bool broadcast(std::string_view channel, ByteView payload)
Send raw bytes on a named channel to every connected peer.
size_t peer_count() const noexcept
Number of currently-established peers.
uint16_t listen_port() const noexcept override
The bound listen port (the actual port when the config requested 0).
bool start()
Bring the node up: open the listener (if enabled), start the reactor pool, then start every attached ...
Node(const Node &)=delete
void connect(const std::string &host, uint16_t port)
Dial a peer.
EventBus & events() noexcept
std::vector< PeerInfo > peers() const override
Snapshot of all established peers (id, addresses, direction, timing).
void close_circuit(PeerRoute route, CloseReason reason) override
Tear a circuit connection down.
void set_max_peers(size_t n) noexcept
bool dial_direct(const Address &addr, TransportKind kind, const DialProfile &profile) override
Start exactly one dial to addr over kind, bypassing the transport race.
bool send(const PeerId &to, std::string_view channel, ByteView payload)
Send raw bytes to one peer on a named channel.
void on_peer_writable(PeerNetwork::PeerEventHandler cb) override
Subscribe to "this peer can be written to again" — fired when a peer whose send queue had filled past...
std::optional< Peer > peer(const PeerId &id)
Handle to a connected peer by id, or std::nullopt if not connected.
void stop()
Tear the node down: stop subsystems (reverse order), close all connections, and join the reactor pool...
const NatStatus & nat_status() const noexcept
What the mesh has shown about our own side of the NAT, from the endpoints datagram peers report obser...
void on(std::string_view channel, MessageRouter::Handler cb)
Register a handler for inbound messages on a named channel.
size_t max_peers() const noexcept
std::function< void(const Address &)> DialFailedHandler
std::function< void(const PeerId &, CloseReason)> PeerDisconnectHandler
A peer went away, and why.
std::function< void(const Peer &, ByteView)> MessageHandler
std::function< void(const Peer &)> PeerEventHandler
A pluggable network subsystem.
Node construction options.
Dialing a specific endpoint over a specific wire — the capability a NAT-traversal module needs and th...
MessageType
Inner-message kind. Application traffic uses App, addressed by channel.
std::vector< uint8_t > Bytes
What the mesh has told us about our own side of the NAT.
What a subsystem receives at attach() — the node's gift to its plugins.
A lightweight handle to a connected peer.
Self-certifying peer identity.
Addressing/metadata for a peer — the shareable, persistable identity.
The narrow contract a subsystem needs from the node — and nothing more.
A decoded inner message. payload is a non-owning view into the source bytes.