Host.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file Host.h
  15. * @author Alex Leverington <nessence@gmail.com>
  16. * @author Gav Wood <i@gavwood.com>
  17. * @date 2014
  18. */
  19. #pragma once
  20. #include <mutex>
  21. #include <map>
  22. #include <vector>
  23. #include <set>
  24. #include <memory>
  25. #include <utility>
  26. #include <thread>
  27. #include <chrono>
  28. #include <libdevcore/Guards.h>
  29. #include <libdevcore/Worker.h>
  30. #include <libdevcrypto/Common.h>
  31. #include <libdevcrypto/ECDHE.h>
  32. #include "NodeTable.h"
  33. #include "HostCapability.h"
  34. #include "Network.h"
  35. #include "Peer.h"
  36. #include "RLPXSocket.h"
  37. #include "RLPXFrameCoder.h"
  38. #include "Common.h"
  39. namespace ba = boost::asio;
  40. namespace bi = ba::ip;
  41. namespace std
  42. {
  43. template<> struct hash<pair<dev::p2p::NodeID, string>>
  44. {
  45. size_t operator()(pair<dev::p2p::NodeID, string> const& _value) const
  46. {
  47. size_t ret = hash<dev::p2p::NodeID>()(_value.first);
  48. return ret ^ (hash<string>()(_value.second) + 0x9e3779b9 + (ret << 6) + (ret >> 2));
  49. }
  50. };
  51. }
  52. namespace dev
  53. {
  54. namespace p2p
  55. {
  56. class Host;
  57. class HostNodeTableHandler: public NodeTableEventHandler
  58. {
  59. public:
  60. HostNodeTableHandler(Host& _host);
  61. Host const& host() const { return m_host; }
  62. private:
  63. virtual void processEvent(NodeID const& _n, NodeTableEventType const& _e);
  64. Host& m_host;
  65. };
  66. struct SubReputation
  67. {
  68. bool isRude = false;
  69. int utility = 0;
  70. bytes data;
  71. };
  72. struct Reputation
  73. {
  74. std::unordered_map<std::string, SubReputation> subs;
  75. };
  76. class ReputationManager
  77. {
  78. public:
  79. ReputationManager();
  80. void noteRude(Session const& _s, std::string const& _sub = std::string());
  81. bool isRude(Session const& _s, std::string const& _sub = std::string()) const;
  82. void setData(Session const& _s, std::string const& _sub, bytes const& _data);
  83. bytes data(Session const& _s, std::string const& _subs) const;
  84. private:
  85. std::unordered_map<std::pair<p2p::NodeID, std::string>, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible.
  86. SharedMutex mutable x_nodes;
  87. };
  88. struct NodeInfo
  89. {
  90. NodeInfo() = default;
  91. NodeInfo(NodeID const& _id, std::string const& _address, unsigned _port, std::string const& _version):
  92. id(_id), address(_address), port(_port), version(_version) {}
  93. std::string enode() const { return "enode://" + id.hex() + "@" + address + ":" + toString(port); }
  94. NodeID id;
  95. std::string address;
  96. unsigned port;
  97. std::string version;
  98. };
  99. /**
  100. * @brief The Host class
  101. * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
  102. *
  103. * @todo determinePublic: ipv6, udp
  104. * @todo per-session keepalive/ping instead of broadcast; set ping-timeout via median-latency
  105. */
  106. class Host: public Worker
  107. {
  108. friend class HostNodeTableHandler;
  109. friend class RLPXHandshake;
  110. friend class Session;
  111. friend class HostCapabilityFace;
  112. public:
  113. /// Start server, listening for connections on the given port.
  114. Host(
  115. std::string const& _clientVersion,
  116. NetworkPreferences const& _n = NetworkPreferences(),
  117. bytesConstRef _restoreNetwork = bytesConstRef()
  118. );
  119. /// Alternative constructor that allows providing the node key directly
  120. /// without restoring the network.
  121. Host(
  122. std::string const& _clientVersion,
  123. KeyPair const& _alias,
  124. NetworkPreferences const& _n = NetworkPreferences()
  125. );
  126. /// Will block on network process events.
  127. virtual ~Host();
  128. /// Default hosts for current version of client.
  129. static std::unordered_map<Public, std::string> const& pocHosts();
  130. /// Register a peer-capability; all new peer connections will have this capability.
  131. template <class T> std::shared_ptr<T> registerCapability(std::shared_ptr<T> const& _t) { _t->m_host = this; m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = _t; return _t; }
  132. template <class T> void addCapability(std::shared_ptr<T> const & _p, std::string const& _name, u256 const& _version) { m_capabilities[std::make_pair(_name, _version)] = _p; }
  133. bool haveCapability(CapDesc const& _name) const { return m_capabilities.count(_name) != 0; }
  134. CapDescs caps() const { CapDescs ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; }
  135. template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } }
  136. /// Add a potential peer.
  137. void addPeer(NodeSpec const& _s, PeerType _t);
  138. /// Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity.
  139. void addNode(NodeID const& _node, NodeIPEndpoint const& _endpoint);
  140. /// Create Peer and attempt keeping peer connected.
  141. void requirePeer(NodeID const& _node, NodeIPEndpoint const& _endpoint);
  142. /// Create Peer and attempt keeping peer connected.
  143. void requirePeer(NodeID const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort) { requirePeer(_node, NodeIPEndpoint(_addr, _udpPort, _tcpPort)); }
  144. /// Note peer as no longer being required.
  145. void relinquishPeer(NodeID const& _node);
  146. /// Set ideal number of peers.
  147. void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
  148. /// Set multipier for max accepted connections.
  149. void setPeerStretch(unsigned _n) { m_stretchPeers = _n; }
  150. /// Get peer information.
  151. PeerSessionInfos peerSessionInfo() const;
  152. /// Get number of peers connected.
  153. size_t peerCount() const;
  154. /// Get the address we're listening on currently.
  155. std::string listenAddress() const { return m_tcpPublic.address().is_unspecified() ? "0.0.0.0" : m_tcpPublic.address().to_string(); }
  156. /// Get the port we're listening on currently.
  157. unsigned short listenPort() const { return std::max(0, m_listenPort); }
  158. /// Serialise the set of known peers.
  159. bytes saveNetwork() const;
  160. // TODO: P2P this should be combined with peers into a HostStat object of some kind; coalesce data, as it's only used for status information.
  161. Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; }
  162. NetworkPreferences const& networkPreferences() const { return m_netPrefs; }
  163. void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
  164. /// Start network. @threadsafe
  165. void start();
  166. /// Stop network. @threadsafe
  167. /// Resets acceptor, socket, and IO service. Called by deallocator.
  168. void stop();
  169. /// @returns if network has been started.
  170. bool isStarted() const { return isWorking(); }
  171. /// @returns our reputation manager.
  172. ReputationManager& repMan() { return m_repMan; }
  173. /// @returns if network is started and interactive.
  174. bool haveNetwork() const { Guard l(x_runTimer); return m_run && !!m_nodeTable; }
  175. /// Validates and starts peer session, taking ownership of _io. Disconnects and returns false upon error.
  176. void startPeerSession(Public const& _id, RLP const& _hello, std::unique_ptr<RLPXFrameCoder>&& _io, std::shared_ptr<RLPXSocket> const& _s);
  177. /// Get session by id
  178. std::shared_ptr<Session> peerSession(NodeID const& _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? m_sessions[_id].lock() : std::shared_ptr<Session>(); }
  179. /// Get our current node ID.
  180. NodeID id() const { return m_alias.pub(); }
  181. /// Get the public TCP endpoint.
  182. bi::tcp::endpoint const& tcpPublic() const { return m_tcpPublic; }
  183. /// Get the public endpoint information.
  184. std::string enode() const { return "enode://" + id().hex() + "@" + (networkPreferences().publicIPAddress.empty() ? m_tcpPublic.address().to_string() : networkPreferences().publicIPAddress) + ":" + toString(m_tcpPublic.port()); }
  185. /// Get the node information.
  186. p2p::NodeInfo nodeInfo() const { return NodeInfo(id(), (networkPreferences().publicIPAddress.empty() ? m_tcpPublic.address().to_string() : networkPreferences().publicIPAddress), m_tcpPublic.port(), m_clientVersion); }
  187. protected:
  188. void onNodeTableEvent(NodeID const& _n, NodeTableEventType const& _e);
  189. /// Deserialise the data and populate the set of known peers.
  190. void restoreNetwork(bytesConstRef _b);
  191. private:
  192. enum PeerSlotType { Egress, Ingress };
  193. unsigned peerSlots(PeerSlotType _type) { return _type == Egress ? m_idealPeerCount : m_idealPeerCount * m_stretchPeers; }
  194. bool havePeerSession(NodeID const& _id) { return !!peerSession(_id); }
  195. /// Determines and sets m_tcpPublic to publicly advertised address.
  196. void determinePublic();
  197. void connect(std::shared_ptr<Peer> const& _p);
  198. /// Returns true if pending and connected peer count is less than maximum
  199. bool peerSlotsAvailable(PeerSlotType _type = Ingress) { Guard l(x_pendingNodeConns); return peerCount() + m_pendingPeerConns.size() < peerSlots(_type); }
  200. /// Ping the peers to update the latency information and disconnect peers which have timed out.
  201. void keepAlivePeers();
  202. /// Disconnect peers which didn't respond to keepAlivePeers ping prior to c_keepAliveTimeOut.
  203. void disconnectLatePeers();
  204. /// Called only from startedWorking().
  205. void runAcceptor();
  206. /// Called by Worker. Not thread-safe; to be called only by worker.
  207. virtual void startedWorking();
  208. /// Called by startedWorking. Not thread-safe; to be called only be Worker.
  209. void run(boost::system::error_code const& error); ///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions.
  210. /// Run network. Not thread-safe; to be called only by worker.
  211. virtual void doWork();
  212. /// Shutdown network. Not thread-safe; to be called only by worker.
  213. virtual void doneWorking();
  214. /// Get or create host identifier (KeyPair).
  215. static KeyPair networkAlias(bytesConstRef _b);
  216. bytes m_restoreNetwork; ///< Set by constructor and used to set Host key and restore network peers & nodes.
  217. bool m_run = false; ///< Whether network is running.
  218. mutable std::mutex x_runTimer; ///< Start/stop mutex.
  219. std::string m_clientVersion; ///< Our version string.
  220. NetworkPreferences m_netPrefs; ///< Network settings.
  221. /// Interface addresses (private, public)
  222. std::set<bi::address> m_ifAddresses; ///< Interface addresses.
  223. int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized.
  224. ba::io_service m_ioService; ///< IOService for network stuff.
  225. bi::tcp::acceptor m_tcp4Acceptor; ///< Listening acceptor.
  226. std::unique_ptr<boost::asio::deadline_timer> m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms.
  227. static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected.
  228. std::set<Peer*> m_pendingPeerConns; /// Used only by connect(Peer&) to limit concurrently connecting to same node. See connect(shared_ptr<Peer>const&).
  229. Mutex x_pendingNodeConns;
  230. bi::tcp::endpoint m_tcpPublic; ///< Our public listening endpoint.
  231. KeyPair m_alias; ///< Alias for network communication. Network address is k*G. k is key material. TODO: Replace KeyPair.
  232. std::shared_ptr<NodeTable> m_nodeTable; ///< Node table (uses kademlia-like discovery).
  233. /// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer;
  234. std::unordered_map<NodeID, std::shared_ptr<Peer>> m_peers;
  235. /// Peers we try to connect regardless of p2p network.
  236. std::set<NodeID> m_requiredPeers;
  237. Mutex x_requiredPeers;
  238. /// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run())
  239. /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
  240. mutable std::unordered_map<NodeID, std::weak_ptr<Session>> m_sessions;
  241. mutable RecursiveMutex x_sessions;
  242. std::list<std::weak_ptr<RLPXHandshake>> m_connecting; ///< Pending connections.
  243. Mutex x_connecting; ///< Mutex for m_connecting.
  244. unsigned m_idealPeerCount = 11; ///< Ideal number of peers to be connected to.
  245. unsigned m_stretchPeers = 7; ///< Accepted connection multiplier (max peers = ideal*stretch).
  246. std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support.
  247. /// Deadline timers used for isolated network events. GC'd by run.
  248. std::list<std::shared_ptr<boost::asio::deadline_timer>> m_timers;
  249. Mutex x_timers;
  250. std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
  251. bool m_accepting = false;
  252. bool m_dropPeers = false;
  253. ReputationManager m_repMan;
  254. };
  255. }
  256. }