Browse Source

makePeer and support setting listen IP.

cl-refactor
subtly 10 years ago
parent
commit
29f40bff0f
  1. 3
      alethzero/CMakeLists.txt
  2. 62
      alethzero/Connect.cpp
  3. 50
      alethzero/Connect.h
  4. 123
      alethzero/Connect.ui
  5. 51
      alethzero/Main.ui
  6. 53
      alethzero/MainWin.cpp
  7. 3
      alethzero/MainWin.h
  8. 9
      eth/main.cpp
  9. 1
      libp2p/Common.cpp
  10. 1
      libp2p/Common.h
  11. 49
      libp2p/Host.cpp
  12. 10
      libp2p/Host.h
  13. 25
      libp2p/Network.cpp
  14. 3
      libp2p/Network.h
  15. 27
      libp2p/NodeTable.cpp
  16. 2
      libp2p/NodeTable.h
  17. 2
      libp2p/Session.cpp
  18. 16
      libwebthree/WebThree.cpp
  19. 36
      libwebthree/WebThree.h
  20. 6
      neth/main.cpp
  21. 8
      test/peer.cpp

3
alethzero/CMakeLists.txt

@ -19,6 +19,7 @@ find_package (Qt5WebEngine QUIET)
find_package (Qt5WebEngineWidgets QUIET)
qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Connect.h Connect.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui)
@ -33,7 +34,7 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Debugger.ui Transact.ui
UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui
WIN_RESOURCES alethzero.rc
)

62
alethzero/Connect.cpp

