Back to Site
Loading...
Searching...
No Matches
hole_punch.h
Go to the documentation of this file.
1#pragma once
2
90#include "librats/util/rats_export.h"
92#include "librats/core/types.h"
95#include "librats/peer/peer.h"
99
100#include <atomic>
101#include <chrono>
102#include <condition_variable>
103#include <cstdint>
104#include <mutex>
105#include <thread>
106#include <unordered_map>
107#include <vector>
108
109namespace librats {
110
111class DialService;
112class ServiceRegistry;
113
116class RATS_API HolePunch final : public Subsystem, public HolePunchService {
117public:
118 struct Config {
123 size_t max_relays = 3;
124
127 size_t max_addresses = 4;
128
130 int attempts = 3;
131
134 std::chrono::milliseconds round_timeout{6000};
135
140 std::chrono::milliseconds cooldown{60000};
141
144 size_t max_sessions = 32;
145
149 bool enable_relay = true;
150
154 size_t relay_budget = 12;
155 std::chrono::milliseconds relay_window{1000};
156
161 bool skip_when_endpoint_dependent = true;
162
164 DialProfile profile = DialProfile::punch();
165
167 std::chrono::milliseconds tick{250};
168
173 bool relay_on_failure = true;
174 };
175
177 explicit HolePunch(Config config);
178 ~HolePunch() override;
179
180 void attach(NodeContext& ctx) override;
181 void start() override;
182 void stop() override;
183
190 bool punch(const PeerId& target) override;
191
193 size_t active_sessions() const;
195 uint64_t punches_started() const noexcept { return punches_started_.load(); }
197 uint64_t relayed() const noexcept { return relayed_.load(); }
198
199private:
200 enum class Phase : uint8_t {
201 AwaitingPeerConnect,
202 AwaitingSync,
203 Punching,
204 };
205
206 struct Session {
207 bool initiator = false;
208 Phase phase = Phase::AwaitingPeerConnect;
209 int attempt = 0;
210 std::vector<Address> peer_addresses;
211 std::chrono::steady_clock::time_point deadline{};
216 PeerId via{};
217 bool have_via = false;
218 };
219
220 // — message handling (reactor threads) —
221 void handle(const Peer& from, ByteView payload);
222 void handle_relay_request(const Peer& from, const PeerId& dst, ByteView inner);
223 void handle_relayed(const Peer& via, const PeerId& src, ByteView inner);
226 void handle_connect(const Peer& via, const PeerId& src, bool opening,
227 std::vector<Address> addresses);
228 void handle_sync(const PeerId& src);
229
230 // — outgoing —
234 size_t relay_to(const PeerId& dst, const Bytes& inner, const PeerId* via);
235 bool send_connect(const PeerId& target, bool opening, const PeerId* via);
236 void send_sync(const PeerId& target, const PeerId* via);
239 void fire_punch(const PeerId& target, const std::vector<Address>& addresses);
240
241 // — worker —
242 void loop();
243 void service_sessions();
244
245 // — helpers —
252 void escalate_to_relay(const PeerId& target);
256 std::vector<PeerId> directly_connected() const;
257 std::vector<Address> own_punch_addresses() const;
258 bool relay_budget_ok(const PeerId& from);
259 bool in_cooldown(const PeerId& target) const;
260 void begin_cooldown(const PeerId& target);
261
262 Config config_;
263 PeerNetwork* network_ = nullptr;
264 DialService* dialer_ = nullptr;
265 ExternalAddressService* external_ = nullptr;
266 ServiceRegistry* services_ = nullptr;
270 std::atomic<RelayService*> relay_{nullptr};
271
272 std::atomic<bool> running_{false};
273 std::atomic<uint64_t> punches_started_{0};
274 std::atomic<uint64_t> relayed_{0};
275
276 mutable std::mutex mutex_;
277 std::condition_variable cv_;
278 std::thread worker_;
279 std::unordered_map<PeerId, Session, PeerId::Hash> sessions_;
280 std::unordered_map<PeerId, std::chrono::steady_clock::time_point, PeerId::Hash> cooldown_;
281
282 struct RelayBudget {
283 std::chrono::steady_clock::time_point window_started{};
284 size_t spent = 0;
285 };
286 std::mutex relay_mutex_;
287 std::unordered_map<PeerId, RelayBudget, PeerId::Hash> relay_budget_;
288};
289
290} // namespace librats
A dialable transport endpoint: a numeric IP + port.
Published as HolePunchService, so a module that discovers a peer it cannot dial (PeerExchange) can ha...
Definition hole_punch.h:116
uint64_t relayed() const noexcept
Messages forwarded on behalf of other peers (diagnostics and tests).
Definition hole_punch.h:197
~HolePunch() override
void stop() override
size_t active_sessions() const
Sessions currently in flight (diagnostics and tests).
void attach(NodeContext &ctx) override
bool punch(const PeerId &target) override
Try to reach target by punching.
uint64_t punches_started() const noexcept
Punch bursts this node has fired (diagnostics and tests).
Definition hole_punch.h:195
void start() override
HolePunch(Config config)
A pluggable network subsystem.
Capability that lets a sibling module ask for a NAT hole punch by PeerId.
Definition node.h:73
What the mesh has told us about our own side of the NAT.
A lightweight handle to a connected peer.
Self-certifying peer identity.
The narrow contract a subsystem needs from the node — and nothing more.
Capability that lets a sibling module ask for a peer to be reached through a third node,...