Ring Daemon
Loading...
Searching...
No Matches
routing_table.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#include "manager.h"
20
21#include <dhtnet/multiplexed_socket.h>
22
23#include <opendht/infohash.h>
24
25#include <asio.hpp>
26#include <asio/detail/deadline_timer_service.hpp>
27
28#include <utility>
29#include <vector>
30#include <memory>
31#include <list>
32#include <set>
33
34using NodeId = dht::PkId;
35
36namespace jami {
37
38static constexpr const std::chrono::minutes FIND_PERIOD {10};
39
41{
42 bool isMobile_ {false};
43 std::shared_ptr<dhtnet::ChannelSocketInterface> socket {};
45 NodeInfo() = delete;
50 NodeInfo(bool mobile, std::shared_ptr<dhtnet::ChannelSocketInterface> socket_)
52 , socket(std::move(socket_))
53 {}
54};
55
56class Bucket
57{
58public:
59 static constexpr int BUCKET_MAX_SIZE = 2;
60
61 Bucket() = delete;
62 Bucket(const Bucket&) = delete;
63 Bucket(const NodeId&);
64
70 bool addNode(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket);
71
77 bool addNode(NodeInfo&& info);
78
85 bool removeNode(const NodeId& nodeId);
86
91 const std::map<NodeId, NodeInfo>& getNodes() const { return nodes; }
92 std::map<NodeId, NodeInfo>& getNodes() { return nodes; }
93
98 std::set<NodeId> getNodeIds() const;
99
105 bool hasNode(const NodeId& nodeId) const;
106
112 bool addKnownNode(const NodeId& nodeId);
113
118 void removeKnownNode(const NodeId& nodeId) { known_nodes.erase(nodeId); }
119
124 const std::set<NodeId>& getKnownNodes() const { return known_nodes; }
125
131 NodeId getKnownNode(unsigned index) const;
132
138 bool hasKnownNode(const NodeId& nodeId) const { return known_nodes.find(nodeId) != known_nodes.end(); }
139
145 bool addMobileNode(const NodeId& nodeId);
146
151 void removeMobileNode(const NodeId& nodeId) { mobile_nodes.erase(nodeId); }
152
158 bool hasMobileNode(const NodeId& nodeId) { return mobile_nodes.find(nodeId) != mobile_nodes.end(); }
159
164 const std::set<NodeId>& getMobileNodes() const { return mobile_nodes; }
165
172 bool addConnectingNode(const NodeId& nodeId);
173
178 void removeConnectingNode(const NodeId& nodeId) { connecting_nodes.erase(nodeId); }
179
183 const std::set<NodeId>& getConnectingNodes() const { return connecting_nodes; };
184
190 bool hasConnectingNode(const NodeId& nodeId) const
191 {
192 return connecting_nodes.find(nodeId) != connecting_nodes.end();
193 }
194
195 bool isEmpty() const { return nodes.empty(); }
196
201 bool isFull() const { return nodes.size() == BUCKET_MAX_SIZE; };
202
209 std::set<NodeId> getKnownNodesRandom(unsigned numberNodes, std::mt19937_64& rd) const;
210
216 NodeId randomId(std::mt19937_64& rd) const
217 {
218 auto node = getKnownNodesRandom(1, rd);
219 return *node.begin();
220 }
221
227 asio::steady_timer& getNodeTimer(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket);
228
235 bool shutdownNode(const NodeId& nodeId);
236
240 void shutdownAllNodes();
241
245 void printBucket(unsigned number) const;
246
250 void changeMobility(const NodeId& nodeId, bool isMobile);
251
256 unsigned getNodesSize() const { return nodes.size(); }
257
262 unsigned getKnownNodesSize() const { return known_nodes.size(); }
263
268 unsigned getConnectingNodesSize() const { return connecting_nodes.size(); }
269
274 NodeId getLowerLimit() const { return lowerLimit_; };
275
280 void setLowerLimit(const NodeId& nodeId) { lowerLimit_ = nodeId; }
281
282 // For tests
283
288 std::set<std::shared_ptr<dhtnet::ChannelSocketInterface>> getNodeSockets() const;
289
290private:
291 NodeId lowerLimit_;
292 std::map<NodeId, NodeInfo> nodes;
293 std::set<NodeId> known_nodes;
294 std::set<NodeId> connecting_nodes;
295 std::set<NodeId> mobile_nodes;
296 mutable std::mutex mutex;
297};
298
299// ####################################################################################################
300
302{
303public:
304 RoutingTable();
305
306 bool isEmpty() const;
307
313 bool addNode(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket);
314
321 bool addNode(const std::shared_ptr<dhtnet::ChannelSocketInterface>& channel, std::list<Bucket>::iterator& bucket);
322
329 bool removeNode(const NodeId& nodeId);
330
336 bool hasNode(const NodeId& nodeId);
337
343 bool addKnownNode(const NodeId& nodeId);
344
350 bool hasKnownNode(const NodeId& nodeId) const
351 {
352 auto bucket = findBucket(nodeId);
353 return bucket->hasKnownNode(nodeId);
354 }
355
361 bool addMobileNode(const NodeId& nodeId);
362
368 void removeMobileNode(const NodeId& nodeId);
369
375 bool hasMobileNode(const NodeId& nodeId);
376
382 bool addConnectingNode(const NodeId& nodeId);
383
389 void removeConnectingNode(const NodeId& nodeId);
390
396 bool hasConnectingNode(const NodeId& nodeId) const
397 {
398 auto bucket = findBucket(nodeId);
399 return bucket->hasConnectingNode(nodeId);
400 }
401
407 std::list<Bucket>::iterator findBucket(const NodeId& nodeId);
408
414 inline const std::list<Bucket>::const_iterator findBucket(const NodeId& nodeId) const
415 {
416 return std::list<Bucket>::const_iterator(const_cast<RoutingTable*>(this)->findBucket(nodeId));
417 }
418
425 std::vector<NodeId> closestNodes(const NodeId& nodeId, unsigned count);
426
431 unsigned size() const { return buckets.size(); }
432
437 unsigned getNodeCount() const
438 {
439 size_t count = 0;
440 for (const auto& b : buckets)
441 count += b.getNodesSize();
442 return count;
443 }
444
445 unsigned getActiveNodesCount() const
446 {
447 size_t count = 0;
448 for (const auto& b : buckets)
449 count += b.getNodesSize() + b.getConnectingNodesSize();
450 return count;
451 }
452
456 void printRoutingTable() const;
457
462 void shutdownNode(const NodeId& nodeId);
463
468 {
469 for (auto& bucket : buckets)
470 bucket.shutdownAllNodes();
471 }
472
477 void setId(const NodeId& node) { id_ = node; }
478
483 NodeId getId() const { return id_; }
484
489 std::list<Bucket>& getBuckets() { return buckets; }
490
495 std::vector<NodeId> getNodes() const;
496
501 std::vector<NodeId> getKnownNodes() const;
502
507 std::vector<NodeId> getMobileNodes() const;
508
513 std::vector<NodeId> getConnectingNodes() const;
514
519 std::vector<NodeId> getBucketMobileNodes() const;
520
521 std::vector<NodeId> getConnectedNodes() const;
522
529 bool contains(const std::list<Bucket>::iterator& it, const NodeId& nodeId) const;
530
534 std::vector<NodeId> getAllNodes() const;
535
539 void deleteNode(const NodeId& nodeId);
540
542 {
543 std::string id;
544 std::string status;
545 std::string remoteAddress;
546 std::chrono::system_clock::time_point connectionTime;
548 };
549 std::vector<NodeStats> getRoutingTableStats() const;
550
551private:
552 RoutingTable(const RoutingTable&) = delete;
553 RoutingTable& operator=(const RoutingTable&) = delete;
554
560 NodeId middle(std::list<Bucket>::iterator& it) const;
561
567 unsigned depth(std::list<Bucket>::iterator& bucket) const;
568
574 bool split(std::list<Bucket>::iterator& bucket);
575
576 NodeId id_;
577
578 std::list<Bucket> buckets;
579
580 mutable std::mutex mutex_;
581};
582}; // namespace jami
void setLowerLimit(const NodeId &nodeId)
Set bucket's lower limit.
void shutdownAllNodes()
Shutdowns all sockets in nodes through shutdownNode.
unsigned getNodesSize() const
Returns number of nodes in bucket.
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.
void removeMobileNode(const NodeId &nodeId)
Remove NodeId from mobile_nodes.
const std::set< NodeId > & getMobileNodes() const
Get NodeIds from mobile_nodes.
Bucket()=delete
bool shutdownNode(const NodeId &nodeId)
Shutdowns socket and removes it from nodes.
unsigned getKnownNodesSize() const
Returns number of knwon_nodes in bucket.
NodeId getLowerLimit() const
Returns bucket lower limit.
NodeId randomId(std::mt19937_64 &rd) const
Returns random NodeId from known_nodes.
Bucket(const Bucket &)=delete
bool addMobileNode(const NodeId &nodeId)
Add NodeId to mobile_nodes if it doesn't exist in nodes.
void removeConnectingNode(const NodeId &nodeId)
Remove NodeId from connecting_nodes.
const std::set< NodeId > & getConnectingNodes() const
Get NodeIds of connecting_nodes.
bool hasNode(const NodeId &nodeId) const
Test if socket exists in nodes.
std::set< NodeId > getNodeIds() const
Get NodeIds from bucket.
static constexpr int BUCKET_MAX_SIZE
bool hasKnownNode(const NodeId &nodeId) const
Test if NodeId exist in known_nodes.
bool addConnectingNode(const NodeId &nodeId)
Add NodeId to connecting_nodes if it doesn't exist in nodes.
bool hasMobileNode(const NodeId &nodeId)
Test if NodeId exist in mobile_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.
bool isFull() const
Indicate if bucket is full.
const std::map< NodeId, NodeInfo > & getNodes() const
Get connected nodes from bucket.
std::set< std::shared_ptr< dhtnet::ChannelSocketInterface > > getNodeSockets() const
Get sockets from bucket.
std::map< NodeId, NodeInfo > & getNodes()
bool hasConnectingNode(const NodeId &nodeId) const
Test if NodeId exist in connecting_nodes.
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.
bool isEmpty() const
unsigned getConnectingNodesSize() const
Returns number of mobile_nodes in bucket.
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.
void removeKnownNode(const NodeId &nodeId)
Remove NodeId from known_nodes.
static LIBJAMI_TEST_EXPORT Manager & instance()
Definition manager.cpp:694
std::shared_ptr< asio::io_context > ioContext() const
Definition manager.cpp:1734
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.
unsigned getNodeCount() const
Returns number of total nodes in routing table.
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 shutdownAllNodes()
Shutdowns all nodes in routing table and add them to known_nodes or mobile_nodes.
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.
unsigned size() const
Returns number of buckets in routing table.
bool hasKnownNode(const NodeId &nodeId) const
Checks if known node exists in routing table.
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.
bool hasConnectingNode(const NodeId &nodeId) const
Check if Connecting node exists in routing table.
std::vector< NodeId > getConnectedNodes() const
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.
std::list< Bucket > & getBuckets()
Returns buckets in routing table.
bool addConnectingNode(const NodeId &nodeId)
Add connecting node to routing table.
const std::list< Bucket >::const_iterator findBucket(const NodeId &nodeId) const
Returns bucket iterator containing nodeId.
unsigned getActiveNodesCount() const
NodeId getId() const
Returns id for 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.
std::vector< NodeStats > getRoutingTableStats() const
void setId(const NodeId &node)
Sets id for routing table.
dht::h256 NodeId
static constexpr const std::chrono::minutes FIND_PERIOD
void emitSignal(Args... args)
Definition jami_signal.h:64
dht::PkId NodeId
std::shared_ptr< dhtnet::ChannelSocketInterface > socket
asio::steady_timer refresh_timer
NodeInfo(NodeInfo &&) noexcept=default
NodeInfo(bool mobile, std::shared_ptr< dhtnet::ChannelSocketInterface > socket_)
NodeInfo()=delete
std::chrono::system_clock::time_point connectionTime