@ -0,0 +1,62 @@
/*
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 Connect.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#include "Connect.h"
#include <libp2p/Host.h>
#include "ui_Connect.h"
Connect::Connect(QWidget *parent) :
QDialog(parent),
ui(new Ui::Connect)
{
reset();
}
Connect::~Connect()
{
delete ui;
}
void Connect::setEnvironment(QStringList const& _nodes)
{
ui->host->addItems(_nodes);
}
void Connect::reset()
{
ui->setupUi(this);
}
QString Connect::host()
{
return ui->host->currentText();
}
QString Connect::nodeId()
{
return ui->nodeId->text();
}
bool Connect::required()
{
return ui->required->isChecked();
}

50
alethzero/Connect.h

@ -0,0 +1,50 @@
/*
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 Connect.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#pragma once
#include <QDialog>
#include <QList>
namespace Ui { class Connect; }
namespace dev { namespace p2p { class Host; } }
class Connect : public QDialog
{
Q_OBJECT
public:
explicit Connect(QWidget *parent = 0);
~Connect();
void setEnvironment(QStringList const& _nodes);
void reset();
QString host();
QString nodeId();
bool required();
private:
Ui::Connect *ui;
};

123
alethzero/Connect.ui

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Connect</class>
<widget class="QDialog" name="Connect">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>343</width>
<height>178</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>343</width>
<height>178</height>
</size>
</property>
<property name="windowTitle">
<string>Connect to Peer</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="1" column="0">
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="host">
<property name="minimumSize">
<size>
<width>311</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLineEdit" name="nodeId">
<property name="placeholderText">
<string>Node Id</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="required">
<property name="text">
<string>Required (Always Connect to this Peer)</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="formLabel">
<property name="text">
<string>Enter a peer to which a connection may be made:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Connect</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Connect</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

51
alethzero/Main.ui

@ -134,7 +134,7 @@
<addaction name="go"/>
<addaction name="separator"/>
<addaction name="upnp"/>
<addaction name="usePast"/>
<addaction name="dropPeers"/>
<addaction name="net"/>
<addaction name="connect"/>
</widget>
@ -283,7 +283,7 @@
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Listen on</string>
@ -303,7 +303,7 @@
</property>
</widget>
</item>
<item row="1" column="2">
<item row="3" column="2">
<widget class="QSpinBox" name="port">
<property name="minimum">
<number>1024</number>
@ -316,17 +316,7 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Client Name</string>
</property>
<property name="buddy">
<cstring>clientName</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="3" column="1">
<widget class="QLineEdit" name="listenIP">
<property name="inputMask">
<string/>
@ -339,13 +329,6 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
@ -356,20 +339,37 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="5" column="1">
<widget class="QLineEdit" name="forcePublicIP">
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Public IP</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Client Name</string>
</property>
<property name="buddy">
<cstring>clientName</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -1456,12 +1456,12 @@ font-size: 14pt</string>
<string>Show &amp;Anonymous Accounts</string>
</property>
</action>
<action name="usePast">
<action name="dropPeers">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Use &amp;Past Peers</string>
<string>&amp;Drop Past Peers</string>
</property>
</action>
<action name="loadJS">
@ -1709,7 +1709,6 @@ font-size: 14pt</string>
<tabstop>idealPeers</tabstop>
<tabstop>listenIP</tabstop>
<tabstop>port</tabstop>
<tabstop>clientName</tabstop>
<tabstop>transactionQueue</tabstop>
<tabstop>pendingInfo</tabstop>
<tabstop>blockChainFilter</tabstop>

53
alethzero/MainWin.cpp

@ -28,6 +28,7 @@
//pragma GCC diagnostic ignored "-Werror=pedantic"
#include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog>
#include <QtWebEngine/QtWebEngine>
@ -251,8 +252,11 @@ void Main::addNewId(QString _ids)
NetworkPreferences Main::netPrefs() const
{
return NetworkPreferences(ui->forcePublicIP->text().toStdString(), ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked());
// return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked());
auto publicip = ui->forcePublicIP->text().toStdString();
if (isPublicAddress(publicip))
return NetworkPreferences(publicip, ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked());
else
return NetworkPreferences(ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked());
}
void Main::onKeysChanged()
@ -676,10 +680,7 @@ void Main::writeSettings()
}
s.setValue("upnp", ui->upnp->isChecked());
#warning fixme
// s.setValue("forceAddress", ui->forceAddress->text());
s.setValue("usePast", ui->usePast->isChecked());
// s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceAddress", ui->forcePublicIP->text());
s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("natSpec", ui->natSpec->isChecked());
@ -687,6 +688,7 @@ void Main::writeSettings()
s.setValue("showAllAccounts", ui->showAllAccounts->isChecked());
s.setValue("clientName", ui->clientName->text());
s.setValue("idealPeers", ui->idealPeers->value());
s.setValue("listenIP", ui->listenIP->text());
s.setValue("port", ui->port->value());
s.setValue("url", ui->urlEdit->text());
s.setValue("privateChain", m_privateChain);
@ -746,10 +748,8 @@ void Main::readSettings(bool _skipGeometry)
}
ui->upnp->setChecked(s.value("upnp", true).toBool());
#warning fixme
// ui->forceAddress->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool());
// ui->localNetworking->setChecked(s.value("localNetworking", true).toBool());
ui->forcePublicIP->setText(s.value("forceAddress", "").toString());
ui->dropPeers->setChecked(false);
ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool());
@ -760,6 +760,7 @@ void Main::readSettings(bool _skipGeometry)
if (ui->clientName->text().isEmpty())
ui->clientName->setText(QInputDialog::getText(nullptr, "Enter identity", "Enter a name that will identify you on the peer network"));
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->listenIP->setText(s.value("listenIP", "").toString());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString();
@ -1746,11 +1747,8 @@ void Main::on_net_triggered()
if (ui->net->isChecked())
{
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
// TODO: p2p
// if (m_networkConfig.size()/* && ui->usePast->isChecked()*/)
// web3()->restoreNetwork(bytesConstRef((byte*)m_networkConfig.data(), m_networkConfig.size()));
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
}
@ -1768,13 +1766,26 @@ void Main::on_connect_triggered()
ui->net->setChecked(true);
on_net_triggered();
}
bool ok = false;
QString s = QInputDialog::getItem(this, "Connect to a Network Peer", "Enter a peer to which a connection may be made:", m_servers, m_servers.count() ? rand() % m_servers.count() : 0, true, &ok);
if (ok && s.contains(":"))
m_connect.setEnvironment(m_servers);
if (m_connect.exec() == QDialog::Accepted)
{
string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt();
web3()->connect(host, port);
bool required = m_connect.required();
string host(m_connect.host().toUtf8().constData());
NodeId nodeid;
try
{
string nstr(m_connect.nodeId().toUtf8().constData());
nodeid = NodeId(fromHex(nstr));
}
catch (BadHexCharacter()) {}
m_connect.reset();
if (required)
web3()->requirePeer(nodeid, host);
else
web3()->addNode(nodeid, host);
}
}
@ -1885,7 +1896,7 @@ void Main::on_go_triggered()
ui->net->setChecked(true);
on_net_triggered();
}
web3()->connect(Host::pocHost());
web3()->addNode(p2p::NodeId(), Host::pocHost());
}
QString Main::prettyU256(dev::u256 _n) const

