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 4692 : std::weak_ptr<SwarmManager> weak() { return weak_from_this(); } 42 : 43 : /** 44 : * Get swarm manager id 45 : * @return NodeId 46 : */ 47 1947 : 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 : /** 95 : * Delete nodes from the different tables in bucket 96 : */ 97 : void deleteNode(const std::vector<NodeId>& nodes); 98 : 99 : // For tests 100 : 101 : /** 102 : * Get routing table 103 : * @return RoutingTable 104 : */ 105 518 : RoutingTable& getRoutingTable() { return routing_table; }; 106 : 107 : /** 108 : * Get buckets of routing table 109 : * @return buckets list 110 : */ 111 : std::list<Bucket>& getBuckets() { return routing_table.getBuckets(); }; 112 : 113 : /** 114 : * Shutdown swarm manager 115 : */ 116 : void shutdown(); 117 : 118 : /** 119 : * Restart the swarm manager. 120 : * 121 : * This function must be called in situations where we want 122 : * to use a swarm manager that was previously shut down. 123 : */ 124 : void restart(); 125 : 126 : /** 127 : * Display swarm manager info 128 : */ 129 : void display() 130 : { 131 : JAMI_DEBUG("SwarmManager {:s} has {:d} nodes in table [P = {}]", 132 : getId().to_c_str(), 133 : routing_table.getNodeCount(), 134 : isMobile_); 135 : // print nodes of routingtable 136 : for (auto& bucket : routing_table.getBuckets()) { 137 : for (auto& node : bucket.getNodes()) { 138 : JAMI_DEBUG("Node {:s}", node.first.toString()); 139 : } 140 : } 141 : } 142 : 143 : /* 144 : * Callback for connection changed 145 : * @param cb 146 : */ 147 513 : void onConnectionChanged(OnConnectionChanged cb) { onConnectionChanged_ = std::move(cb); } 148 : 149 : /** 150 : * Set mobility of swarm manager 151 : * @param isMobile 152 : */ 153 163 : void setMobility(bool isMobile) { isMobile_ = isMobile; } 154 : 155 : /** 156 : * Get mobility of swarm manager 157 : * @return true if mobile, false if not 158 : */ 159 9 : bool isMobile() const { return isMobile_; } 160 : 161 : /** 162 : * Maintain/Update buckets 163 : * @param toConnect Nodes to connect 164 : */ 165 : void maintainBuckets(const std::set<NodeId>& toConnect = {}); 166 : 167 : /** 168 : * Check if we're connected with a specific device 169 : * @param deviceId 170 : * @return true if connected, false if not 171 : */ 172 : bool isConnectedWith(const NodeId& deviceId); 173 : 174 : /** 175 : * Check if swarm manager is shutdown 176 : * @return true if shutdown, false if not 177 : */ 178 1041 : bool isShutdown() { return isShutdown_; }; 179 : 180 : private: 181 : /** 182 : * Add node to the known_nodes list 183 : * @param nodeId 184 : * @return if node inserted 185 : */ 186 : bool addKnownNode(const NodeId& nodeId); 187 : 188 : /** 189 : * Add node to the mobile_Nodes list 190 : * @param nodeId 191 : */ 192 : void addMobileNodes(const NodeId& nodeId); 193 : 194 : /** 195 : * Send nodes request to fill known_nodes list 196 : * @param socket 197 : * @param nodeId 198 : * @param q 199 : * @param numberNodes 200 : */ 201 : void sendRequest(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket, 202 : const NodeId& nodeId, 203 : Query q, 204 : int numberNodes = Bucket::BUCKET_MAX_SIZE); 205 : 206 : /** 207 : * Send answer to request 208 : * @param socket 209 : * @param msg 210 : */ 211 : void sendAnswer(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket, const Message& msg_); 212 : 213 : /** 214 : * Interpret received message 215 : * @param socket 216 : */ 217 : void receiveMessage(const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket); 218 : 219 : /** 220 : * Reset node's timer expiry 221 : * @param ec 222 : * @param socket 223 : * @param node 224 : */ 225 : void resetNodeExpiry(const asio::error_code& ec, 226 : const std::shared_ptr<dhtnet::ChannelSocketInterface>& socket, 227 : NodeId node = {}); 228 : 229 : /** 230 : * Try to establich connexion with specific node 231 : * @param nodeId 232 : */ 233 : void tryConnect(const NodeId& nodeId); 234 : 235 : /** 236 : * Remove node from routing table 237 : * @param nodeId 238 : */ 239 : void removeNodeInternal(const NodeId& nodeId); 240 : 241 : const NodeId id_; 242 : bool isMobile_ {false}; 243 : std::mt19937_64 rd; 244 : mutable std::mutex mutex; 245 : RoutingTable routing_table; 246 : 247 : std::atomic_bool isShutdown_ {false}; 248 : 249 : OnConnectionChanged onConnectionChanged_ {}; 250 : 251 : ToConnectCb toConnectCb_; 252 : }; 253 : 254 : } // namespace jami