Line data Source code
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 "routing_table.h" 20 : #include "swarm_protocol.h" 21 : 22 : #include <memory> 23 : 24 : namespace jami { 25 : 26 : using namespace swarm_protocol; 27 : 28 : class SwarmManager : public std::enable_shared_from_this<SwarmManager> 29 : { 30 : using ChannelCb = std::function<bool(const std::shared_ptr<dhtnet::ChannelSocketInterface>&)>; 31 : using NeedSocketCb = std::function<void(const std::string&, ChannelCb&&)>; 32 : using ToConnectCb = std::function<bool(const NodeId&)>; 33 : using OnConnectionChanged = std::function<void(bool ok)>; 34 : 35 : public: 36 : explicit SwarmManager(const NodeId&, const std::mt19937_64& rand, ToConnectCb&& toConnectCb); 37 : ~SwarmManager(); 38 : 39 : NeedSocketCb needSocketCb_; 40 : 41 3857 : std::weak_ptr<SwarmManager> weak() { return weak_from_this(); } 42 : 43 : /** 44 : * Get swarm manager id 45 : * @return NodeId 46 : */ 47 1630 : const NodeId& getId() const { return id_; } 48 : 49 : /** 50 : * Set list of nodes to the routing table known_nodes 51 : * @param known_nodes 52 : * @return if some are new 53 : */ 54 : bool setKnownNodes(const std::vector<NodeId>& known_nodes); 55 : 56 : /** 57 : * Set list of nodes to the routing table mobile_nodes 58 : * @param mobile_nodes 59 : */ 60 : void setMobileNodes(const std::vector<NodeId>& mobile_nodes); 61 : 62 : /** 63 : * Add channel to routing table 64 : * @param channel 65 : */ 66 : void addChannel(const std::shared_ptr<dhtnet::ChannelSocketInterface>& channel); 67 : 68 : /** 69 : * Remove channel from routing table 70 : * @param channel 71 : */ 72 : void removeNode(const NodeId& nodeId); 73 : 74 : /** 75 : * Change mobility of specific node 76 : * @param nodeId 77 : * @param isMobile 78 : */ 79 : void changeMobility(const NodeId& nodeId, bool isMobile); 80 : 81 : /** 82 : * Check if swarm manager is connected 83 : * @return true if the swarm has at least one connected node, false if not 84 : */ 85 : bool isConnected() const; 86 : 87 : /** 88 : * get all nodes from the different tables in bucket 89 : */ 90 : std::vector<NodeId> getAllNodes() const; 91 : 92 : std::vector<NodeId> getConnectedNodes() const; 93 : 94 : std::vector<std::map<std::string, std::string>> getRoutingTableInfo() const; 95 : 96 472 : unsigned getActiveNodesCount() const { return routing_table.getActiveNodesCount(); } 97 : 98 : /** 99 : * Delete nodes from the different tables in bucket 100 : */ 101 : void deleteNode(const std::vector<NodeId>& nodes); 102 : 103 : // For tests 104 : 105 : /** 106 : * Get routing table 107 : * @return RoutingTable 108 : */ 109 229 : RoutingTable& getRoutingTable() { return routing_table; }; 110 : 111 : /** 112 : * Get buckets of routing table 113 : * @return buckets list 114 : */ 115 : std::list<Bucket>& getBuckets() { return routing_table.getBuckets(); }; 116 : 117 : /** 118 : * Shutdown swarm manager 119 : */ 120 : void shutdown(); 121 : 122 : /** 123 : * Restart the swarm manager. 124 : * 125 : * This function must be called in situations where we want 126 : * to use a swarm manager that was previously shut down. 127 : */ 128 : void restart(); 129 : 130 : /** 131 : * Display swarm manager info 132 : */ 133 : void display() 134 : { 135 : JAMI_DEBUG("SwarmManager {:s} has {:d} nodes in table [P = {}]", 136 : getId().to_c_str(), 137 : routing_table.getNodeCount(), 138 : isMobile_); 139 : // print nodes of routingtable 140 : for (auto& bucket : routing_table.getBuckets()) { 141 : for (auto& node : bucket.getNodes()) { 142 : JAMI_DEBUG("Node {:s}", node.first.toString()); 143 : } 144 : } 145 : } 146 : 147 : /* 148 : * Callback for connection changed 149 : * @param cb 150 : */ 151 514 : void onConnectionChanged(OnConnectionChanged cb) { onConnectionChanged_ = std::move(cb); } 152 : 153 : /** 154 : * Set mobility of swarm manager 155 : * @param isMobile 156 : */ 157 163 : void setMobility(bool isMobile) { isMobile_ = isMobile; } 158 : 159 : /** 160 : * Get mobility of swarm manager 161 : * @return true if mobile, false if not 162 : */ 163 9 : bool isMobile() const { return isMobile_; } 164 : 165 : /** 166 : * Maintain/Update buckets 167 : * @param toConnect Nodes to connect 168 : */ 169 : void maintainBuckets(const std::set<NodeId>& toConnect = {}); 170 : 171 : /** 172 : * Check if we're connected with a specific device 173 : * @param deviceId 174 : * @return true if connected, false if not 175 : */ 176 : bool isConnectedWith(const NodeId& deviceId); 177 : 178 : /** 179 : * Check if swarm manager is shutdown 180 : * @return true if shutdown, false if not 181 : */ 182 1029 : bool isShutdown() { return isShutdown_; }; 183 : 184 : private: 185 : /** 186 : * Add node to the known_nodes list 187 : * @param nodeId 188 : * @return if node inserted 189 : */ 190 : bool addKnownNode(const NodeId& nodeId); 191 : 192 : /** 193 : * Add node to the mobile_Nodes list 194 : * @param nodeId 195 : */ 196 : void addMobileNodes(const NodeId& nodeId); 197 : 198 : /** 199 : * Send nodes request to fill known_nodes list 200 : * @param socket 201 : * @param nodeId 202 : * @param q 203 : * @param numberNodes 204 : */ 205 : void sendRequest(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket, 206 : const NodeId& nodeId, 207 : Query q, 208 : int numberNodes = Bucket::BUCKET_MAX_SIZE); 209 : 210 : /** 211 : * Send answer to request 212 : * @param socket 213 : * @param msg 214 : */ 215 : void sendAnswer(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket, const Message& msg_); 216 : 217 : /** 218 : * Interpret received message 219 : * @param socket 220 : */ 221 : void receiveMessage(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket); 222 : 223 : /** 224 : * Reset node's timer expiry 225 : * @param ec 226 : * @param socket 227 : * @param node 228 : */ 229 : void resetNodeExpiry(const asio::error_code& ec, 230 : const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket, 231 : NodeId node = {}); 232 : 233 : /** 234 : * Try to establich connexion with specific node 235 : * @param nodeId 236 : */ 237 : void tryConnect(const NodeId& nodeId); 238 : 239 : /** 240 : * Remove node from routing table 241 : * @param nodeId 242 : */ 243 : void removeNodeInternal(const NodeId& nodeId); 244 : 245 : const NodeId id_; 246 : bool isMobile_ {false}; 247 : std::mt19937_64 rd; 248 : mutable std::mutex mutex; 249 : RoutingTable routing_table; 250 : 251 : std::atomic_bool isShutdown_ {false}; 252 : 253 : OnConnectionChanged onConnectionChanged_ {}; 254 : 255 : ToConnectCb toConnectCb_; 256 : }; 257 : 258 : } // namespace jami