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