Back to Site
Loading...
Searching...
No Matches
peer_exchange.h File Reference

Peer exchange (PEX): peers gossip the addresses of peers they know, so a node bootstraps the mesh from its existing links — no DHT/tracker needed. More...

#include "librats/util/rats_export.h"
#include "librats/node/peer_network.h"
#include "librats/peer/peer.h"
#include "librats/peer/peer_id.h"
#include "librats/core/address.h"
#include <atomic>
#include <chrono>
#include <cstdint>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
Include dependency graph for peer_exchange.h:

Go to the source code of this file.

Classes

class  librats::PeerExchange
 
struct  librats::PeerExchange::Config
 

Namespaces

namespace  librats
 

Detailed Description

Peer exchange (PEX): peers gossip the addresses of peers they know, so a node bootstraps the mesh from its existing links — no DHT/tracker needed.

A Subsystem built on PeerNetwork, plus one optional capability: when a peer it discovered refuses to be dialed and HolePunch is present, it asks for a NAT hole punch to that peer's id instead of writing the peer off (see below). This first cut is deliberately pull-only: when we connect to a peer we ask it for some of its known peers, and it replies with a random sample (address + id). We then dial the ones we do not already have. Both sides must run PeerExchange — the responder needs it to answer the request.

It rides on the node's identify layer: identify is what fills in each peer's dialable address (an inbound peer's listen port is otherwise unknown), and PEX simply forwards those addresses on. A discovered peer we dial becomes an outbound link, so — paired with ReconnectionService — it is then persisted and kept alive automatically.

Wire format (MessageType::Pex payload), all integers big-endian: Request : [u8 ver=1][u8 op=0][u16 max] Response : [u8 ver=1][u8 op=1][u16 count] × { [u8 ip_len][ip][u16 port][32B peer_id] }

── Punch fallback ────────────────────────────────────────────────────────── A PEX entry carries an id and an address, which is exactly what a peer behind a NAT cannot be reached at: its advertised endpoint is unreachable from the outside, so the dial fails and the mesh silently stays one link short. That is the case HolePunch exists for, and PEX is the only module that holds both halves it needs — so each dial started here is remembered by address for punch_window, and if on_dial_failed reports that address back, the id is handed to HolePunchService. Entirely optional: with no HolePunch attached the lookup answers nullptr and the failure is simply the end of the story, as before.

Safety: response size is capped both sides; the receiver bounds how many it dials per response and de-duplicates dials with a TTL'd cooldown set (so a slow dial or a repeated response can't trigger a connect storm); malformed payloads are ignored, never fatal. public_only restricts sharing to globally-routable addresses for WAN deployments that must not relay private/LAN endpoints. The punch fallback inherits those bounds — one punch per dial we ourselves started, and HolePunch caps sessions and cooldowns on top of that.

Threading: handlers run on reactor threads (possibly several with a multi-reactor pool), so the cooldown set is mutex-guarded. The subsystem owns no thread.

Definition in file peer_exchange.h.