Back to Site
Loading...
Searching...
No Matches
node.h
Go to the documentation of this file.
1#pragma once
2
41
42#include "librats/util/rats_export.h"
43#include "librats/transport/connection.h" // ConnectionDelegate
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" // SecurityProvider
52#include "librats/node/config.h"
54#include "librats/node/dialer.h"
56#include "librats/node/reflexive_probe.h"
57#include "librats/node/node_context.h" // NodeContext, EventBus, ServiceRegistry
58#include "librats/peer/peer.h"
60#include "librats/wire/message_router.h"
61
62#include <atomic>
63#include <condition_variable>
64#include <functional>
65#include <memory>
66#include <mutex>
67#include <optional>
68#include <string>
69#include <string_view>
70#include <thread>
71#include <type_traits>
72#include <unordered_map>
73#include <vector>
74
75namespace librats {
76
77class NetworkMonitor; // util/network_monitor.h — owned via unique_ptr, included in node.cpp
78class MessageJson; // subsystems/message_json.h — reached via json() (json.h stays out of node.h)
79
80class RATS_API Node final : public ConnectionDelegate,
81 public PeerNetwork,
82 public DialService,
83 public CircuitService {
84public:
87 explicit Node(NodeConfig config);
89 ~Node() override;
90
91 Node(const Node&) = delete;
92 Node& operator=(const Node&) = delete;
93
100 template <class T>
101 T* add_subsystem(std::unique_ptr<T> subsystem) {
102 static_assert(std::is_base_of<Subsystem, T>::value, "T must derive from Subsystem");
103 T* raw = subsystem.get();
104 subsystems_.push_back(std::move(subsystem)); // upcast to unique_ptr<Subsystem>
105 return raw;
106 }
107
112 bool start();
115 void stop();
116
118 const PeerId& local_id() const noexcept override { return identity_.id; }
121 uint16_t listen_port() const noexcept override { return listen_port_; }
122
126 uint8_t transports() const noexcept override { return transports_; }
127
129 const std::string& protocol() const noexcept override { return config_.protocol; }
130
131 // — node-scoped coordination, shared by subsystems and the app (see NodeContext) —
132 // events() : fire-and-forget notifications, one→many (host events, …)
133 // services() : targeted synchronous calls by capability interface, one→one
134 EventBus& events() noexcept { return events_; }
135 ServiceRegistry& services() noexcept { return services_; }
136
137 // — connections —
145 void connect(const Address& address) override;
147 void connect(const std::string& host, uint16_t port);
148
150 size_t peer_count() const noexcept { return peers_.size(); }
154 size_t standbys() const;
156 std::vector<PeerInfo> peers() const override { return peers_.snapshot(); }
158 std::optional<Peer> peer(const PeerId& id);
159
163 std::vector<Address> observed_addresses() const;
164
169 const NatStatus& nat_status() const noexcept { return nat_status_; }
170
171 // — DialService: dial one endpoint over one wire, bypassing the transport race
172 // (see node/dial_service.h; used by hole punching) —
173 bool dial_direct(const Address& addr, TransportKind kind,
174 const DialProfile& profile) override;
175
176 // — CircuitService: make a relayed byte stream an ordinary peer connection
177 // (see node/circuit_service.h; used by the relay module) —
178 std::optional<PeerRoute> adopt_circuit(const PeerId& carrier, std::unique_ptr<Link> link,
179 ConnRole role, bool connected) override;
180 void wake_circuit(PeerRoute route, uint32_t events) override;
181 void close_circuit(PeerRoute route, CloseReason reason) override;
182 std::optional<PeerRoute> dial_relayed(const PeerId& carrier, uint64_t cid,
183 ForwardedCircuit circuit) override;
184 std::optional<PeerRoute> expect_relayed(const PeerId& carrier, uint64_t cid,
185 ForwardedCircuit circuit) override;
186 bool forward_datagrams(const PeerId& dialer, const PeerId& responder,
187 uint64_t cid,
188 std::shared_ptr<std::atomic<uint64_t>> bytes,
189 uint64_t rate, uint64_t burst) override;
190 void stop_forwarding(uint64_t cid) override;
191
192 // — peer admission limit (0 = unlimited; guards inbound, not our own dials) —
193 size_t max_peers() const noexcept { return max_peers_.load(std::memory_order_relaxed); }
194 void set_max_peers(size_t n) noexcept { max_peers_.store(n, std::memory_order_relaxed); }
195 bool peer_limit_reached() const noexcept {
196 const size_t cap = max_peers_.load(std::memory_order_relaxed);
197 return cap != 0 && peers_.size() >= cap;
198 }
199
200 // — application messaging (raw bytes on a named channel) —
222 bool send(const PeerId& to, std::string_view channel, ByteView payload, SendOptions options = {});
232 bool broadcast(std::string_view channel, ByteView payload, SendOptions options = {});
233
251 bool peer_writable(const PeerId& id) const override;
252
253 // — events (register before start(); invoked on a reactor thread). Multiple
254 // listeners are supported, so subsystems and the app can both subscribe. —
256 void on_peer_connected(PeerNetwork::PeerEventHandler cb) override { peer_connected_.push_back(std::move(cb)); }
258 void on_peer_disconnected(PeerNetwork::PeerDisconnectHandler cb) override { peer_disconnected_.push_back(std::move(cb)); }
260 void on_dial_failed(PeerNetwork::DialFailedHandler cb) override { dial_failed_.push_back(std::move(cb)); }
265 void on_peer_writable(PeerNetwork::PeerEventHandler cb) override { peer_writable_.push_back(std::move(cb)); }
268 void on_peer_rerouted(PeerNetwork::PeerEventHandler cb) override { peer_rerouted_.push_back(std::move(cb)); }
271 void on_peer_moved(PeerNetwork::PeerEventHandler cb) override { peer_moved_.push_back(std::move(cb)); }
277 void on_peer_path(PeerNetwork::PeerPathHandler cb) override { peer_path_.push_back(std::move(cb)); }
282 live_outcome_.emplace_back(type, std::move(cb));
283 }
284
287 std::optional<PathStats> path_stats(const PeerId& id) const override { return peers_.path(id); }
288 void set_send_ceiling(const PeerId& id, uint64_t bits_per_second) override;
291 void on(std::string_view channel, MessageRouter::Handler cb) { router_.on_channel(channel, std::move(cb)); }
292
293 // — typed lookup of an attached subsystem (nullptr if none of that type) —
294 // reaches a module's own API without threading a pointer from add_subsystem:
295 // if (auto* j = node.json()) j->on("chat", …);
296 template <class T>
297 T* subsystem() noexcept {
298 for (auto& s : subsystems_) if (auto* p = dynamic_cast<T*>(s.get())) return p;
299 return nullptr;
300 }
301
303 MessageJson* json() noexcept;
304
305 // — PeerNetwork (for subsystems) —
306 bool send(const PeerId& to, MessageType type, ByteView payload,
307 SendOptions options = {}) override;
308 bool broadcast(MessageType type, ByteView payload, SendOptions options = {}) override;
309 std::vector<PeerId> connected_peers() const override;
310 void on(MessageType type, PeerNetwork::MessageHandler cb) override { router_.on_type(type, std::move(cb)); }
312 router_.on_type(type, std::move(cb));
313 }
314
315private:
316 friend class Peer;
317
318 // ConnectionDelegate (reactor thread)
319 bool admit_inbound() override;
320 void on_established(Connection& conn) override;
321 void on_frame(Connection& conn, const Frame& frame) override;
322 void on_closed(Connection& conn, CloseReason reason) override;
323 void on_writable_changed(Connection& conn, bool writable) override;
324 void on_path_sample(Connection& conn, const PathStats& stats) override;
325 void on_moved(Connection& conn) override;
326 void on_live_outcome(Connection& conn, const LiveOutcome& outcome) override;
327 void on_dial_aborted(uint8_t reactor_index, ConnId id,
328 const std::string& host, uint16_t port) override;
329
332 bool open_listeners();
334 void report_dial_failed(const std::string& host, uint16_t port);
336 std::optional<PeerRoute> datagram_route(const PeerId& id) const;
337
338 Peer make_peer(const PeerId& id, PeerRoute route) { return Peer(id, route, *this); }
341 void route_send(PeerRoute route, FrameHeader header, Bytes payload, Deadline deadline,
342 uint64_t tag, uint8_t rank, std::shared_ptr<std::atomic<size_t>> owed);
344 bool send_to(const PeerId& to, FrameHeader header, ByteView payload, SendOptions options);
345 bool broadcast_all(FrameHeader header, ByteView payload, SendOptions options);
349 size_t send_low_water() const noexcept;
350 void route_close(PeerRoute route);
352 void close_duplicate(PeerRoute route);
355 void take_up(Connection& conn);
356
357 // — standby: a duplicate held in case the link it lost to has gone dead —
360 void hold_standby(const PeerInfo& info, PeerRoute route);
362 void watch_standby(const PeerId& id, uint64_t watch);
365 void check_standby(const PeerId& id, uint8_t reactor, uint64_t watch);
368 bool take_over(const PeerId& id, PeerRoute from, bool close_from);
369
370 // — identify: how peers learn each other's dialable addresses (reactor thread) —
371 void send_identify(Connection& conn);
372 void handle_identify(Connection& conn, const Frame& frame);
373 std::vector<Address> advertised_addresses() const;
374 void rebuild_advertised_addresses(const std::vector<std::string>& local_ips);
375 void record_observed_address(const Address& addr);
378 bool is_own_endpoint(const Address& addr) const;
379
380 void start_network_monitor();
381 void stop_network_monitor();
382 void maintenance_loop();
383
384 NodeConfig config_;
385 Identity identity_;
386 std::unique_ptr<SecurityProvider> security_;
387 PeerTable peers_;
388 MessageRouter router_;
389 EventBus events_;
390 ServiceRegistry services_;
391 std::unique_ptr<ReactorPool> reactors_;
392 std::unique_ptr<Dialer> dialer_;
393
394 std::vector<std::unique_ptr<Subsystem>> subsystems_;
395
396 // Host network-change watch. The monitor signals on its own thread; the
397 // maintenance thread does the (possibly blocking) EventBus emit off it, so
398 // subscribers may run slow recovery without stalling change detection.
399 std::unique_ptr<NetworkMonitor> monitor_;
400 std::thread maintenance_thread_;
401 std::mutex maintenance_mutex_;
402 std::condition_variable maintenance_cv_;
403 std::vector<std::string> pending_addresses_;
404 bool maintenance_pending_ = false;
405 bool maintenance_stop_ = false;
406
407 socket_t listen_socket_ = RATS_INVALID_SOCKET;
408 socket_t udp_socket_ = RATS_INVALID_SOCKET;
409 uint16_t listen_port_ = 0;
410 uint8_t transports_ = 0;
411 std::atomic<bool> running_{false};
412 std::atomic<size_t> max_peers_{0};
413
414 std::vector<PeerNetwork::PeerEventHandler> peer_connected_;
415 std::vector<PeerNetwork::PeerDisconnectHandler> peer_disconnected_;
416 std::vector<PeerNetwork::DialFailedHandler> dial_failed_;
417 std::vector<PeerNetwork::PeerEventHandler> peer_writable_;
418 std::vector<PeerNetwork::PeerEventHandler> peer_rerouted_;
419 std::vector<PeerNetwork::PeerEventHandler> peer_moved_;
420 std::vector<PeerNetwork::PeerPathHandler> peer_path_;
421 std::vector<std::pair<MessageType, PeerNetwork::LiveOutcomeHandler>> live_outcome_;
422
423 // Standbys by peer: what a duplicate connection the peer table turned down
424 // is, while it is held (hold_standby).
425 struct Standby {
426 PeerInfo info;
427 PeerRoute route;
428 std::chrono::steady_clock::time_point until;
429 uint64_t watch = 0;
430 };
431 mutable std::mutex standby_mutex_;
432 std::unordered_map<PeerId, Standby, PeerId::Hash> standbys_;
433 uint64_t standby_watches_ = 0;
434
435 // Send ceilings by peer (set_send_ceiling), for the link that carries it now
436 // and any it moves to.
437 mutable std::mutex ceilings_mutex_;
438 std::unordered_map<PeerId, uint64_t, PeerId::Hash> ceilings_;
439
440 // Our own addresses as peers observe us (their reported IP + our listen port).
441 mutable std::mutex observed_mutex_;
442 std::vector<Address> observed_addresses_;
443
444 // The datagram half of the same knowledge, which is a different thing: what a
445 // peer sees on a UDP link is our NAT's mapping of the one shared socket, port
446 // included, and several peers' views of it are what say whether that mapping is
447 // stable enough to punch through. Published as ExternalAddressService.
448 NatStatus nat_status_;
449 // And asked of STUN, from that socket, before any peer has said: published as
450 // ReflexiveAddressService.
451 ReflexiveProbe reflexive_;
452
453 // The dialable addresses we advertise to peers in identify. Derived from local
454 // interfaces (and, in future, promoted observed addresses). Rebuilt once at
455 // start() and on NetworkMonitor changes — never re-enumerated per connection,
456 // since interface enumeration is a syscall and the send path is hot.
457 mutable std::mutex advertised_mutex_;
458 std::vector<Address> advertised_addresses_;
459};
460
461} // namespace librats
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.
Definition bytes.h:27
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::optional< PathStats > path_stats(const PeerId &id) const override
The latest path sample for a peer — safe from any thread.
Definition node.h:287
std::vector< Address > observed_addresses() const
Our own addresses as remote peers reported observing us at — their observed IP paired with our listen...
void on_peer_moved(PeerNetwork::PeerEventHandler cb) override
Subscribe to "the path to this peer changed: one end moved" (see PeerNetwork::on_peer_moved).
Definition node.h:271
Node & operator=(const Node &)=delete
ServiceRegistry & services() noexcept
Definition node.h:135
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...
std::optional< PeerRoute > expect_relayed(const PeerId &carrier, uint64_t cid, ForwardedCircuit circuit) override
Accept the dial that will come through carrier, the relay, as an Inbound connection — under the same ...
void connect(const Address &address) override
Dial a peer.
std::optional< PeerRoute > dial_relayed(const PeerId &carrier, uint64_t cid, ForwardedCircuit circuit) override
Dial the far end through carrier, the relay. The connection is Outbound.
void stop_forwarding(uint64_t cid) override
const std::string & protocol() const noexcept override
Application protocol identity bound into the handshake (see NodeConfig).
Definition node.h:129
std::vector< PeerId > connected_peers() const override
bool peer_writable(const PeerId &id) const override
Whether a peer's send queue has room for more.
bool peer_limit_reached() const noexcept
Definition node.h:195
T * add_subsystem(std::unique_ptr< T > subsystem)
Attach a subsystem (DHT, GossipSub, PingService…).
Definition node.h:101
void on_peer_disconnected(PeerNetwork::PeerDisconnectHandler cb) override
Subscribe to peer-disconnected events. The handler runs on a reactor thread.
Definition node.h:258
void on_peer_connected(PeerNetwork::PeerEventHandler cb) override
Subscribe to peer-connected events. The handler runs on a reactor thread.
Definition node.h:256
void on_dial_failed(PeerNetwork::DialFailedHandler cb) override
Subscribe to failed-outbound-dial events. The handler runs on a reactor thread.
Definition node.h:260
const PeerId & local_id() const noexcept override
Our self-certifying peer identity (the public key peers authenticate).
Definition node.h:118
bool broadcast(std::string_view channel, ByteView payload, SendOptions options={})
Send raw bytes on a named channel to every connected peer.
size_t standbys() const
Links held as standbys now: duplicates the peer table turned down, kept a while in case the one they ...
uint8_t transports() const noexcept override
Transports this node is actually running, as a PeerTransports bitmask.
Definition node.h:126
~Node() override
Stops the node if still running, then releases all resources.
void set_send_ceiling(const PeerId &id, uint64_t bits_per_second) override
Send to id no faster than bits_per_second, whatever its congestion controller paces at; 0 lifts the c...
void on(MessageType type, PeerNetwork::MessageHandler cb) override
Definition node.h:310
void on_peer_rerouted(PeerNetwork::PeerEventHandler cb) override
Subscribe to "this peer's traffic moved to another connection" (see PeerNetwork::on_peer_rerouted).
Definition node.h:268
size_t peer_count() const noexcept
Number of currently-established peers.
Definition node.h:150
friend class Peer
Definition node.h:316
uint16_t listen_port() const noexcept override
The bound listen port (the actual port when the config requested 0).
Definition node.h:121
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
Definition node.h:134
void on_with_deadline(MessageType type, PeerNetwork::DeadlineMessageHandler cb) override
on(), with each message's deadline.
Definition node.h:311
bool broadcast(MessageType type, ByteView payload, SendOptions options={}) override
Send to every connected peer.
std::vector< PeerInfo > peers() const override
Snapshot of all established peers (id, addresses, direction, timing).
Definition node.h:156
bool send(const PeerId &to, std::string_view channel, ByteView payload, SendOptions options={})
Send raw bytes to one peer on a named channel.
T * subsystem() noexcept
Definition node.h:297
void close_circuit(PeerRoute route, CloseReason reason) override
Tear a circuit connection down.
void on_peer_path(PeerNetwork::PeerPathHandler cb) override
Subscribe to periodic path samples of every connected peer (see PathStats): the estimate to size a li...
Definition node.h:277
void set_max_peers(size_t n) noexcept
Definition node.h:194
bool dial_direct(const Address &addr, TransportKind kind, const DialProfile &profile) override
Start exactly one dial to addr over kind, bypassing the transport race.
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...
Definition node.h:265
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...
Definition node.h:169
void on(std::string_view channel, MessageRouter::Handler cb)
Register a handler for inbound messages on a named channel.
Definition node.h:291
bool forward_datagrams(const PeerId &dialer, const PeerId &responder, uint64_t cid, std::shared_ptr< std::atomic< uint64_t > > bytes, uint64_t rate, uint64_t burst) override
As the relay: forward the packets of cid between dialer and responder, counting their bytes into byte...
void on_live_outcome(MessageType type, PeerNetwork::LiveOutcomeHandler cb) override
Subscribe to what becomes of the live messages of type sent with a tag (SendOptions::tag): delivered,...
Definition node.h:281
size_t max_peers() const noexcept
Definition node.h:193
std::function< void(const Peer &, ByteView, Deadline)> DeadlineMessageHandler
A message handler that is also told each message's deadline: for a live one (SendOptions::lifetime),...
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 &, const PathStats &)> PeerPathHandler
std::function< void(const Peer &, uint64_t tag, bool delivered)> LiveOutcomeHandler
What became of a live message sent with a tag: delivered, or given up on (see LiveOutcome).
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...
Definition node.h:75
std::vector< uint8_t > Bytes
Definition bytes.h:24
MessageType
Inner-message kind. Application traffic uses App, addressed by channel.
Definition frame.h:40
STL namespace.
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.
Fixed header of an inner message.
Definition frame.h:56
A decoded inner message. payload is a non-owning view into the source bytes.
Definition frame.h:63
What became of a live message sent with a tag (SendOptions::tag), as far as its sender can tell.
Definition frame.h:78