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