You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
5.4 KiB
176 lines
5.4 KiB
/*
|
|
This file is part of cpp-ethereum.
|
|
|
|
cpp-ethereum is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
cpp-ethereum is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/** @file EthereumHost.h
|
|
* @author Gav Wood <i@gavwood.com>
|
|
* @date 2014
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <mutex>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <thread>
|
|
#include <libdevcore/Guards.h>
|
|
#include <libdevcore/Worker.h>
|
|
#include "HostCapability.h"
|
|
#include "Common.h"
|
|
namespace ba = boost::asio;
|
|
namespace bi = boost::asio::ip;
|
|
|
|
namespace dev
|
|
{
|
|
|
|
class RLPStream;
|
|
|
|
namespace p2p
|
|
{
|
|
|
|
struct NetworkPreferences
|
|
{
|
|
NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), publicIP(i), upnp(u), localNetworking(l) {}
|
|
|
|
unsigned short listenPort = 30303;
|
|
std::string publicIP;
|
|
bool upnp = true;
|
|
bool localNetworking = false;
|
|
};
|
|
|
|
/**
|
|
* @brief The Host class
|
|
* Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
|
|
*/
|
|
class Host: public Worker
|
|
{
|
|
friend class Session;
|
|
friend class HostCapabilityFace;
|
|
|
|
public:
|
|
/// Start server, listening for connections on the given port.
|
|
Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bool _start = false);
|
|
|
|
/// Will block on network process events.
|
|
virtual ~Host();
|
|
|
|
/// Closes all peers.
|
|
void disconnectPeers();
|
|
|
|
/// Basic peer network protocol version.
|
|
unsigned protocolVersion() const;
|
|
|
|
/// Register a peer-capability; all new peer connections will have this capability.
|
|
template <class T> std::shared_ptr<T> registerCapability(T* _t) { _t->m_host = this; auto ret = std::shared_ptr<T>(_t); m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = ret; return ret; }
|
|
|
|
bool haveCapability(CapDesc const& _name) const { return m_capabilities.count(_name) != 0; }
|
|
CapDescs caps() const { CapDescs ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; }
|
|
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; } }
|
|
|
|
/// Connect to a peer explicitly.
|
|
static std::string pocHost();
|
|
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
|
|
void connect(bi::tcp::endpoint const& _ep);
|
|
|
|
/// @returns true iff we have the a peer of the given id.
|
|
bool havePeer(h512 _id) const;
|
|
|
|
/// Set ideal number of peers.
|
|
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
|
|
|
|
/// Get peer information.
|
|
std::vector<PeerInfo> peers(bool _updatePing = false) const;
|
|
|
|
/// Get number of peers connected; equivalent to, but faster than, peers().size().
|
|
size_t peerCount() const { Guard l(x_peers); return m_peers.size(); }
|
|
|
|
/// Ping the peers, to update the latency information.
|
|
void pingAll();
|
|
|
|
/// Get the port we're listening on currently.
|
|
unsigned short listenPort() const { return m_public.port(); }
|
|
|
|
/// Serialise the set of known peers.
|
|
bytes savePeers() const;
|
|
|
|
/// Deserialise the data and populate the set of known peers.
|
|
void restorePeers(bytesConstRef _b);
|
|
|
|
void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); }
|
|
|
|
void start();
|
|
void stop();
|
|
bool isStarted() const { return isWorking(); }
|
|
|
|
h512 id() const { return m_id; }
|
|
|
|
void registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps);
|
|
|
|
private:
|
|
/// Called when the session has provided us with a new peer we can connect to.
|
|
void noteNewPeers() {}
|
|
|
|
void seal(bytes& _b);
|
|
void populateAddresses();
|
|
void determinePublic(std::string const& _publicAddress, bool _upnp);
|
|
void ensureAccepting();
|
|
|
|
void growPeers();
|
|
void prunePeers();
|
|
|
|
/// Conduct I/O, polling, syncing, whatever.
|
|
/// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway.
|
|
/// This won't touch alter the blockchain.
|
|
virtual void doWork();
|
|
|
|
std::map<h512, bi::tcp::endpoint> potentialPeers();
|
|
|
|
std::string m_clientVersion;
|
|
|
|
NetworkPreferences m_netPrefs;
|
|
|
|
static const int NetworkStopped = -1;
|
|
int m_listenPort = NetworkStopped;
|
|
|
|
ba::io_service m_ioService;
|
|
bi::tcp::acceptor m_acceptor;
|
|
bi::tcp::socket m_socket;
|
|
|
|
UPnP* m_upnp = nullptr;
|
|
bi::tcp::endpoint m_public;
|
|
h512 m_id;
|
|
|
|
mutable std::mutex x_peers;
|
|
mutable std::map<h512, std::weak_ptr<Session>> m_peers; // mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
|
|
|
|
std::map<h512, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers; // TODO: does this need a lock?
|
|
std::vector<h512> m_freePeers;
|
|
|
|
std::chrono::steady_clock::time_point m_lastPeersRequest;
|
|
unsigned m_idealPeerCount = 5;
|
|
|
|
std::vector<bi::address_v4> m_addresses;
|
|
std::vector<bi::address_v4> m_peerAddresses;
|
|
|
|
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities;
|
|
|
|
bool m_accepting = false;
|
|
};
|
|
|
|
}
|
|
}
|
|
|