20#include <dhtnet/multiplexed_socket.h>
21#include <opendht/infohash.h>
31using namespace std::placeholders;
50 auto nodeId = info.socket->deviceId();
51 if (nodes.try_emplace(nodeId, std::move(info)).second) {
52 connecting_nodes.erase(nodeId);
53 known_nodes.erase(nodeId);
54 mobile_nodes.erase(nodeId);
63 auto node = nodes.find(nodeId);
64 auto isMobile = node->second.isMobile_;
65 if (node == nodes.end())
81 for (
auto const& key : nodes)
89 return nodes.find(nodeId) != nodes.end();
96 if (known_nodes.emplace(nodeId).second) {
106 if (index > known_nodes.size()) {
107 throw std::out_of_range(
"End of table for get known Node Id " + std::to_string(index));
109 auto it = known_nodes.begin();
110 std::advance(
it, index);
119 if (mobile_nodes.emplace(nodeId).second) {
120 known_nodes.erase(nodeId);
131 if (connecting_nodes.emplace(nodeId).second) {
132 known_nodes.erase(nodeId);
133 mobile_nodes.erase(nodeId);
160 auto node = nodes.find(socket->deviceId());
161 if (node == nodes.end()) {
162 throw std::range_error(
"Unable to find timer " + socket->deviceId().toString());
164 return node->second.refresh_timer;
170 auto node = nodes.find(nodeId);
172 if (node != nodes.end()) {
173 auto socket = node->second.socket;
174 auto node = socket->deviceId();
185 while (
not nodes.empty()) {
186 auto it = nodes.begin();
187 auto socket =
it->second.socket;
188 auto nodeId = socket->deviceId();
200 for (
auto it = nodes.begin();
it != nodes.end(); ++
it) {
201 JAMI_DEBUG(
"Node {:s} Id: {:s} isMobile: {:s}", std::to_string(
nodeNum),
it->first.toString(), std::to_string(
it->second.isMobile_));
206 for (
auto it = mobile_nodes.begin();
it != mobile_nodes.end(); ++
it) {
213 for (
auto it = known_nodes.begin();
it != known_nodes.end(); ++
it) {
219 for (
auto it = connecting_nodes.begin();
it != connecting_nodes.end(); ++
it) {
228 auto itn = nodes.find(nodeId);
229 if (
itn != nodes.end()) {
230 itn->second.isMobile_ = isMobile;
236std::set<std::shared_ptr<dhtnet::ChannelSocketInterface>>
239 std::set<std::shared_ptr<dhtnet::ChannelSocketInterface>>
sockets;
240 for (
auto const& info : nodes)
241 sockets.insert(info.second.socket);
249 buckets.emplace_back(NodeId::zero());
261 std::list<Bucket>::iterator&
bucket)
263 NodeId nodeId = channel->deviceId();
265 if (
bucket->hasNode(nodeId) || id_ == nodeId) {
269 while (
bucket->isFull()) {
275 return bucket->addNode(std::move(channel));
278 return bucket->addNode(std::move(channel));
284 return findBucket(nodeId)->removeNode(nodeId);
300 if (
bucket == buckets.end())
303 return bucket->addKnownNode(nodeId);
314 if (
bucket == buckets.end())
317 bucket->addMobileNode(nodeId);
324 return findBucket(nodeId)->removeMobileNode(nodeId);
330 return findBucket(nodeId)->hasMobileNode(nodeId);
341 if (
bucket == buckets.end())
344 bucket->addConnectingNode(nodeId);
351 findBucket(nodeId)->removeConnectingNode(nodeId);
354std::list<Bucket>::iterator
358 throw std::runtime_error(
"No bucket");
360 auto b = buckets.begin();
363 auto next = std::next(
b);
364 if (next == buckets.end())
366 if (std::memcmp(nodeId.data(), next->getLowerLimit().data(), nodeId.size()) < 0)
378 auto nodes =
b->getNodeIds();
379 for (
auto n : nodes) {
384 return nodeId.xorCmp(n, NodeId) < 0;
393 auto itp = (
bucket == buckets.begin()) ? buckets.end() : std::prev(
bucket);
394 while (
itn != buckets.end() ||
itp != buckets.end()) {
395 if (
itn != buckets.end()) {
399 if (
itp != buckets.end()) {
401 itp = (
itp == buckets.begin()) ? buckets.end() : std::prev(
itp);
417 for (
auto it = buckets.begin();
it != buckets.end(); ++
it) {
421 JAMI_DEBUG(
"_____________________________________________________________________________");
433 std::lock_guard lock(mutex_);
434 std::vector<NodeId>
ret;
435 for (
const auto&
b : buckets) {
436 const auto& nodes =
b.getNodeIds();
437 ret.insert(
ret.end(), nodes.begin(), nodes.end());
445 std::vector<NodeId>
ret;
446 for (
const auto&
b : buckets) {
447 const auto& nodes =
b.getKnownNodes();
448 ret.insert(
ret.end(), nodes.begin(), nodes.end());
456 std::vector<NodeId>
ret;
457 for (
const auto&
b : buckets) {
458 const auto& nodes =
b.getMobileNodes();
459 ret.insert(
ret.end(), nodes.begin(), nodes.end());
467 std::vector<NodeId>
ret;
468 for (
const auto&
b : buckets) {
469 const auto& nodes =
b.getConnectingNodes();
470 ret.insert(
ret.end(), nodes.begin(), nodes.end());
478 std::vector<NodeId>
ret;
480 const auto& nodes =
bucket->getMobileNodes();
481 ret.insert(
ret.end(), nodes.begin(), nodes.end());
489 return NodeId::cmp(
bucket->getLowerLimit(), nodeId) <= 0
490 && (std::next(
bucket) == buckets.end()
491 || NodeId::cmp(nodeId, std::next(
bucket)->getLowerLimit()) < 0);
497 std::vector<NodeId>
ret;
498 for (
const auto&
b : buckets) {
499 const auto& nodes =
b.getNodeIds();
504 ret.insert(
ret.end(), nodes.begin(), nodes.end());
516 bucket->shutdownNode(nodeId);
517 bucket->removeConnectingNode(nodeId);
518 bucket->removeKnownNode(nodeId);
519 bucket->removeMobileNode(nodeId);
523RoutingTable::middle(std::list<Bucket>::iterator&
it)
const
525 unsigned bit = depth(
it);
527 throw std::out_of_range(
"End of table");
530 id.setBit(
bit,
true);
535RoutingTable::depth(std::list<Bucket>::iterator&
bucket)
const
538 int bit2 = std::next(
bucket) != buckets.end() ? std::next(
bucket)->getLowerLimit().lowbit()
544RoutingTable::split(std::list<Bucket>::iterator&
bucket)
554 auto nodeId =
it->first;
571 bucket->removeConnectingNode(nodeId);
584 bucket->removeKnownNode(nodeId);
597 bucket->removeMobileNode(nodeId);
void shutdownAllNodes()
Shutdowns all sockets in nodes through shutdownNode.
bool addNode(const std::shared_ptr< dhtnet::ChannelSocketInterface > &socket)
Add Node socket to bucket.
bool removeNode(const NodeId &nodeId)
Remove NodeId socket from bucket and insert it in known_nodes or mobile_nodes depending on its type.
bool shutdownNode(const NodeId &nodeId)
Shutdowns socket and removes it from nodes.
unsigned getKnownNodesSize() const
Returns number of knwon_nodes in bucket.
bool addMobileNode(const NodeId &nodeId)
Add NodeId to mobile_nodes if it doesn't exist in nodes.
bool hasNode(const NodeId &nodeId) const
Test if socket exists in nodes.
std::set< NodeId > getNodeIds() const
Get NodeIds from bucket.
bool addConnectingNode(const NodeId &nodeId)
Add NodeId to connecting_nodes if it doesn't exist in nodes.
NodeId getKnownNode(unsigned index) const
Returns NodeId from known_nodes at index.
void printBucket(unsigned number) const
Prints bucket and bucket's number.
bool addKnownNode(const NodeId &nodeId)
Add NodeId to known_nodes if it doesn't exist in nodes.
std::set< std::shared_ptr< dhtnet::ChannelSocketInterface > > getNodeSockets() const
Get sockets from bucket.
asio::steady_timer & getNodeTimer(const std::shared_ptr< dhtnet::ChannelSocketInterface > &socket)
Returns socket's timer.
const std::set< NodeId > & getKnownNodes() const
Get NodeIds from known_nodes.
std::set< NodeId > getKnownNodesRandom(unsigned numberNodes, std::mt19937_64 &rd) const
Returns random numberNodes NodeId from known_nodes.
void changeMobility(const NodeId &nodeId, bool isMobile)
Change mobility of specific node, mobile or not.
bool hasMobileNode(const NodeId &nodeId)
Check if mobile node exists in routing table.
std::vector< NodeId > getAllNodes() const
Return every node from each bucket.
std::vector< NodeId > getConnectingNodes() const
Returns all routing table's connecting nodes.
void deleteNode(const NodeId &nodeId)
Delete node from every table in bucket.
bool addKnownNode(const NodeId &nodeId)
Add known node to routing table.
std::vector< NodeId > closestNodes(const NodeId &nodeId, unsigned count)
Returns the count closest nodes to a specific nodeId.
std::vector< NodeId > getBucketMobileNodes() const
Returns mobile nodes corresponding to the swarm's id.
void shutdownNode(const NodeId &nodeId)
Shutdowns a node.
bool addMobileNode(const NodeId &nodeId)
Add mobile node to routing table.
std::list< Bucket >::iterator findBucket(const NodeId &nodeId)
Returns bucket iterator containing nodeId.
std::vector< NodeId > getMobileNodes() const
Returns all routing table's mobile nodes.
bool removeNode(const NodeId &nodeId)
Removes node from routing table Adds it to known_nodes or mobile_nodes depending on mobility.
void removeConnectingNode(const NodeId &nodeId)
Remove connecting connecting node to routing table.
bool hasNode(const NodeId &nodeId)
Check if connected node exsits in routing table.
std::vector< NodeId > getKnownNodes() const
Returns all routing table's known nodes.
std::vector< NodeId > getNodes() const
Returns all routing table's connected nodes.
bool contains(const std::list< Bucket >::iterator &it, const NodeId &nodeId) const
Test if connected nodeId is in specific bucket.
void printRoutingTable() const
Prints routing table.
bool addConnectingNode(const NodeId &nodeId)
Add connecting node to routing table.
void removeMobileNode(const NodeId &nodeId)
Remove mobile node to routing table.
bool addNode(const std::shared_ptr< dhtnet::ChannelSocketInterface > &socket)
Add socket to bucket.
#define JAMI_ERROR(formatstr,...)
#define JAMI_DEBUG(formatstr,...)
void emitSignal(Args... args)
constexpr const std::chrono::minutes FIND_PERIOD