Back to Site
Loading...
Searching...
No Matches
node.h
Go to the documentation of this file.
1#pragma once
2
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/node_context.h" // NodeContext, EventBus, ServiceRegistry
57#include "librats/peer/peer.h"
59#include "librats/wire/message_router.h"
60
61#include <atomic>
62#include <condition_variable>
63#include <functional>
64#include <memory>
65#include <mutex>
66#include <optional>
67#include <string>
68#include <string_view>
69#include <thread>
70#include <type_traits>
71#include <vector>
72
73namespace librats {
74
75class NetworkMonitor; // util/network_monitor.h — owned via unique_ptr, included in node.cpp
76class MessageJson; // subsystems/message_json.h — reached via json() (json.h stays out of node.h)
77
78class RATS_API Node final : public ConnectionDelegate,
79 public PeerNetwork,
80 public DialService,
81 public CircuitService {
82public:
85 explicit Node(NodeConfig config);
87 ~Node() override;
88
89 Node(const Node&) = delete;
90 Node& operator=(const Node&) = delete;
91
98 template <class T>
99 T* add_subsystem(std::unique_ptr<T> subsystem) {
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)); // upcast to unique_ptr<Subsystem>
103 return raw;
104 }
105
110 bool start();
113 void stop();
114
116 const PeerId& local_id() const noexcept override { return identity_.id; }
119 uint16_t listen_port() const noexcept override { return listen_port_; }
120
124 uint8_t transports() const noexcept override { return transports_; }
125
127 const std::string& protocol() const noexcept override { return config_.protocol; }
128
129 // — node-scoped coordination, shared by subsystems and the app (see NodeContext) —
130 // events() : fire-and-forget notifications, one→many (host events, …)
131 // services() : targeted synchronous calls by capability interface, one→one
132 EventBus& events() noexcept { return events_; }
133 ServiceRegistry& services() noexcept { return services_; }
134
135 // — connections —
143 void connect(const Address& address) override;
145 void connect(const std::string& host, uint16_t port);
146
148 size_t peer_count() const noexcept { return peers_.size(); }
150 std::vector<PeerInfo> peers() const override { return peers_.snapshot(); }
152 std::optional<Peer> peer(const PeerId& id);
153
157 std::vector<Address> observed_addresses() const;
158
163 const NatStatus& nat_status() const noexcept { return nat_status_; }
164
165 // — DialService: dial one endpoint over one wire, bypassing the transport race
166 // (see node/dial_service.h; used by hole punching) —
167 bool dial_direct(const Address& addr, TransportKind kind,
168 const DialProfile& profile) override;
169
170 // — CircuitService: make a relayed byte stream an ordinary peer connection
171 // (see node/circuit_service.h; used by the relay module) —
172 std::optional<PeerRoute> adopt_circuit(const PeerId& carrier, std::unique_ptr<Link> link,
173 ConnRole role, bool connected) override;
174 void wake_circuit(PeerRoute route, uint32_t events) override;
175 void close_circuit(PeerRoute route, CloseReason reason) override;
176
177 // — peer admission limit (0 = unlimited; guards inbound, not our own dials) —
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); }
180 bool peer_limit_reached() const noexcept {
181 const size_t cap = max_peers_.load(std::memory_order_relaxed);
182 return cap != 0 && peers_.size() >= cap;
183 }
184
185 // — application messaging (raw bytes on a named channel) —
204 bool send(const PeerId& to, std::string_view channel, ByteView payload);
214 bool broadcast(std::string_view channel, ByteView payload);
215
233 bool peer_writable(const PeerId& id) const override;
234
235 // — events (register before start(); invoked on a reactor thread). Multiple
236 // listeners are supported, so subsystems and the app can both subscribe. —
238 void on_peer_connected(PeerNetwork::PeerEventHandler cb) override { peer_connected_.push_back(std::move(cb)); }
240 void on_peer_disconnected(PeerNetwork::PeerDisconnectHandler cb) override { peer_disconnected_.push_back(std::move(cb)); }
242 void on_dial_failed(PeerNetwork::DialFailedHandler cb) override { dial_failed_.push_back(std::move(cb)); }
247 void on_peer_writable(PeerNetwork::PeerEventHandler cb) override { peer_writable_.push_back(std::move(cb)); }
250 void on(std::string_view channel, MessageRouter::Handler cb) { router_.on_channel(channel, std::move(cb)); }
251
252 // — typed lookup of an attached subsystem (nullptr if none of that type) —
253 // reaches a module's own API without threading a pointer from add_subsystem:
254 // if (auto* j = node.json()) j->on("chat", …);
255 template <class T>
256 T* subsystem() noexcept {
257 for (auto& s : subsystems_) if (auto* p = dynamic_cast<T*>(s.get())) return p;
258 return nullptr;
259 }
262 MessageJson* json() noexcept;
263
264 // — PeerNetwork (for subsystems) —
265 bool send(const PeerId& to, MessageType type, ByteView payload) override;
266 bool broadcast(MessageType type, ByteView payload) override;
267 std::vector<PeerId> connected_peers() const override;
268 void on(MessageType type, PeerNetwork::MessageHandler cb) override { router_.on_type(type, std::move(cb)); }
269
270private:
271 friend class Peer;
272
273 // ConnectionDelegate (reactor thread)
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;
281
284 bool open_listeners();
286 void report_dial_failed(const std::string& host, uint16_t port);
287
288 Peer make_peer(const PeerId& id, PeerRoute route) { return Peer(id, route, *this); }
289 void route_send(PeerRoute route, FrameHeader header, Bytes payload,
290 std::shared_ptr<std::atomic<size_t>> owed = nullptr);
294 size_t send_low_water() const noexcept;
295 void route_close(PeerRoute route);
296
297 // — identify: how peers learn each other's dialable addresses (reactor thread) —
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;
306
307 void start_network_monitor();
308 void stop_network_monitor();
309 void maintenance_loop();
310
311 NodeConfig config_;
312 Identity identity_;
313 std::unique_ptr<SecurityProvider> security_;
314 PeerTable peers_;
315 MessageRouter router_;
316 EventBus events_;
317 ServiceRegistry services_;
318 std::unique_ptr<ReactorPool> reactors_;
319 std::unique_ptr<Dialer> dialer_;
320
321 std::vector<std::unique_ptr<Subsystem>> subsystems_;
322
323 // Host network-change watch. The monitor signals on its own thread; the
324 // maintenance thread does the (possibly blocking) EventBus emit off it, so
325 // subscribers may run slow recovery without stalling change detection.
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;
333
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};
340
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_;
345
346 // Our own addresses as peers observe us (their reported IP + our listen port).
347 mutable std::mutex observed_mutex_;
348 std::vector<Address> observed_addresses_;
349
350 // The datagram half of the same knowledge, which is a different thing: what a
351 // peer sees on a UDP link is our NAT's mapping of the one shared socket, port
352 // included, and several peers' views of it are what say whether that mapping is
353 // stable enough to punch through. Published as ExternalAddressService.
354 NatStatus nat_status_;
355
356 // The dialable addresses we advertise to peers in identify. Derived from local
357 // interfaces (and, in future, promoted observed addresses). Rebuilt once at
358 // start() and on NetworkMonitor changes — never re-enumerated per connection,
359 // since interface enumeration is a syscall and the send path is hot.
360 mutable std::mutex advertised_mutex_;
361 std::vector<Address> advertised_addresses_;
362};
363
364} // 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::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
Definition node.h:133
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).
Definition node.h:127
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:180
T * add_subsystem(std::unique_ptr< T > subsystem)
Attach a subsystem (DHT, GossipSub, PingService…).
Definition node.h:99
void on_peer_disconnected(PeerNetwork::PeerDisconnectHandler cb) override
Subscribe to peer-disconnected events. The handler runs on a reactor thread.
Definition node.h:240
void on_peer_connected(PeerNetwork::PeerEventHandler cb) override
Subscribe to peer-connected events. The handler runs on a reactor thread.
Definition node.h:238
void on_dial_failed(PeerNetwork::DialFailedHandler cb) override
Subscribe to failed-outbound-dial events. The handler runs on a reactor thread.
Definition node.h:242
const PeerId & local_id() const noexcept override
Our self-certifying peer identity (the public key peers authenticate).
Definition node.h:116
uint8_t transports() const noexcept override
Transports this node is actually running, as a PeerTransports bitmask.
Definition node.h:124
~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.
Definition node.h:148
uint16_t listen_port() const noexcept override
The bound listen port (the actual port when the config requested 0).
Definition node.h:119
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:132
std::vector< PeerInfo > peers() const override
Snapshot of all established peers (id, addresses, direction, timing).
Definition node.h:150
T * subsystem() noexcept
Definition node.h:256
void close_circuit(PeerRoute route, CloseReason reason) override
Tear a circuit connection down.
void set_max_peers(size_t n) noexcept
Definition node.h:179
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...
Definition node.h:247
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:163
void on(std::string_view channel, MessageRouter::Handler cb)
Register a handler for inbound messages on a named channel.
Definition node.h:250
size_t max_peers() const noexcept
Definition node.h:178
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...
Definition node.h:73
MessageType
Inner-message kind. Application traffic uses App, addressed by channel.
Definition frame.h:39
std::vector< uint8_t > Bytes
Definition bytes.h:24
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:53
A decoded inner message. payload is a non-owning view into the source bytes.
Definition frame.h:60