2018-07-11 13:20:14 +00:00
|
|
|
#ifndef LLARP_DHT_BUCKET_HPP
|
|
|
|
#define LLARP_DHT_BUCKET_HPP
|
|
|
|
|
2018-12-12 00:48:54 +00:00
|
|
|
#include <dht/kademlia.hpp>
|
|
|
|
#include <dht/key.hpp>
|
2019-02-08 19:43:25 +00:00
|
|
|
#include <util/status.hpp>
|
2019-01-13 16:30:07 +00:00
|
|
|
|
2018-07-11 13:20:14 +00:00
|
|
|
#include <map>
|
|
|
|
#include <set>
|
2018-08-04 02:59:32 +00:00
|
|
|
#include <vector>
|
2018-07-11 13:20:14 +00:00
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
namespace dht
|
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename Val_t>
|
2019-04-19 15:10:26 +00:00
|
|
|
struct Bucket
|
2018-07-11 13:20:14 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
using BucketStorage_t = std::map<Key_t, Val_t, XorMetric>;
|
|
|
|
using Random_t = std::function<uint64_t()>;
|
2018-07-11 13:20:14 +00:00
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
Bucket(const Key_t& us, Random_t r) : nodes(XorMetric(us)), random(std::move(r))
|
2019-04-24 23:27:31 +00:00
|
|
|
{
|
|
|
|
}
|
2018-07-11 13:20:14 +00:00
|
|
|
|
2019-02-11 17:14:43 +00:00
|
|
|
util::StatusObject
|
2019-04-19 15:10:26 +00:00
|
|
|
ExtractStatus() const
|
2019-02-08 19:43:25 +00:00
|
|
|
{
|
2019-02-11 17:14:43 +00:00
|
|
|
util::StatusObject obj{};
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& item : nodes)
|
2019-02-08 19:43:25 +00:00
|
|
|
{
|
2019-08-19 21:26:34 +00:00
|
|
|
obj[item.first.ToString()] = item.second.ExtractStatus();
|
2019-02-08 19:43:25 +00:00
|
|
|
}
|
2019-02-11 17:14:43 +00:00
|
|
|
return obj;
|
2019-02-08 19:43:25 +00:00
|
|
|
}
|
|
|
|
|
2018-09-09 12:27:56 +00:00
|
|
|
size_t
|
2019-01-19 01:41:08 +00:00
|
|
|
size() const
|
2018-09-09 12:27:56 +00:00
|
|
|
{
|
|
|
|
return nodes.size();
|
|
|
|
}
|
|
|
|
|
2019-01-19 01:41:08 +00:00
|
|
|
struct SetIntersector
|
|
|
|
{
|
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
operator()(const typename BucketStorage_t::value_type& lhs, const Key_t& rhs)
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
|
|
|
return lhs.first < rhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
operator()(const Key_t& lhs, const typename BucketStorage_t::value_type& rhs)
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
|
|
|
return lhs < rhs.first;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-04 02:59:32 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
GetRandomNodeExcluding(Key_t& result, const std::set<Key_t>& exclude) const
|
2018-08-04 02:59:32 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
std::vector<typename BucketStorage_t::value_type> candidates;
|
|
|
|
std::set_difference(
|
|
|
|
nodes.begin(),
|
|
|
|
nodes.end(),
|
|
|
|
exclude.begin(),
|
|
|
|
exclude.end(),
|
|
|
|
std::back_inserter(candidates),
|
|
|
|
SetIntersector());
|
|
|
|
|
|
|
|
if (candidates.empty())
|
2018-08-04 02:59:32 +00:00
|
|
|
{
|
|
|
|
return false;
|
2019-01-19 01:41:08 +00:00
|
|
|
}
|
|
|
|
result = candidates[random() % candidates.size()].first;
|
2018-08-04 02:59:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-11 13:20:14 +00:00
|
|
|
bool
|
|
|
|
FindClosest(const Key_t& target, Key_t& result) const
|
|
|
|
{
|
|
|
|
Key_t mindist;
|
|
|
|
mindist.Fill(0xff);
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& item : nodes)
|
2018-07-11 13:20:14 +00:00
|
|
|
{
|
|
|
|
auto curDist = item.first ^ target;
|
2020-04-07 18:38:56 +00:00
|
|
|
if (curDist < mindist)
|
2018-07-11 13:20:14 +00:00
|
|
|
{
|
|
|
|
mindist = curDist;
|
2020-04-07 18:38:56 +00:00
|
|
|
result = item.first;
|
2018-07-11 13:20:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nodes.size() > 0;
|
|
|
|
}
|
|
|
|
|
2018-08-29 20:40:26 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
GetManyRandom(std::set<Key_t>& result, size_t N) const
|
2018-08-29 20:40:26 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (nodes.size() < N || nodes.empty())
|
2018-11-20 16:58:18 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
llarp::LogWarn("Not enough dht nodes, have ", nodes.size(), " want ", N);
|
2018-08-29 20:40:26 +00:00
|
|
|
return false;
|
2018-11-20 16:58:18 +00:00
|
|
|
}
|
2020-04-07 18:38:56 +00:00
|
|
|
if (nodes.size() == N)
|
2018-08-29 20:40:26 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
std::transform(
|
|
|
|
nodes.begin(), nodes.end(), std::inserter(result, result.end()), [](const auto& a) {
|
|
|
|
return a.first;
|
|
|
|
});
|
2019-01-19 01:41:08 +00:00
|
|
|
|
2018-08-29 20:40:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
size_t expecting = N;
|
2020-04-07 18:38:56 +00:00
|
|
|
size_t sz = nodes.size();
|
|
|
|
while (N)
|
2018-08-29 20:40:26 +00:00
|
|
|
{
|
|
|
|
auto itr = nodes.begin();
|
2019-01-19 01:41:08 +00:00
|
|
|
std::advance(itr, random() % sz);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (result.insert(itr->first).second)
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
2018-08-29 20:40:26 +00:00
|
|
|
--N;
|
2019-01-19 01:41:08 +00:00
|
|
|
}
|
2018-08-29 20:40:26 +00:00
|
|
|
}
|
|
|
|
return result.size() == expecting;
|
|
|
|
}
|
|
|
|
|
2018-07-11 13:20:14 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
FindCloseExcluding(const Key_t& target, Key_t& result, const std::set<Key_t>& exclude) const
|
2018-07-11 13:20:14 +00:00
|
|
|
{
|
|
|
|
Key_t maxdist;
|
|
|
|
maxdist.Fill(0xff);
|
|
|
|
Key_t mindist;
|
|
|
|
mindist.Fill(0xff);
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& item : nodes)
|
2018-07-11 13:20:14 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (exclude.count(item.first))
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
2018-07-11 13:20:14 +00:00
|
|
|
continue;
|
2019-01-19 01:41:08 +00:00
|
|
|
}
|
2018-08-10 21:34:11 +00:00
|
|
|
|
2018-07-11 13:20:14 +00:00
|
|
|
auto curDist = item.first ^ target;
|
2020-04-07 18:38:56 +00:00
|
|
|
if (curDist < mindist)
|
2018-07-11 13:20:14 +00:00
|
|
|
{
|
|
|
|
mindist = curDist;
|
2020-04-07 18:38:56 +00:00
|
|
|
result = item.first;
|
2018-07-11 13:20:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return mindist < maxdist;
|
|
|
|
}
|
|
|
|
|
2019-01-19 01:41:08 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
GetManyNearExcluding(
|
|
|
|
const Key_t& target,
|
|
|
|
std::set<Key_t>& result,
|
|
|
|
size_t N,
|
|
|
|
const std::set<Key_t>& exclude) const
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
std::set<Key_t> s(exclude.begin(), exclude.end());
|
2019-01-19 01:41:08 +00:00
|
|
|
|
|
|
|
Key_t peer;
|
2020-04-07 18:38:56 +00:00
|
|
|
while (N--)
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (!FindCloseExcluding(target, peer, s))
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
s.insert(peer);
|
|
|
|
result.insert(peer);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-11 13:20:14 +00:00
|
|
|
void
|
|
|
|
PutNode(const Val_t& val)
|
|
|
|
{
|
2018-09-21 14:50:07 +00:00
|
|
|
auto itr = nodes.find(val.ID);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr == nodes.end() || itr->second < val)
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
2018-09-21 14:50:07 +00:00
|
|
|
nodes[val.ID] = val;
|
2019-01-19 01:41:08 +00:00
|
|
|
}
|
2018-07-11 13:20:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DelNode(const Key_t& key)
|
|
|
|
{
|
|
|
|
auto itr = nodes.find(key);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr != nodes.end())
|
2019-01-19 01:41:08 +00:00
|
|
|
{
|
2018-07-11 13:20:14 +00:00
|
|
|
nodes.erase(itr);
|
2019-01-19 01:41:08 +00:00
|
|
|
}
|
2018-07-11 13:20:14 +00:00
|
|
|
}
|
|
|
|
|
2018-12-19 17:48:29 +00:00
|
|
|
bool
|
|
|
|
HasNode(const Key_t& key) const
|
|
|
|
{
|
|
|
|
return nodes.find(key) != nodes.end();
|
|
|
|
}
|
|
|
|
|
2019-09-10 14:16:32 +00:00
|
|
|
// remove all nodes who's key matches a predicate
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename Predicate>
|
2019-09-10 14:16:32 +00:00
|
|
|
void
|
|
|
|
RemoveIf(Predicate pred)
|
|
|
|
{
|
|
|
|
auto itr = nodes.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != nodes.end())
|
2019-09-10 14:16:32 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (pred(itr->first))
|
2019-09-10 14:16:32 +00:00
|
|
|
itr = nodes.erase(itr);
|
|
|
|
else
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename Visit_t>
|
2020-01-21 17:31:48 +00:00
|
|
|
void
|
|
|
|
ForEachNode(Visit_t visit)
|
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& item : nodes)
|
2020-01-21 17:31:48 +00:00
|
|
|
{
|
|
|
|
visit(item.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-19 01:41:08 +00:00
|
|
|
void
|
|
|
|
Clear()
|
|
|
|
{
|
|
|
|
nodes.clear();
|
|
|
|
}
|
|
|
|
|
2018-07-11 13:20:14 +00:00
|
|
|
BucketStorage_t nodes;
|
2019-01-19 01:41:08 +00:00
|
|
|
Random_t random;
|
2018-07-11 13:20:14 +00:00
|
|
|
};
|
2018-07-17 04:37:50 +00:00
|
|
|
} // namespace dht
|
|
|
|
} // namespace llarp
|
2018-08-27 13:44:16 +00:00
|
|
|
#endif
|