3
alethzero/MainWin.h

@ -40,6 +40,7 @@
#include "Context.h"
#include "Transact.h"
#include "NatspecHandler.h"
#include "Connect.h"
namespace Ui {
class Main;
@ -256,4 +257,6 @@ private:
std::unique_ptr<DappHost> m_dappHost;
DappLoader* m_dappLoader;
QWebEnginePage* m_webPage;
Connect m_connect;
};

9
eth/main.cpp

@ -421,8 +421,7 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
#warning fixme
NetworkPreferences netPrefs(listenPort);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3(
@ -450,9 +449,9 @@ int main(int argc, char** argv)
web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC
shared_ptr<WebThreeStubServer> jsonrpcServer;
@ -512,7 +511,7 @@ int main(int argc, char** argv)
string addr;
unsigned port;
iss >> addr >> port;
web3.connect(addr, (short)port);
web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
}
else if (cmd == "netstop")
{

1
libp2p/Common.cpp

@ -25,6 +25,7 @@ using namespace dev;
using namespace dev::p2p;
const unsigned dev::p2p::c_protocolVersion = 3;
const unsigned dev::p2p::c_defaultIPPort = 30303;
bool p2p::isPublicAddress(std::string const& _addressToCheck)
{

1
libp2p/Common.h

@ -50,6 +50,7 @@ namespace p2p
/// Peer network protocol version.
extern const unsigned c_protocolVersion;
extern const unsigned c_defaultIPPort;
using NodeId = h512;

49
libp2p/Host.cpp

@ -66,10 +66,6 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, byte
m_alias(networkAlias(_restoreNetwork)),
m_lastPing(chrono::steady_clock::time_point::min())
{
for (auto address: m_ifAddresses)
if (address.is_v4())
clog(NetNote) << "IP Address: " << address << " = " << (isPrivateAddress(address) ? "[LOCAL]" : "[PEER]");
clog(NetNote) << "Id:" << id();
}
@ -387,7 +383,7 @@ string Host::pocHost()
return "poc-" + strs[1] + ".ethdev.com";
}
void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPeerPort, unsigned short _udpNodePort)
void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpNodePort, unsigned short _tcpPeerPort)
{
// TODO: p2p clean this up (bring tested acceptor code over from network branch)
while (isWorking() && !m_run)
@ -404,36 +400,13 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short
_tcpPeerPort = 0;
}
boost::system::error_code ec;
bi::address addr = bi::address::from_string(_addr, ec);
if (ec)
{
bi::tcp::resolver *r = new bi::tcp::resolver(m_ioService);
r->async_resolve({_addr, toString(_tcpPeerPort)}, [=](boost::system::error_code const& _ec, bi::tcp::resolver::iterator _epIt)
{
if (!_ec)
{
bi::tcp::endpoint tcp = *_epIt;
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(tcp.address(), _udpNodePort), tcp)));
}
delete r;
});
}
else
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(addr, _udpNodePort), bi::tcp::endpoint(addr, _tcpPeerPort))));
}
void Host::relinquishPeer(NodeId const& _node)
{
Guard l(x_requiredPeers);
if (m_requiredPeers.count(_node))
m_requiredPeers.erase(_node);
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(_addr, _udpNodePort), bi::tcp::endpoint(_addr, _tcpPeerPort))));
}
void Host::requirePeer(NodeId const& _n, std::string const& _udpAddr, unsigned short _udpPort, std::string const& _tcpAddr, unsigned short _tcpPort)
void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr, unsigned short _tcpPort)
{
auto naddr = bi::address::from_string(_udpAddr);
auto paddr = _tcpAddr.empty() ? naddr : bi::address::from_string(_tcpAddr);
auto naddr = _udpAddr;
auto paddr = _tcpAddr.is_unspecified() ? naddr : _tcpAddr;
auto udp = bi::udp::endpoint(naddr, _udpPort);
auto tcp = bi::tcp::endpoint(paddr, _tcpPort ? _tcpPort : _udpPort);
Node node(_n, NodeIPEndpoint(udp, tcp));
@ -468,11 +441,18 @@ void Host::requirePeer(NodeId const& _n, std::string const& _udpAddr, unsigned s
{
if (!_ec && m_nodeTable)
if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint.udp.address().to_string(), n.endpoint.udp.port(), n.endpoint.tcp.address().to_string(), n.endpoint.tcp.port());
requirePeer(n.id, n.endpoint.udp.address(), n.endpoint.udp.port(), n.endpoint.tcp.address(), n.endpoint.tcp.port());
});
}
}
void Host::relinquishPeer(NodeId const& _node)
{
Guard l(x_requiredPeers);
if (m_requiredPeers.count(_node))
m_requiredPeers.erase(_node);
}
void Host::connect(std::shared_ptr<Peer> const& _p)
{
if (!m_run)
@ -760,6 +740,9 @@ void Host::restoreNetwork(bytesConstRef _b)
if (!isStarted())
BOOST_THROW_EXCEPTION(NetworkStartRequired());
if (m_dropPeers)
return;
RecursiveGuard l(x_sessions);
RLP r(_b);
if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion)

