1 /* 2 * Copyright (C) 2014-2019 Savoir-faire Linux Inc. 3 * Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com> 4 * Simon Désaulniers <simon.desaulniers@savoirfairelinux.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <https://www.gnu.org/licenses/>. 18 */ 19 20 #pragma once 21 22 #include "infohash.h" // includes socket structures 23 #include "utils.h" 24 #include "sockaddr.h" 25 26 #include <list> 27 #include <map> 28 29 namespace dht { 30 31 struct Node; 32 namespace net { 33 struct Request; 34 struct Socket; 35 struct RequestAnswer; 36 } /* namespace net */ 37 38 using Tid = uint32_t; 39 using SocketCb = std::function<void(const Sp<Node>&, net::RequestAnswer&&)>; 40 struct Socket { SocketSocket41 Socket() {} SocketSocket42 Socket(SocketCb&& on_receive) : 43 on_receive(std::move(on_receive)) {} 44 SocketCb on_receive {}; 45 }; 46 47 struct Node { 48 const InfoHash id; 49 50 Node(const InfoHash& id, const SockAddr& addr, bool client=false); 51 Node(const InfoHash& id, SockAddr&& addr, bool client=false); NodeNode52 Node(const InfoHash& id, const sockaddr* sa, socklen_t salen) 53 : Node(id, SockAddr(sa, salen)) {} 54 getIdNode55 InfoHash getId() const { 56 return id; 57 } getAddrNode58 const SockAddr& getAddr() const { return addr; } getAddrStrNode59 std::string getAddrStr() const { 60 return addr.toString(); 61 } isClientNode62 bool isClient() const { return is_client; } isIncomingNode63 bool isIncoming() { return time > reply_time; } 64 getTimeNode65 const time_point& getTime() const { return time; } getReplyTimeNode66 const time_point& getReplyTime() const { return reply_time; } setTimeNode67 void setTime(const time_point& t) { time = t; } 68 69 /** 70 * Makes notice about an additionnal authentication error with this node. Up 71 * to MAX_AUTH_ERRORS errors are accepted in order to let the node recover. 72 * Upon this limit, the node expires. 73 */ authErrorNode74 void authError() { 75 if (++auth_errors > MAX_AUTH_ERRORS) 76 setExpired(); 77 } authSuccessNode78 void authSuccess() { auth_errors = 0; } 79 isExpiredNode80 bool isExpired() const { return expired_; } 81 bool isGood(time_point now) const; 82 bool isPendingMessage() const; 83 size_t getPendingMessageCount() const; 84 isOldNode85 bool isOld(const time_point& now) const { 86 return time + NODE_EXPIRE_TIME < now; 87 } isRemovableNode88 bool isRemovable(const time_point& now) const { 89 return isExpired() and isOld(now); 90 } 91 exportNodeNode92 NodeExport exportNode() const { 93 NodeExport ne; 94 ne.id = id; 95 ne.sslen = addr.getLength(); 96 std::memcpy(&ne.ss, addr.get(), ne.sslen); 97 return ne; 98 } getFamilyNode99 sa_family_t getFamily() const { return addr.getFamily(); } 100 101 void update(const SockAddr&); 102 103 void requested(const Sp<net::Request>& req); 104 void received(time_point now, const Sp<net::Request>& req); 105 Sp<net::Request> getRequest(Tid tid); 106 void cancelRequest(const Sp<net::Request>& req); 107 108 void setExpired(); 109 110 /** 111 * Opens a socket on which a node will be able allowed to write for further 112 * additionnal updates following the response to a previous request. 113 * 114 * @param node The node which will be allowed to write on this socket. 115 * @param cb The callback to execute once updates arrive on the socket. 116 * 117 * @return the socket. 118 */ 119 Tid openSocket(SocketCb&& cb); 120 121 Sp<Socket> getSocket(Tid id); 122 123 /** 124 * Closes a socket so that no further data will be red on that socket. 125 * 126 * @param socket The socket to close. 127 */ 128 void closeSocket(Tid id); 129 130 /** 131 * Resets the state of the node so it's not expired anymore. 132 */ resetNode133 void reset() { expired_ = false; reply_time = time_point::min(); } 134 135 /** 136 * Generates a new request id, skipping the invalid id. 137 * 138 * @return the new id. 139 */ getNewTidNode140 Tid getNewTid() { 141 ++transaction_id; 142 return transaction_id ? ++transaction_id : transaction_id; 143 } 144 145 std::string toString() const; 146 147 OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Node& h); 148 149 static constexpr const std::chrono::minutes NODE_GOOD_TIME {120}; 150 151 /* The time after which we consider a node to be expirable. */ 152 static constexpr const std::chrono::minutes NODE_EXPIRE_TIME {10}; 153 154 /* Time for a request to timeout */ 155 static constexpr const std::chrono::seconds MAX_RESPONSE_TIME {1}; 156 157 private: 158 /* Number of times we accept authentication errors from this node. */ 159 static const constexpr unsigned MAX_AUTH_ERRORS {3}; 160 161 SockAddr addr; 162 bool is_client {false}; 163 time_point time {time_point::min()}; /* last time eared about */ 164 time_point reply_time {time_point::min()}; /* time of last correct reply received */ 165 unsigned auth_errors {0}; 166 bool expired_ {false}; 167 Tid transaction_id; 168 using TransactionDist = std::uniform_int_distribution<decltype(transaction_id)>; 169 170 std::map<Tid, Sp<net::Request>> requests_ {}; 171 std::map<Tid, Sp<Socket>> sockets_; 172 }; 173 174 } 175