58#include "librats/util/rats_export.h"
61#include "librats/dht/dht.h"
65#include <condition_variable>
72#include <unordered_map>
78class ReflexiveAddressService;
91 std::vector<std::string>
keys;
137 using Clock = std::chrono::steady_clock;
141 Redials(std::chrono::milliseconds every, std::chrono::milliseconds dial_for,
142 std::chrono::milliseconds slow)
143 : every_(every), for_(dial_for), slow_(slow) {}
150 std::vector<Address>
due(Clock::time_point now);
159 size_t size()
const {
return found_.size(); }
163 Clock::time_point first;
164 Clock::time_point last;
165 Clock::time_point seen;
167 std::chrono::milliseconds every_;
168 std::chrono::milliseconds for_;
169 std::chrono::milliseconds slow_;
170 std::unordered_map<Address, Dialed> found_;
185 DhtClient*
dht_client()
override {
return dht_ ? dht_.get() : dht6_.get(); }
199 enum class Use : uint8_t { Announce = 1, Search = 2, Both = 3 };
210 void set_keys(
const std::vector<std::string>& keys);
233 bool probe_external_ip();
234 void on_peers(
const std::vector<Address>& peers,
const InfoHash& info_hash);
237 bool searches(
const InfoHash& hash)
const;
241 std::vector<Address> connected_addresses()
const;
243 void punch_due(std::chrono::steady_clock::time_point now);
245 uint16_t announced_port(
bool v6 =
false)
const;
249 std::unique_ptr<DhtClient> make_client(AddressFamily family);
256 void refresh_own_ips();
259 template <
typename Fn>
260 void for_each_client(Fn fn) {
262 if (dht6_) fn(*dht6_);
270 std::optional<std::chrono::steady_clock::time_point> announced[2];
271 bool searched =
false;
275 mutable std::mutex keys_mutex_;
276 std::vector<Announced> hashes_;
277 bool keys_set_ =
false;
278 PeerNetwork* network_ =
nullptr;
279 DialService* dial_ =
nullptr;
280 ReflexiveAddressService* reflexive_ =
nullptr;
281 std::unique_ptr<DhtClient> dht_;
282 std::unique_ptr<DhtClient> dht6_;
285 std::atomic<bool> running_{
false};
286 std::atomic<bool> recover_pending_{
false};
287 std::atomic<bool> announce_pending_{
false};
288 std::atomic<bool> keys_pending_{
false};
289 std::atomic<bool> punch_pending_{
false};
290 std::atomic<uint16_t> mapped_port_{0};
291 std::atomic<uint16_t> reflexive_port_{0};
292 bool mapping_checked_ =
false;
293 std::optional<Address> last_seen_;
295 mutable std::mutex own_mutex_;
296 std::vector<IpAddress> own_local_;
297 std::optional<IpAddress> own_seen_;
298 std::optional<IpAddress> own_mapped_;
299 std::mutex wait_mutex_;
300 std::condition_variable wake_;
302 std::mutex dialed_mutex_;
Redials(std::chrono::milliseconds every, std::chrono::milliseconds dial_for, std::chrono::milliseconds slow)
Punched every every for dial_for after first found (due()); then, as found again, every slow at most ...
void connected(const Address &address)
address found connected: once its link is gone, it is dialed as though found for the first time.
std::optional< Clock::time_point > next_due() const
When the next of those is due; none: none is in its first stretch.
void forget_older_than(Clock::time_point before)
Forget what has not been found for a while: the DHT stops handing out an address half an hour after i...
std::chrono::steady_clock Clock
std::vector< Address > due(Clock::time_point now)
The addresses whose punch is due at now in their first stretch (dial_for after first found),...
Dial found(const Address &address, Clock::time_point now)
address found at now, not connected.
bool is_own(const Address &address) const
Whether address is this node's own, as a key it announces and searches hands it back: an IP of this h...
void set_keys(const std::vector< std::string > &keys)
std::vector< InfoHash > discovery_hashes() const
InfoHash discovery_hash() const
The first key's hash (the only one, unless keys were given).
uint16_t dht_port_v6() const
IPv6 DHT UDP port (0 if not running).
std::string external_address() const
Our external (public) IP currently used to derive the DHT node id, learned via STUN at startup or in-...
void set_keys(const std::vector< Key > &keys)
The keys announced and searched from now on, in place of those before (a key twice: what both say): o...
DhtDiscovery(Config config)
static InfoHash hash_for_key(const std::string &key)
Map an application key to a stable 20-byte discovery hash (SHA-1).
uint16_t dht_port() const
IPv4 DHT UDP port (0 if not running).
DhtClient * dht_client() override
DhtService: hand out the live Kademlia node so siblings (e.g.
Use
What is done with a key: announced, so that the node is found under it; searched, so that it finds wh...
void attach(NodeContext &ctx) override
A pluggable network subsystem.
Capability that hands out the node-owned DhtClient to sibling modules.
The narrow contract a subsystem needs from the node — and nothing more.
std::chrono::milliseconds stun_every
STUN is asked again this often, on the search round it falls in — after a round with no answer,...
std::vector< std::string > keys
The keys to announce and search, in place of discovery_key when not empty (set_keys() changes them as...
std::string data_dir
routing-table persistence dir (empty = cwd). Set to the node's data_dir to co-locate state.
bool enable_ipv4
run the IPv4 Kademlia network
std::vector< HostEndpoint > bootstrap_nodes
empty → default internet nodes
uint16_t dht_port
0 = ephemeral
std::chrono::milliseconds announce_interval
every 30 seconds
std::chrono::milliseconds search_interval
std::vector< HostEndpoint > stun_servers
empty → built-in public defaults
std::chrono::milliseconds redial_for
bool enable_ipv6
run the IPv6 Kademlia network (BEP 32)
std::chrono::milliseconds redial_slow
After redial_for: punched again each time the DHT hands it out again, at most this often,...
bool discover_external_ip
Ask STUN where we are: the public IP seeds the DHT node id per BEP 42 (without it we still converge v...
std::chrono::milliseconds redial_every
A peer found and not connected is punched this often, found again or not, for this long after it was ...
std::string discovery_key
DHT namespace.
std::chrono::milliseconds stun_timeout