10
libp2p/Host.h

@ -95,6 +95,9 @@ public:
/// Default host for current version of client.
static std::string pocHost();
/// Resolve "host:port" or "ip:port" string as TCP endpoint. Returns unspecified endpoint on failure.
static bi::tcp::endpoint resolveHost(Host& _host, std::string const& _addr) { return Network::resolveHost(_host.m_ioService, _addr); }
/// 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; }
@ -103,10 +106,10 @@ public:
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; } }
/// Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity.
void addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort);
void addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort);
/// Create Peer and attempt keeping peer connected.
void requirePeer(NodeId const& _node, std::string const& _udpAddr, unsigned short _udpPort, std::string const& _tcpAddr = "", unsigned short _tcpPort = 0);
void requirePeer(NodeId const& _node, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr = bi::address(), unsigned short _tcpPort = 0);
/// Note peer as no longer being required.
void relinquishPeer(NodeId const& _node);
@ -132,7 +135,7 @@ public:
// 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.
Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; }
void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
/// Start network. @threadsafe
void start();
@ -236,6 +239,7 @@ private:
std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
bool m_accepting = false;
bool m_dropPeers = false;
};
}

25
libp2p/Network.cpp

@ -27,6 +27,7 @@
#endif
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/Assertions.h>
@ -206,3 +207,27 @@ bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses
return upnpep;
}
bi::tcp::endpoint Network::resolveHost(ba::io_service& _ioService, string const& _addr)
{
vector<string> split;
boost::split(split, _addr, boost::is_any_of(":"));
unsigned port = split.size() > 1 ? stoi(split[1]) : c_defaultIPPort;
bi::tcp::endpoint ep(bi::address(), port);
boost::system::error_code ec;
bi::address address = bi::address::from_string(split[0], ec);
if (!ec)
ep.address(address);
else
{
boost::system::error_code ec;
// resolve returns an iterator (host can resolve to multiple addresses)
bi::tcp::resolver r(_ioService);
auto it = r.resolve({split[0], toString(port)}, ec);
if (!ec)
ep = *it;
}
return ep;
}

3
libp2p/Network.h

