26#include "network_engine.h"
28#include "routing_table.h"
30#include "dht_interface.h"
85 return std::max(getStatus(AF_INET), getStatus(AF_INET6));
101 virtual void registerType(
const ValueType& type) {
102 types.registerType(type);
104 const ValueType& getType(ValueType::Id type_id)
const {
105 return types.getType(type_id);
114 void insertNode(
const InfoHash&
id,
const sockaddr* sa, socklen_t salen) {
115 insertNode(
id,
SockAddr(sa, salen));
118 insertNode(n.id,
SockAddr(n.ss, n.sslen));
121 void pingNode(
const sockaddr*, socklen_t, DoneCallbackSimple&& cb={});
123 time_point periodic(
const uint8_t *buf,
size_t buflen,
const SockAddr&);
124 time_point periodic(
const uint8_t *buf,
size_t buflen,
const sockaddr* from, socklen_t fromlen) {
125 return periodic(buf, buflen, SockAddr(from, fromlen));
139 virtual void get(
const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) {
140 get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
142 virtual void get(
const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) {
143 get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
145 virtual void get(
const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) {
146 get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
158 virtual void query(
const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {},
Query&& q = {});
159 virtual void query(
const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) {
160 query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
181 DoneCallback cb=
nullptr,
182 time_point created=time_point::max(),
183 bool permanent =
false);
186 DoneCallbackSimple cb,
187 time_point created=time_point::max(),
188 bool permanent =
false)
190 put(key, v, bindDoneCb(cb), created, permanent);
195 DoneCallback cb=
nullptr,
196 time_point created=time_point::max(),
197 bool permanent =
false)
199 put(key, std::make_shared<Value>(std::move(v)), cb, created, permanent);
201 void put(
const InfoHash& key,
203 DoneCallbackSimple cb,
204 time_point created=time_point::max(),
205 bool permanent =
false)
207 put(key, std::forward<Value>(v), bindDoneCb(cb), created, permanent);
236 return listen(key, [cb](
const std::vector<Sp<Value>>& vals,
bool expired){
240 }, std::forward<Value::Filter>(f), std::forward<Where>(w));
242 virtual size_t listen(
const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) {
243 return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
246 virtual bool cancelListen(
const InfoHash&,
size_t token);
254 void connectivityChanged() {
255 reported_addr.clear();
256 connectivityChanged(AF_INET);
257 connectivityChanged(AF_INET6);
266 std::vector<ValuesExport> exportValues()
const;
267 void importValues(
const std::vector<ValuesExport>&);
269 NodeStats getNodesStats(sa_family_t af)
const;
271 std::string getStorageLog()
const;
272 std::string getStorageLog(
const InfoHash&)
const;
274 std::string getRoutingTablesLog(sa_family_t)
const;
275 std::string getSearchesLog(sa_family_t)
const;
276 std::string getSearchLog(
const InfoHash&, sa_family_t af = AF_UNSPEC)
const;
278 void dumpTables()
const;
279 std::vector<unsigned> getNodeMessageStats(
bool in =
false) {
280 return network_engine.getNodeMessageStats(in);
287 max_store_size = limit;
295 return {total_store_size, total_values};
298 std::vector<SockAddr> getPublicAddress(sa_family_t family = 0);
301 void resubscribe(
unsigned) {}
308 static constexpr unsigned SEARCH_NODES {14};
318 static constexpr unsigned SEARCH_MAX_BAD_NODES {25};
321 static constexpr unsigned MAX_REQUESTED_SEARCH_NODES {4};
324 static constexpr unsigned LISTEN_NODES {4};
327 static constexpr unsigned MAX_HASHES {16384};
330 static constexpr unsigned MAX_SEARCHES {16384};
332 static constexpr std::chrono::minutes MAX_STORAGE_MAINTENANCE_EXPIRE_TIME {10};
335 static constexpr std::chrono::minutes SEARCH_EXPIRE_TIME {62};
338 static constexpr std::chrono::seconds LISTEN_EXPIRE_TIME {30};
340 static constexpr std::chrono::seconds REANNOUNCE_MARGIN {10};
342 static constexpr size_t TOKEN_SIZE {32};
351 Dht(
const Dht&) =
delete;
352 Dht& operator=(
const Dht&) =
delete;
357 uint64_t oldsecret {};
366 const bool is_bootstrap {
false};
367 const bool maintain_storage {
false};
370 RoutingTable buckets4 {};
371 RoutingTable buckets6 {};
373 std::map<InfoHash, Storage> store;
374 std::map<SockAddr, StorageBucket, SockAddr::ipCmp> store_quota;
375 size_t total_values {0};
376 size_t total_store_size {0};
377 size_t max_store_size {DEFAULT_STORAGE_LIMIT};
379 using SearchMap = std::map<InfoHash, Sp<Search>>;
380 SearchMap searches4 {};
381 SearchMap searches6 {};
382 uint16_t search_id {0};
386 std::map<size_t, std::tuple<size_t, size_t, size_t>> listeners {};
387 size_t listener_token {1};
391 Sp<Scheduler::Job> nextNodesConfirmation {};
392 Sp<Scheduler::Job> nextStorageMaintenance {};
394 net::NetworkEngine network_engine;
395 unsigned pending_pings4 {0};
396 unsigned pending_pings6 {0};
398 using ReportedAddr = std::pair<unsigned, SockAddr>;
399 std::vector<ReportedAddr> reported_addr;
401 std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
403 void rotateSecrets();
405 Blob makeToken(
const SockAddr&,
bool old)
const;
406 bool tokenMatch(
const Blob& token,
const SockAddr&)
const;
408 void reportedAddr(
const SockAddr&);
411 void storageAddListener(
const InfoHash&
id,
const Sp<Node>& node,
size_t tid, Query&& = {});
412 bool storageStore(
const InfoHash&
id,
const Sp<Value>& value, time_point created,
const SockAddr& sa = {});
414 void expireStorage(InfoHash h);
415 void expireStore(
decltype(store)::iterator);
417 void storageChanged(
const InfoHash&
id, Storage& st, ValueStorage&,
bool newValue);
418 std::string printStorageLog(
const decltype(store)::value_type&)
const;
425 void dataPersistence(InfoHash
id);
426 size_t maintainStorage(
decltype(store)::value_type&,
bool force=
false, DoneCallback donecb=
nullptr);
429 RoutingTable& buckets(sa_family_t af) {
return af == AF_INET ? buckets4 : buckets6; }
430 const RoutingTable& buckets(sa_family_t af)
const {
return af == AF_INET ? buckets4 : buckets6; }
431 Bucket* findBucket(
const InfoHash&
id, sa_family_t af) {
432 RoutingTable::iterator b;
435 b = buckets4.findBucket(
id);
436 return b == buckets4.end() ? nullptr : &(*b);
438 b = buckets6.findBucket(
id);
439 return b == buckets6.end() ? nullptr : &(*b);
444 const Bucket* findBucket(
const InfoHash&
id, sa_family_t af)
const {
445 return const_cast<Dht*
>(
this)->findBucket(
id, af);
448 void expireBuckets(RoutingTable&);
449 void sendCachedPing(Bucket& b);
450 bool bucketMaintenance(RoutingTable&);
451 void dumpBucket(
const Bucket& b, std::ostream& out)
const;
454 void onNewNode(
const Sp<Node>& node,
int confirm);
455 const Sp<Node> findNode(
const InfoHash&
id, sa_family_t af)
const;
456 bool trySearchInsert(
const Sp<Node>& node);
460 inline SearchMap& searches(sa_family_t af) {
return af == AF_INET ? searches4 : searches6; }
461 inline const SearchMap& searches(sa_family_t af)
const {
return af == AF_INET ? searches4 : searches6; }
467 Sp<Search> search(
const InfoHash&
id, sa_family_t af, GetCallback = {}, QueryCallback = {}, DoneCallback = {}, Value::Filter = {}, Query q = {});
469 void announce(
const InfoHash&
id, sa_family_t af, Sp<Value> value, DoneCallback callback, time_point created=time_point::max(),
bool permanent =
false);
470 size_t listenTo(
const InfoHash&
id, sa_family_t af, ValueCallback cb, Value::Filter f = Value::AllFilter(),
const Sp<Query>& q = {});
479 unsigned refill(Search& sr);
480 void expireSearches();
493 void searchNodeGetDone(
const net::Request& status,
494 net::RequestAnswer&& answer,
495 std::weak_ptr<Search> ws,
507 void searchNodeGetExpired(
const net::Request& status,
bool over, std::weak_ptr<Search> ws, Sp<Query> query);
516 void paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n);
521 SearchNode* searchSendGetValues(Sp<Search> sr, SearchNode *n =
nullptr,
bool update =
true);
529 void searchSendAnnounceValue(
const Sp<Search>& sr);
538 void searchStep(Sp<Search>);
539 void searchSynchedNodeListen(
const Sp<Search>&, SearchNode&);
541 void dumpSearch(
const Search& sr, std::ostream& out)
const;
543 bool neighbourhoodMaintenance(RoutingTable&);
545 void onError(Sp<net::Request> node, net::DhtProtocolException e);
547 void onReportedAddr(
const InfoHash&
id,
const SockAddr&);
549 net::RequestAnswer onPing(Sp<Node> node);
551 net::RequestAnswer onFindNode(Sp<Node> node,
const InfoHash& hash, want_t want);
552 void onFindNodeDone(
const Sp<Node>& status,
553 net::RequestAnswer& a,
556 net::RequestAnswer onGetValues(Sp<Node> node,
557 const InfoHash& hash,
560 void onGetValuesDone(
const Sp<Node>& status,
561 net::RequestAnswer& a,
563 const Sp<Query>& orig_query);
565 net::RequestAnswer onListen(Sp<Node> node,
566 const InfoHash& hash,
570 void onListenDone(
const Sp<Node>& status,
571 net::RequestAnswer& a,
574 net::RequestAnswer onAnnounce(Sp<Node> node,
575 const InfoHash& hash,
577 const std::vector<Sp<Value>>& v,
578 const time_point& created);
579 net::RequestAnswer onRefresh(Sp<Node> node,
580 const InfoHash& hash,
582 const Value::Id& vid);
583 void onAnnounceDone(
const Sp<Node>& status,
584 net::RequestAnswer& a,
std::vector< Sp< Value > > getLocal(const InfoHash &key, Value::Filter f=Value::AllFilter()) const
std::vector< NodeExport > exportNodes()
void pushNotificationReceived(const std::map< std::string, std::string > &)
Dht(const int &s, const int &s6, Config config)
void connectivityChanged(sa_family_t)
void put(const InfoHash &key, Sp< Value >, DoneCallback cb=nullptr, time_point created=time_point::max(), bool permanent=false)
Sp< Value > getLocalById(const InfoHash &key, Value::Id vid) const
Sp< Value > getPut(const InfoHash &, const Value::Id &)
void setStorageLimit(size_t limit=DEFAULT_STORAGE_LIMIT)
void shutdown(ShutdownCallback cb)
const InfoHash & getNodeId() const
virtual void get(const InfoHash &key, GetCallback cb, DoneCallback donecb={}, Value::Filter &&f={}, Where &&w={})
std::vector< Sp< Value > > getPut(const InfoHash &)
std::pair< size_t, size_t > getStoreSize() const
virtual void query(const InfoHash &key, QueryCallback cb, DoneCallback done_cb={}, Query &&q={})
bool isRunning(sa_family_t af=0) const
virtual size_t listen(const InfoHash &key, GetCallback cb, Value::Filter f={}, Where w={})
void insertNode(const InfoHash &id, const SockAddr &)
bool cancelPut(const InfoHash &, const Value::Id &)
NodeStatus getStatus(sa_family_t af) const
virtual size_t listen(const InfoHash &, ValueCallback, Value::Filter={}, Where={})
std::vector< uint8_t > Blob
Describes a query destined to another peer.
Serializable dht::Value filter.