mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-08 12:28:42 +00:00
move routing table to a different file
This commit is contained in:
1 parent
f9e6662f7d
commit
0890ed9c4f
5 files changed
+244
-204
No files matched your search
@@ -35,6 +35,7 @@ list (APPEND opendht_SOURCES
|
||||
src/node.cpp
|
||||
src/value.cpp
|
||||
src/dht.cpp
|
||||
src/routing_table.cpp
|
||||
src/network_engine.cpp
|
||||
src/securedht.cpp
|
||||
src/dhtrunner.cpp
|
||||
@@ -55,6 +56,7 @@ list (APPEND opendht_HEADERS
|
||||
include/opendht/node.h
|
||||
include/opendht/value.h
|
||||
include/opendht/dht.h
|
||||
include/opendht/routing_table.h
|
||||
include/opendht/network_engine.h
|
||||
include/opendht/scheduler.h
|
||||
include/opendht/securedht.h
|
||||
|
||||
+1
-54
@@ -26,6 +26,7 @@
|
||||
#include "utils.h"
|
||||
#include "network_engine.h"
|
||||
#include "scheduler.h"
|
||||
#include "routing_table.h"
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
@@ -368,60 +369,6 @@ private:
|
||||
std::list<std::weak_ptr<Node>> cache_6;
|
||||
};
|
||||
|
||||
struct Bucket {
|
||||
Bucket() : cached() {}
|
||||
Bucket(sa_family_t af, const InfoHash& f = {}, time_point t = time_point::min())
|
||||
: af(af), first(f), time(t), cached() {}
|
||||
sa_family_t af {0};
|
||||
InfoHash first {};
|
||||
time_point time {time_point::min()}; /* time of last reply in this bucket */
|
||||
std::list<std::shared_ptr<Node>> nodes {};
|
||||
sockaddr_storage cached; /* the address of a likely candidate */
|
||||
socklen_t cachedlen {0};
|
||||
|
||||
/** Return a random node in a bucket. */
|
||||
std::shared_ptr<Node> randomNode();
|
||||
};
|
||||
|
||||
class RoutingTable : public std::list<Bucket> {
|
||||
public:
|
||||
using std::list<Bucket>::list;
|
||||
|
||||
InfoHash middle(const RoutingTable::const_iterator&) const;
|
||||
|
||||
std::vector<std::shared_ptr<Node>> findClosestNodes(const InfoHash id, time_point now, size_t count = TARGET_NODES) const;
|
||||
|
||||
RoutingTable::iterator findBucket(const InfoHash& id);
|
||||
RoutingTable::const_iterator findBucket(const InfoHash& id) const;
|
||||
|
||||
/**
|
||||
* Return true if the id is in the bucket's range.
|
||||
*/
|
||||
inline bool contains(const RoutingTable::const_iterator& bucket, const InfoHash& id) const {
|
||||
return InfoHash::cmp(bucket->first, id) <= 0
|
||||
&& (std::next(bucket) == end() || InfoHash::cmp(id, std::next(bucket)->first) < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the table has no bucket ore one empty buket.
|
||||
*/
|
||||
inline bool isEmpty() const {
|
||||
return empty() || (size() == 1 && front().nodes.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random id in the bucket's range.
|
||||
*/
|
||||
InfoHash randomId(const RoutingTable::const_iterator& bucket) const;
|
||||
|
||||
unsigned depth(const RoutingTable::const_iterator& bucket) const;
|
||||
|
||||
/**
|
||||
* Split a bucket in two equal parts.
|
||||
*/
|
||||
bool split(const RoutingTable::iterator& b);
|
||||
};
|
||||
|
||||
struct SearchNode {
|
||||
SearchNode(std::shared_ptr<Node> node) : node(node) {}
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "node.h"
|
||||
|
||||
namespace dht {
|
||||
|
||||
struct Bucket {
|
||||
Bucket() : cached() {}
|
||||
Bucket(sa_family_t af, const InfoHash& f = {}, time_point t = time_point::min())
|
||||
: af(af), first(f), time(t), cached() {}
|
||||
sa_family_t af {0};
|
||||
InfoHash first {};
|
||||
time_point time {time_point::min()}; /* time of last reply in this bucket */
|
||||
std::list<std::shared_ptr<Node>> nodes {};
|
||||
sockaddr_storage cached; /* the address of a likely candidate */
|
||||
socklen_t cachedlen {0};
|
||||
|
||||
/** Return a random node in a bucket. */
|
||||
std::shared_ptr<Node> randomNode();
|
||||
};
|
||||
|
||||
class RoutingTable : public std::list<Bucket> {
|
||||
public:
|
||||
using std::list<Bucket>::list;
|
||||
|
||||
InfoHash middle(const RoutingTable::const_iterator&) const;
|
||||
|
||||
std::vector<std::shared_ptr<Node>> findClosestNodes(const InfoHash id, time_point now, size_t count = TARGET_NODES) const;
|
||||
|
||||
RoutingTable::iterator findBucket(const InfoHash& id);
|
||||
RoutingTable::const_iterator findBucket(const InfoHash& id) const;
|
||||
|
||||
/**
|
||||
* Return true if the id is in the bucket's range.
|
||||
*/
|
||||
inline bool contains(const RoutingTable::const_iterator& bucket, const InfoHash& id) const {
|
||||
return InfoHash::cmp(bucket->first, id) <= 0
|
||||
&& (std::next(bucket) == end() || InfoHash::cmp(id, std::next(bucket)->first) < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the table has no bucket ore one empty buket.
|
||||
*/
|
||||
inline bool isEmpty() const {
|
||||
return empty() || (size() == 1 && front().nodes.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random id in the bucket's range.
|
||||
*/
|
||||
InfoHash randomId(const RoutingTable::const_iterator& bucket) const;
|
||||
|
||||
unsigned depth(const RoutingTable::const_iterator& bucket) const;
|
||||
|
||||
/**
|
||||
* Split a bucket in two equal parts.
|
||||
*/
|
||||
bool split(const RoutingTable::iterator& b);
|
||||
};
|
||||
|
||||
}
|
||||
-150
@@ -173,128 +173,6 @@ Dht::isMartian(const sockaddr *sa, socklen_t len)
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Node>
|
||||
Dht::Bucket::randomNode()
|
||||
{
|
||||
if (nodes.empty())
|
||||
return nullptr;
|
||||
std::uniform_int_distribution<unsigned> rand_node(0, nodes.size()-1);
|
||||
unsigned nn = rand_node(rd);
|
||||
for (auto& n : nodes)
|
||||
if (not nn--) return n;
|
||||
return nodes.back();
|
||||
}
|
||||
|
||||
InfoHash
|
||||
Dht::RoutingTable::randomId(const Dht::RoutingTable::const_iterator& it) const
|
||||
{
|
||||
int bit1 = it->first.lowbit();
|
||||
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
|
||||
int bit = std::max(bit1, bit2) + 1;
|
||||
|
||||
if (bit >= 8*(int)HASH_LEN)
|
||||
return it->first;
|
||||
|
||||
int b = bit/8;
|
||||
InfoHash id_return;
|
||||
std::copy_n(it->first.begin(), b, id_return.begin());
|
||||
id_return[b] = it->first[b] & (0xFF00 >> (bit % 8));
|
||||
id_return[b] |= rand_byte(rd) >> (bit % 8);
|
||||
for (unsigned i = b + 1; i < HASH_LEN; i++)
|
||||
id_return[i] = rand_byte(rd);
|
||||
return id_return;
|
||||
}
|
||||
|
||||
InfoHash
|
||||
Dht::RoutingTable::middle(const RoutingTable::const_iterator& it) const
|
||||
{
|
||||
unsigned bit = depth(it);
|
||||
if (bit >= 8*HASH_LEN)
|
||||
throw std::out_of_range("End of table");
|
||||
|
||||
InfoHash id = it->first;
|
||||
id.setBit(bit, 1);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned
|
||||
Dht::RoutingTable::depth(const RoutingTable::const_iterator& it) const
|
||||
{
|
||||
int bit1 = it->first.lowbit();
|
||||
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
|
||||
return std::max(bit1, bit2)+1;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Node>>
|
||||
Dht::RoutingTable::findClosestNodes(const InfoHash id, time_point now, size_t count) const
|
||||
{
|
||||
std::vector<std::shared_ptr<Node>> nodes {};
|
||||
auto bucket = findBucket(id);
|
||||
|
||||
if (bucket == end()) { return nodes; }
|
||||
|
||||
auto sortedBucketInsert = [&](const Bucket &b) {
|
||||
for (auto n : b.nodes) {
|
||||
if (not n->isGood(now))
|
||||
continue;
|
||||
|
||||
auto here = std::find_if(nodes.begin(), nodes.end(),
|
||||
[&id,&n](std::shared_ptr<Node> &node) {
|
||||
return id.xorCmp(n->id, node->id) < 0;
|
||||
}
|
||||
);
|
||||
nodes.insert(here, n);
|
||||
}
|
||||
};
|
||||
|
||||
auto itn = bucket;
|
||||
auto itp = std::prev(bucket);
|
||||
while (nodes.size() < count && (itn != end() || itp != end())) {
|
||||
if (itn != end()) {
|
||||
sortedBucketInsert(*itn);
|
||||
itn = std::next(itn);
|
||||
}
|
||||
if (itp != end()) {
|
||||
sortedBucketInsert(*itp);
|
||||
if (itp == begin()) {
|
||||
itp = end();
|
||||
continue;
|
||||
}
|
||||
itp = std::prev(itp);
|
||||
}
|
||||
}
|
||||
|
||||
// shrink to the count closest nodes.
|
||||
if (nodes.size() > count) {
|
||||
nodes.resize(count);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
Dht::RoutingTable::iterator
|
||||
Dht::RoutingTable::findBucket(const InfoHash& id)
|
||||
{
|
||||
if (empty())
|
||||
return end();
|
||||
auto b = begin();
|
||||
while (true) {
|
||||
auto next = std::next(b);
|
||||
if (next == end())
|
||||
return b;
|
||||
if (InfoHash::cmp(id, next->first) < 0)
|
||||
return b;
|
||||
b = next;
|
||||
}
|
||||
}
|
||||
|
||||
Dht::RoutingTable::const_iterator
|
||||
Dht::RoutingTable::findBucket(const InfoHash& id) const
|
||||
{
|
||||
/* Avoid code duplication for the const version */
|
||||
const_iterator it = const_cast<RoutingTable*>(this)->findBucket(id);
|
||||
return it;
|
||||
}
|
||||
|
||||
/* Every bucket contains an unordered list of nodes. */
|
||||
std::shared_ptr<Node>
|
||||
Dht::findNode(const InfoHash& id, sa_family_t af)
|
||||
@@ -444,34 +322,6 @@ Dht::getPublicAddress(sa_family_t family)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Split a bucket into two equal parts. */
|
||||
bool
|
||||
Dht::RoutingTable::split(const RoutingTable::iterator& b)
|
||||
{
|
||||
InfoHash new_id;
|
||||
try {
|
||||
new_id = middle(b);
|
||||
} catch (const std::out_of_range& e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert new bucket
|
||||
insert(std::next(b), Bucket {b->af, new_id, b->time});
|
||||
|
||||
// Re-assign nodes
|
||||
std::list<std::shared_ptr<Node>> nodes {};
|
||||
nodes.splice(nodes.begin(), b->nodes);
|
||||
while (!nodes.empty()) {
|
||||
auto n = nodes.begin();
|
||||
auto b = findBucket((*n)->id);
|
||||
if (b == end())
|
||||
nodes.erase(n);
|
||||
else
|
||||
b->nodes.splice(b->nodes.begin(), nodes, n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Dht::trySearchInsert(const std::shared_ptr<Node>& node)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
#include "routing_table.h"
|
||||
#include "rng.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace dht {
|
||||
|
||||
static std::mt19937 rd {dht::crypto::random_device{}()};
|
||||
static std::uniform_int_distribution<uint8_t> rand_byte;
|
||||
|
||||
std::shared_ptr<Node>
|
||||
Bucket::randomNode()
|
||||
{
|
||||
if (nodes.empty())
|
||||
return nullptr;
|
||||
std::uniform_int_distribution<unsigned> rand_node(0, nodes.size()-1);
|
||||
unsigned nn = rand_node(rd);
|
||||
for (auto& n : nodes)
|
||||
if (not nn--) return n;
|
||||
return nodes.back();
|
||||
}
|
||||
|
||||
InfoHash
|
||||
RoutingTable::randomId(const RoutingTable::const_iterator& it) const
|
||||
{
|
||||
int bit1 = it->first.lowbit();
|
||||
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
|
||||
int bit = std::max(bit1, bit2) + 1;
|
||||
|
||||
if (bit >= 8*(int)HASH_LEN)
|
||||
return it->first;
|
||||
|
||||
int b = bit/8;
|
||||
InfoHash id_return;
|
||||
std::copy_n(it->first.begin(), b, id_return.begin());
|
||||
id_return[b] = it->first[b] & (0xFF00 >> (bit % 8));
|
||||
id_return[b] |= rand_byte(rd) >> (bit % 8);
|
||||
for (unsigned i = b + 1; i < HASH_LEN; i++)
|
||||
id_return[i] = rand_byte(rd);
|
||||
return id_return;
|
||||
}
|
||||
|
||||
InfoHash
|
||||
RoutingTable::middle(const RoutingTable::const_iterator& it) const
|
||||
{
|
||||
unsigned bit = depth(it);
|
||||
if (bit >= 8*HASH_LEN)
|
||||
throw std::out_of_range("End of table");
|
||||
|
||||
InfoHash id = it->first;
|
||||
id.setBit(bit, 1);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned
|
||||
RoutingTable::depth(const RoutingTable::const_iterator& it) const
|
||||
{
|
||||
int bit1 = it->first.lowbit();
|
||||
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
|
||||
return std::max(bit1, bit2)+1;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Node>>
|
||||
RoutingTable::findClosestNodes(const InfoHash id, time_point now, size_t count) const
|
||||
{
|
||||
std::vector<std::shared_ptr<Node>> nodes {};
|
||||
auto bucket = findBucket(id);
|
||||
|
||||
if (bucket == end()) { return nodes; }
|
||||
|
||||
auto sortedBucketInsert = [&](const Bucket &b) {
|
||||
for (auto n : b.nodes) {
|
||||
if (not n->isGood(now))
|
||||
continue;
|
||||
|
||||
auto here = std::find_if(nodes.begin(), nodes.end(),
|
||||
[&id,&n](std::shared_ptr<Node> &node) {
|
||||
return id.xorCmp(n->id, node->id) < 0;
|
||||
}
|
||||
);
|
||||
nodes.insert(here, n);
|
||||
}
|
||||
};
|
||||
|
||||
auto itn = bucket;
|
||||
auto itp = std::prev(bucket);
|
||||
while (nodes.size() < count && (itn != end() || itp != end())) {
|
||||
if (itn != end()) {
|
||||
sortedBucketInsert(*itn);
|
||||
itn = std::next(itn);
|
||||
}
|
||||
if (itp != end()) {
|
||||
sortedBucketInsert(*itp);
|
||||
if (itp == begin()) {
|
||||
itp = end();
|
||||
continue;
|
||||
}
|
||||
itp = std::prev(itp);
|
||||
}
|
||||
}
|
||||
|
||||
// shrink to the count closest nodes.
|
||||
if (nodes.size() > count) {
|
||||
nodes.resize(count);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
RoutingTable::iterator
|
||||
RoutingTable::findBucket(const InfoHash& id)
|
||||
{
|
||||
if (empty())
|
||||
return end();
|
||||
auto b = begin();
|
||||
while (true) {
|
||||
auto next = std::next(b);
|
||||
if (next == end())
|
||||
return b;
|
||||
if (InfoHash::cmp(id, next->first) < 0)
|
||||
return b;
|
||||
b = next;
|
||||
}
|
||||
}
|
||||
|
||||
RoutingTable::const_iterator
|
||||
RoutingTable::findBucket(const InfoHash& id) const
|
||||
{
|
||||
/* Avoid code duplication for the const version */
|
||||
const_iterator it = const_cast<RoutingTable*>(this)->findBucket(id);
|
||||
return it;
|
||||
}
|
||||
|
||||
/* Split a bucket into two equal parts. */
|
||||
bool
|
||||
RoutingTable::split(const RoutingTable::iterator& b)
|
||||
{
|
||||
InfoHash new_id;
|
||||
try {
|
||||
new_id = middle(b);
|
||||
} catch (const std::out_of_range& e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert new bucket
|
||||
insert(std::next(b), Bucket {b->af, new_id, b->time});
|
||||
|
||||
// Re-assign nodes
|
||||
std::list<std::shared_ptr<Node>> nodes {};
|
||||
nodes.splice(nodes.begin(), b->nodes);
|
||||
while (!nodes.empty()) {
|
||||
auto n = nodes.begin();
|
||||
auto b = findBucket((*n)->id);
|
||||
if (b == end())
|
||||
nodes.erase(n);
|
||||
else
|
||||
b->nodes.splice(b->nodes.begin(), nodes, n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user