@ -54,6 +54,9 @@ public:
/// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port.
static bi::tcp::endpoint traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr);
/// Resolve "host:port" string as TCP endpoint. Returns unspecified endpoint on failure.
static bi::tcp::endpoint resolveHost(ba::io_service& _ioService, std::string const& _host);
};
struct NetworkPreferences

27
libp2p/NodeTable.cpp

@ -101,6 +101,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp)));
m_nodes[_node.id] = ret;
ret->cullEndpoint();
clog(NodeTableConnect) << "addNode pending for" << m_node.endpoint.udp << m_node.endpoint.tcp;
PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port());
p.sign(m_secret);
m_socketPointer->send(p);
@ -450,6 +451,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
return; // unsolicited pong; don't note node as active
}
clog(NodeTableConnect) << "PONG from " << nodeid.abridged() << _from;
break;
}
@ -550,31 +552,16 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec)
clog(NodeTableEvent) << "refreshing buckets";
bool connected = m_socketPointer->isOpen();
bool refreshed = false;
if (connected)
{
Guard l(x_state);
for (auto& d: m_state)
if (chrono::steady_clock::now() - d.modified > c_bucketRefresh)
{
d.touch();
while (!d.nodes.empty())
{
auto n = d.nodes.front();
if (auto p = n.lock())
{
refreshed = true;
ping(p.get());
break;
}
d.nodes.pop_front();
}
}
NodeId randNodeId;
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0,h256::size));
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size,h256::size));
discover(randNodeId);
}
unsigned nextRefresh = connected ? (refreshed ? 200 : c_bucketRefresh.count()*1000) : 10000;
auto runcb = [this](boost::system::error_code const& error) { doRefreshBuckets(error); };
m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh));
m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(c_bucketRefresh.count()));
m_bucketRefreshTimer.async_wait(runcb);
}

2
libp2p/NodeTable.h

@ -195,7 +195,7 @@ private:
/* todo: replace boost::posix_time; change constants to upper camelcase */
boost::posix_time::milliseconds const c_evictionCheckInterval = boost::posix_time::milliseconds(75); ///< Interval at which eviction timeouts are checked.
std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations).
std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
std::chrono::milliseconds const c_bucketRefresh = std::chrono::milliseconds(112500); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
struct NodeBucket
{

2
libp2p/Session.cpp

@ -237,7 +237,7 @@ bool Session::interpret(PacketType _t, RLP const& _r)
// OK passed all our checks. Assume it's good.
addRating(1000);
m_server->addNode(id, ep.address().to_string(), ep.port(), ep.port());
m_server->addNode(id, ep.address(), ep.port(), ep.port());
clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")";
CONTINUE:;
LAMEPEER:;

16
libwebthree/WebThree.cpp

@ -27,7 +27,6 @@
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libp2p/Host.h>
#include <libethereum/Defaults.h>
#include <libethereum/EthereumHost.h>
#include <libwhisper/WhisperHost.h>
@ -73,12 +72,12 @@ WebThreeDirect::~WebThreeDirect()
m_ethereum.reset();
}
void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n)
void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers)
{
auto had = haveNetwork();
if (had)
stopNetwork();
m_net.setNetworkPreferences(_n);
m_net.setNetworkPreferences(_n, _dropPeers);
if (had)
startNetwork();
}
@ -103,7 +102,14 @@ bytes WebThreeDirect::saveNetwork()
return m_net.saveNetwork();
}
void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port)
void WebThreeDirect::addNode(NodeId const& _node, bi::tcp::endpoint const& _host)
{
m_net.addNode(NodeId(), _seedHost, _port, _port);
m_net.addNode(_node, _host.address(), _host.port(), _host.port());
}
void WebThreeDirect::requirePeer(NodeId const& _node, bi::tcp::endpoint const& _host)
{
m_net.requirePeer(_node, _host.address(), _host.port());
}

36
libwebthree/WebThree.h

