C++ Distributed Hash Table
node.h
1 /*
2  * Copyright (C) 2014-2022 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 {
41  Socket() {}
42  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, std::mt19937_64& rd, bool client=false);
51  Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client=false);
52  Node(const InfoHash& id, const sockaddr* sa, socklen_t salen, std::mt19937_64& rd)
53  : Node(id, SockAddr(sa, salen), rd) {}
54 
55  InfoHash getId() const {
56  return id;
57  }
58  const SockAddr& getAddr() const { return addr; }
59  std::string getAddrStr() const {
60  return addr.toString();
61  }
62  bool isClient() const { return is_client; }
63  bool isIncoming() { return time > reply_time; }
64 
65  const time_point& getTime() const { return time; }
66  const time_point& getReplyTime() const { return reply_time; }
67  void setTime(const time_point& t) { time = t; }
68 
74  void authError() {
75  if (++auth_errors > MAX_AUTH_ERRORS)
76  setExpired();
77  }
78  void authSuccess() { auth_errors = 0; }
79 
80  bool isExpired() const { return expired_; }
81  bool isGood(time_point now) const;
82  bool isPendingMessage() const;
83  size_t getPendingMessageCount() const;
84 
85  bool isOld(const time_point& now) const {
86  return time + NODE_EXPIRE_TIME < now;
87  }
88  bool isRemovable(const time_point& now) const {
89  return isExpired() and isOld(now);
90  }
91 
92  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  }
99  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 
119  Tid openSocket(SocketCb&& cb);
120 
121  Sp<Socket> getSocket(Tid id);
122 
128  void closeSocket(Tid id);
129 
133  void reset() { expired_ = false; reply_time = time_point::min(); }
134 
140  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 }
void reset()
Definition: node.h:133
sa_family_t getFamily() const
Definition: sockaddr.h:123
void authError()
Definition: node.h:74
Definition: node.h:47
Tid getNewTid()
Definition: node.h:140
socklen_t getLength() const
Definition: sockaddr.h:205
void closeSocket(Tid id)
Tid openSocket(SocketCb &&cb)
Definition: callbacks.h:35
const sockaddr * get() const
Definition: sockaddr.h:218