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