@ -63,8 +63,11 @@ public:
/// Same as peers().size(), but more efficient.
virtual size_t peerCount() const = 0;
/// Connect to a particular peer.
virtual void connect(std::string const& _seedHost, unsigned short _port) = 0;
/// Add node to connect to.
virtual void addNode(p2p::NodeId const& _node, bi::tcp::endpoint const& _hostEndpoint) = 0;
/// Require connection to peer.
virtual void requirePeer(p2p::NodeId const& _node, bi::tcp::endpoint const& _endpoint) = 0;
/// Save peers
virtual dev::bytes saveNetwork() = 0;
@ -74,7 +77,7 @@ public:
virtual bool haveNetwork() const = 0;
virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n) = 0;
virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) = 0;
virtual p2p::NodeId id() const = 0;
@ -138,21 +141,36 @@ public:
/// Same as peers().size(), but more efficient.
size_t peerCount() const override;
/// Connect to a particular peer.
void connect(std::string const& _seedHost, unsigned short _port = 30303) override;
/// Add node to connect to.
virtual void addNode(p2p::NodeId const& _node, bi::tcp::endpoint const& _hostEndpoint) override;
/// Add node to connect to.
void addNode(p2p::NodeId const& _node, std::string const& _hostString) { addNode(_node, resolveHost(_hostString)); }
/// Add node to connect to.
void addNode(bi::tcp::endpoint const& _endpoint) { addNode(p2p::NodeId(), _endpoint); }
/// Add node to connect to.
void addNode(std::string const& _hostString) { addNode(p2p::NodeId(), _hostString); }
/// Require connection to peer.
void requirePeer(p2p::NodeId const& _node, bi::tcp::endpoint const& _endpoint) override;
/// Require connection to peer.
void requirePeer(p2p::NodeId const& _node, std::string const& _hostString) { requirePeer(_node, resolveHost(_hostString)); }
/// Resolve "host[:port]" string as TCP endpoint. Returns unspecified endpoint on failure.
bi::tcp::endpoint resolveHost(std::string const& _host) { return haveNetwork() ? p2p::Host::resolveHost(m_net, _host) : bi::tcp::endpoint(); }
/// Save peers
dev::bytes saveNetwork() override;
// /// Restore peers
// void restoreNetwork(bytesConstRef _saved) override;
/// Sets the ideal number of peers.
void setIdealPeerCount(size_t _n) override;
bool haveNetwork() const override { return m_net.isStarted(); }
void setNetworkPreferences(p2p::NetworkPreferences const& _n) override;
void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers = false) override;
p2p::NodeId id() const override { return m_net.id(); }

6
neth/main.cpp

@ -572,9 +572,9 @@ int main(int argc, char** argv)
web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
if (c && mining)
c->startMining();
@ -699,7 +699,7 @@ int main(int argc, char** argv)
string addr;
unsigned port;
iss >> addr >> port;
web3.connect(addr, (short)port);
web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
}
else if (cmd == "netstop")
{

8
test/peer.cpp

@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(host)
auto node2 = host2.id();
host2.start();
host1.addNode(node2, "127.0.0.1", host2prefs.listenPort, host2prefs.listenPort);
host1.addNode(node2, bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort);
this_thread::sleep_for(chrono::seconds(3));
@ -73,11 +73,11 @@ BOOST_AUTO_TEST_CASE(save_nodes)
Host& host = *hosts.front();
for (auto const& h: hosts)
host.addNode(h->id(), "127.0.0.1", h->listenPort(), h->listenPort());
host.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort());
Host& host2 = *hosts.back();
for (auto const& h: hosts)
host2.addNode(h->id(), "127.0.0.1", h->listenPort(), h->listenPort());
host2.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort());
this_thread::sleep_for(chrono::milliseconds(2000));
bytes firstHostNetwork(host.saveNetwork());
@ -122,7 +122,7 @@ int peerTest(int argc, char** argv)
Host ph("Test", NetworkPreferences(listenPort));
if (!remoteHost.empty() && !remoteAlias)
ph.addNode(remoteAlias, remoteHost, remotePort, remotePort);
ph.addNode(remoteAlias, bi::address::from_string(remoteHost), remotePort, remotePort);
this_thread::sleep_for(chrono::milliseconds(200));

Loading…
Cancel
Save