From 8fb315be4951ca3877dc890c901fed3d0ed91fc2 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 26 Mar 2015 06:19:47 +0100 Subject: [PATCH 01/21] refactor network prefs --- libp2p/Host.cpp | 92 ++++++++++++++++++++-------------------------- libp2p/Host.h | 8 ++-- libp2p/Network.cpp | 59 +++++++++++++++++++---------- libp2p/Network.h | 31 ++++++++++------ 4 files changed, 100 insertions(+), 90 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b946d9b3e..4ce672602 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -287,67 +287,53 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) } } -void Host::determinePublic(string const& _publicAddress, bool _upnp) +void Host::determinePublic(NetworkPreferences const& _netPrefs) { - m_peerAddresses.clear(); - - // no point continuing if there are no interface addresses or valid listen port - if (!m_ifAddresses.size() || m_listenPort < 1) - return; - - // populate interfaces we'll listen on (eth listens on all interfaces); ignores local - for (auto addr: m_ifAddresses) - if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && !isLocalHostAddress(addr)) - m_peerAddresses.insert(addr); - - // if user supplied address is a public address then we use it - // if user supplied address is private, and localnetworking is enabled, we use it - bi::address reqPublicAddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress))); - bi::tcp::endpoint reqPublic(reqPublicAddr, m_listenPort); - bool isprivate = isPrivateAddress(reqPublicAddr); - bool ispublic = !isprivate && !isLocalHostAddress(reqPublicAddr); - if (!reqPublicAddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking))) + // set m_tcpPublic := listenIP (if public) > public > upnp > unspecified address. + + auto ifAddresses = Network::getInterfaceAddresses(); + auto laddr = bi::address::from_string(_netPrefs.listenIPAddress); + auto lset = !laddr.is_unspecified(); + auto paddr = bi::address::from_string(_netPrefs.publicIPAddress); + auto pset = !paddr.is_unspecified(); + + bool listenIsPublic = lset && isPublicAddress(laddr); + bool publicIsHost = !lset && pset && ifAddresses.count(paddr); + + bi::tcp::endpoint ep(bi::address(), _netPrefs.listenPort); + if (_netPrefs.traverseNAT && listenIsPublic) { - if (!m_peerAddresses.count(reqPublicAddr)) - m_peerAddresses.insert(reqPublicAddr); - m_tcpPublic = reqPublic; - return; + clog(NetNote) << "Listen address set to Public address:" << laddr << ". UPnP disabled."; + ep.address(laddr); } - - // if address wasn't provided, then use first public ipv4 address found - for (auto addr: m_peerAddresses) - if (addr.is_v4() && !isPrivateAddress(addr)) - { - m_tcpPublic = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort); - return; - } - - // or find address via upnp - if (_upnp) + else if (_netPrefs.traverseNAT && publicIsHost) + { + clog(NetNote) << "Public address set to Host configured address:" << paddr << ". UPnP disabled."; + ep.address(paddr); + } + else if (_netPrefs.traverseNAT) { - bi::address upnpifaddr; - bi::tcp::endpoint upnpep = Network::traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr); - if (!upnpep.address().is_unspecified() && !upnpifaddr.is_unspecified()) + bi::address natIFAddr; + if (lset && ifAddresses.count(laddr)) + ep = Network::traverseNAT(std::set({laddr}), _netPrefs.listenPort, natIFAddr); + else + ep = Network::traverseNAT(ifAddresses, _netPrefs.listenPort, natIFAddr); + + if (lset && natIFAddr != laddr) + // if listen address is set we use it, even if upnp returns different + clog(NetWarn) << "Listen address" << laddr << "differs from local address" << natIFAddr << "returned by UPnP!"; + + if (pset && ep.address() != paddr) { - if (!m_peerAddresses.count(upnpep.address())) - m_peerAddresses.insert(upnpep.address()); - m_tcpPublic = upnpep; - return; + // if public address is set we advertise it, even if upnp returns different + clog(NetWarn) << "Specified public address" << paddr << "differs from external address" << ep.address() << "returned by UPnP!"; + ep.address(paddr); } } + else if (pset) + ep.address(paddr); - // or if no address provided, use private ipv4 address if local networking is enabled - if (reqPublicAddr.is_unspecified()) - if (m_netPrefs.localNetworking) - for (auto addr: m_peerAddresses) - if (addr.is_v4() && isPrivateAddress(addr)) - { - m_tcpPublic = bi::tcp::endpoint(addr, m_listenPort); - return; - } - - // otherwise address is unspecified - m_tcpPublic = bi::tcp::endpoint(bi::address(), m_listenPort); + m_tcpPublic = ep; } void Host::runAcceptor() diff --git a/libp2p/Host.h b/libp2p/Host.h index 0feda364f..e1fe9de68 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -154,8 +154,8 @@ protected: private: bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; } - /// Populate m_peerAddresses with available public addresses. - void determinePublic(std::string const& _publicAddress, bool _upnp); + /// Determines and sets m_tcpPublic to publicly advertised address. + void determinePublic(NetworkPreferences const& _netPrefs); void connect(std::shared_ptr const& _p); @@ -192,7 +192,7 @@ private: NetworkPreferences m_netPrefs; ///< Network settings. /// Interface addresses (private, public) - std::vector m_ifAddresses; ///< Interface addresses. + std::set m_ifAddresses; ///< Interface addresses. int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized. @@ -222,8 +222,6 @@ private: unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. - std::set m_peerAddresses; ///< Public addresses that peers (can) know us by. - std::map> m_capabilities; ///< Each of the capabilities we support. std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index bdd1f0108..7be54d9fb 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -40,9 +40,9 @@ using namespace std; using namespace dev; using namespace dev::p2p; -std::vector Network::getInterfaceAddresses() +std::set Network::getInterfaceAddresses() { - std::vector addresses; + std::set addresses; #ifdef _WIN32 WSAData wsaData; @@ -72,7 +72,7 @@ std::vector Network::getInterfaceAddresses() char *addrStr = inet_ntoa(addr); bi::address address(bi::address::from_string(addrStr)); if (!isLocalHostAddress(address)) - addresses.push_back(address.to_v4()); + addresses.insert(address.to_v4()); } WSACleanup(); @@ -91,7 +91,7 @@ std::vector Network::getInterfaceAddresses() in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr)); if (!isLocalHostAddress(address)) - addresses.push_back(address); + addresses.insert(address); } else if (ifa->ifa_addr->sa_family == AF_INET6) { @@ -101,7 +101,7 @@ std::vector Network::getInterfaceAddresses() memcpy(&bytes[0], addr.s6_addr, 16); boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); if (!isLocalHostAddress(address)) - addresses.push_back(address); + addresses.insert(address); } } @@ -113,13 +113,39 @@ std::vector Network::getInterfaceAddresses() return std::move(addresses); } -int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort) +int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs) { int retport = -1; - for (unsigned i = 0; i < 2; ++i) + if (_netPrefs.listenIPAddress.empty()) + for (unsigned i = 0; i < 2; ++i) + { + // try to connect w/listenPort, else attempt net-allocated port + bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _netPrefs.listenPort); + try + { + _acceptor.open(endpoint.protocol()); + _acceptor.set_option(ba::socket_base::reuse_address(true)); + _acceptor.bind(endpoint); + _acceptor.listen(); + retport = _acceptor.local_endpoint().port(); + break; + } + catch (...) + { + if (i) + { + // both attempts failed + cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); + } + + // first attempt failed + _acceptor.close(); + continue; + } + } + else { - // try to connect w/listenPort, else attempt net-allocated port - bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _listenPort); + bi::tcp::endpoint endpoint(bi::address::from_string(_netPrefs.listenIPAddress), _netPrefs.listenPort); try { _acceptor.open(endpoint.protocol()); @@ -127,25 +153,18 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort _acceptor.bind(endpoint); _acceptor.listen(); retport = _acceptor.local_endpoint().port(); - break; } catch (...) { - if (i) - { - // both attempts failed - cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); - } - - // first attempt failed - _acceptor.close(); - continue; + clog(NetWarn) << "Couldn't start accepting connections on host. Failed to accept socket.\n" << boost::current_exception_diagnostic_information(); } + assert(retport == _netPrefs.listenPort); + return retport; } return retport; } -bi::tcp::endpoint Network::traverseNAT(std::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) +bi::tcp::endpoint Network::traverseNAT(std::set const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) { asserts(_listenPort != 0); diff --git a/libp2p/Network.h b/libp2p/Network.h index aeeabf329..127b5ea04 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -37,15 +37,7 @@ namespace dev 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; -}; +struct NetworkPreferences; /** * @brief Network Class @@ -55,14 +47,29 @@ class Network { public: /// @returns public and private interface addresses - static std::vector getInterfaceAddresses(); + static std::set getInterfaceAddresses(); /// Try to bind and listen on _listenPort, else attempt net-allocated port. - static int tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort); + static int tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs); /// 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::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr); + static bi::tcp::endpoint traverseNAT(std::set const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr); }; +struct NetworkPreferences +{ + // Network Preferences with unspecified Public IP + NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), listenIPAddress(i), publicIPAddress(), traverseNAT(u) {} + + // Network Preferences with intended Public IP + NetworkPreferences(std::string publicIP, unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), listenIPAddress(i), publicIPAddress(publicIP), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); } + + unsigned short listenPort = 30303; + std::string listenIPAddress; + std::string publicIPAddress; + + bool traverseNAT = true; +}; + } } From 4da7a0f4c63579169efe3b6eb67ff3d36db74556 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 26 Mar 2015 20:14:35 +0100 Subject: [PATCH 02/21] initial requirepeer --- libp2p/Host.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ libp2p/Host.h | 10 ++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 41c2fbb77..f833efbc5 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -437,6 +437,53 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short 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& _addr, unsigned short _port) +{ + auto addr = bi::address::from_string(_addr); + Node node(_n, NodeIPEndpoint(bi::udp::endpoint(addr, _port), bi::tcp::endpoint(addr, _port))); + if (_n) + { + // add or replace peer + shared_ptr p; + RecursiveGuard l(x_sessions); + if (m_peers.count(_n)) + p = m_peers[_n]; + else + { + // TODO p2p: construct peer from node + p.reset(new Peer()); + p->id = _n; + p->endpoint = NodeIPEndpoint(node.endpoint.udp, node.endpoint.tcp); + p->required = true; + m_peers[_n] = p; + } + p->endpoint.udp = node.endpoint.udp; + p->endpoint.tcp = node.endpoint.tcp; + } + else if (m_nodeTable) + { + shared_ptr t(new boost::asio::deadline_timer(m_ioService)); + m_timers.push_back(t); + + m_nodeTable->addNode(node); + t->expires_from_now(boost::posix_time::milliseconds(600)); + t->async_wait([this, _n](boost::system::error_code const& _ec) + { + if (!_ec && m_nodeTable) + if (auto n = m_nodeTable->node(_n)) + if (!m_peers.count(_n)) + { + shared_ptr p(new Peer()); + p->id = _n; + p->endpoint = n.endpoint; + p->required = true; + RecursiveGuard l(x_sessions); + m_peers[_n] = p; + } + }); + } +} + void Host::connect(std::shared_ptr const& _p) { if (!m_run) diff --git a/libp2p/Host.h b/libp2p/Host.h index 0feda364f..e27bc8855 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -70,9 +70,7 @@ private: * @brief The Host class * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. * - * @todo cleanup startPeerSession * @todo determinePublic: ipv6, udp - * @todo handle conflict if addNode/requireNode called and Node already exists w/conflicting tcp or udp port * @todo per-session keepalive/ping instead of broadcast; set ping-timeout via median-latency */ class Host: public Worker @@ -106,7 +104,13 @@ public: /// 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); + + /// Create Peer and attempt keeping peer connected. + void requirePeer(NodeId const& _node, std::string const& _addr, unsigned short _port); +// /// Note peer as no longer being required. +// void relinquishPeer(NodeId const& _node); + /// Set ideal number of peers. void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; } @@ -211,6 +215,8 @@ private: /// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer; std::map> m_peers; + + std::list> m_timers; /// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run()) /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method. From c887d5c0d23171f39bdcd0d5695b11a57e5b83de Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 26 Mar 2015 21:28:53 +0100 Subject: [PATCH 03/21] Don't create address from empty string. Use member property instead of parameter. --- libp2p/Host.cpp | 22 +++++++++++----------- libp2p/Host.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 3f2cebff2..5251fd2e6 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -287,37 +287,37 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) } } -void Host::determinePublic(NetworkPreferences const& _netPrefs) +void Host::determinePublic() { // set m_tcpPublic := listenIP (if public) > public > upnp > unspecified address. auto ifAddresses = Network::getInterfaceAddresses(); - auto laddr = bi::address::from_string(_netPrefs.listenIPAddress); + auto laddr = m_netPrefs.listenIPAddress.empty() ? bi::address() : bi::address::from_string(m_netPrefs.listenIPAddress); auto lset = !laddr.is_unspecified(); - auto paddr = bi::address::from_string(_netPrefs.publicIPAddress); + auto paddr = m_netPrefs.publicIPAddress.empty() ? bi::address() : bi::address::from_string(m_netPrefs.publicIPAddress); auto pset = !paddr.is_unspecified(); bool listenIsPublic = lset && isPublicAddress(laddr); bool publicIsHost = !lset && pset && ifAddresses.count(paddr); - bi::tcp::endpoint ep(bi::address(), _netPrefs.listenPort); - if (_netPrefs.traverseNAT && listenIsPublic) + bi::tcp::endpoint ep(bi::address(), m_netPrefs.listenPort); + if (m_netPrefs.traverseNAT && listenIsPublic) { clog(NetNote) << "Listen address set to Public address:" << laddr << ". UPnP disabled."; ep.address(laddr); } - else if (_netPrefs.traverseNAT && publicIsHost) + else if (m_netPrefs.traverseNAT && publicIsHost) { clog(NetNote) << "Public address set to Host configured address:" << paddr << ". UPnP disabled."; ep.address(paddr); } - else if (_netPrefs.traverseNAT) + else if (m_netPrefs.traverseNAT) { bi::address natIFAddr; if (lset && ifAddresses.count(laddr)) - ep = Network::traverseNAT(std::set({laddr}), _netPrefs.listenPort, natIFAddr); + ep = Network::traverseNAT(std::set({laddr}), m_netPrefs.listenPort, natIFAddr); else - ep = Network::traverseNAT(ifAddresses, _netPrefs.listenPort, natIFAddr); + ep = Network::traverseNAT(ifAddresses, m_netPrefs.listenPort, natIFAddr); if (lset && natIFAddr != laddr) // if listen address is set we use it, even if upnp returns different @@ -583,13 +583,13 @@ void Host::startedWorking() h.second->onStarting(); // try to open acceptor (todo: ipv6) - m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort); + m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs); // determine public IP, but only if we're able to listen for connections // todo: GUI when listen is unavailable in UI if (m_listenPort) { - determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); + determinePublic(); if (m_listenPort > 0) runAcceptor(); diff --git a/libp2p/Host.h b/libp2p/Host.h index e1fe9de68..fe0b9a148 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -155,7 +155,7 @@ private: bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; } /// Determines and sets m_tcpPublic to publicly advertised address. - void determinePublic(NetworkPreferences const& _netPrefs); + void determinePublic(); void connect(std::shared_ptr const& _p); From 11d2446247529da3182586ce9f520cd9c54ea5d3 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 27 Mar 2015 07:50:43 +0100 Subject: [PATCH 04/21] api cleanup. connect peer when required. --- libp2p/Host.cpp | 53 ++++++++++++++++++++++++++----------------------- libp2p/Host.h | 10 +++++++--- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 7c8bed71a..87922f016 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -423,28 +423,39 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short 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& _addr, unsigned short _port) +void Host::relinquishPeer(NodeId const& _node) { - auto addr = bi::address::from_string(_addr); - Node node(_n, NodeIPEndpoint(bi::udp::endpoint(addr, _port), bi::tcp::endpoint(addr, _port))); + Guard l(x_requiredPeers); + if (m_requiredPeers.count(_node)) + m_requiredPeers.erase(_node); +} + +void Host::requirePeer(NodeId const& _n, std::string const& _udpAddr, unsigned short _udpPort, std::string const& _tcpAddr, unsigned short _tcpPort) +{ + auto naddr = bi::address::from_string(_udpAddr); + auto paddr = _tcpAddr.empty() ? naddr : bi::address::from_string(_tcpAddr); + auto udp = bi::udp::endpoint(naddr, _udpPort); + auto tcp = bi::tcp::endpoint(paddr, _tcpPort ? _tcpPort : _udpPort); + Node node(_n, NodeIPEndpoint(udp, tcp)); if (_n) { // add or replace peer shared_ptr p; - RecursiveGuard l(x_sessions); - if (m_peers.count(_n)) - p = m_peers[_n]; - else { - // TODO p2p: construct peer from node - p.reset(new Peer()); - p->id = _n; - p->endpoint = NodeIPEndpoint(node.endpoint.udp, node.endpoint.tcp); - p->required = true; - m_peers[_n] = p; + RecursiveGuard l(x_sessions); + if (m_peers.count(_n)) + p = m_peers[_n]; + else + { + p.reset(new Peer()); + p->id = _n; + p->required = true; + m_peers[_n] = p; + } + p->endpoint.udp = node.endpoint.udp; + p->endpoint.tcp = node.endpoint.tcp; } - p->endpoint.udp = node.endpoint.udp; - p->endpoint.tcp = node.endpoint.tcp; + connect(p); } else if (m_nodeTable) { @@ -456,16 +467,8 @@ void Host::requirePeer(NodeId const& _n, std::string const& _addr, unsigned shor t->async_wait([this, _n](boost::system::error_code const& _ec) { if (!_ec && m_nodeTable) - if (auto n = m_nodeTable->node(_n)) - if (!m_peers.count(_n)) - { - shared_ptr p(new Peer()); - p->id = _n; - p->endpoint = n.endpoint; - p->required = true; - RecursiveGuard l(x_sessions); - m_peers[_n] = p; - } + 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()); }); } } diff --git a/libp2p/Host.h b/libp2p/Host.h index bb16d079e..7a18380c3 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -106,10 +106,10 @@ public: void addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort); /// Create Peer and attempt keeping peer connected. - void requirePeer(NodeId const& _node, std::string const& _addr, unsigned short _port); + void requirePeer(NodeId const& _node, std::string const& _udpAddr, unsigned short _udpPort, std::string const& _tcpAddr = "", unsigned short _tcpPort = 0); -// /// Note peer as no longer being required. -// void relinquishPeer(NodeId const& _node); + /// Note peer as no longer being required. + void relinquishPeer(NodeId const& _node); /// Set ideal number of peers. void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; } @@ -216,6 +216,10 @@ private: /// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer; std::map> m_peers; + /// Peers we try to connect regardless of p2p network. + std::set m_requiredPeers; + Mutex x_requiredPeers; + std::list> m_timers; /// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run()) From 3c1ae84557dbaf07261dae46bca58f849b3ae7db Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 27 Mar 2015 18:14:55 +0100 Subject: [PATCH 05/21] inc failedattempt for handshake --- libp2p/Host.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 87922f016..3835b9504 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -521,6 +521,9 @@ void Host::connect(std::shared_ptr const& _p) Guard l(x_connecting); m_connecting.push_back(handshake); } + + // preempt setting failedAttempts; this value is cleared upon success + _p->m_failedAttempts++; handshake->start(); } @@ -647,6 +650,7 @@ void Host::startedWorking() else clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "Listen port is invalid or unavailable. Node Table using default port (30303)."; + // this doesn't work unless local-networking is enabled because the port is -1 m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort() > 0 ? listenPort() : 30303)); m_nodeTable->setEventHandler(new HostNodeTableHandler(*this)); restoreNetwork(&m_restoreNetwork); From bb261e553a281d4b96f34fa3d55faf3e6ce485c5 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 27 Mar 2015 20:49:05 +0100 Subject: [PATCH 06/21] update CLI and AZ UI for replacing local-networking with explicit --listen-ip --- alethzero/Main.ui | 73 +++++++++++++++++++++++++------------------ alethzero/MainWin.cpp | 13 +++++--- eth/main.cpp | 19 +++++------ libp2p/Common.cpp | 6 ++-- libp2p/Network.h | 14 +++++---- libp2p/Peer.h | 1 - neth/main.cpp | 24 ++++++++------ test/peer.cpp | 6 ++-- 8 files changed, 89 insertions(+), 67 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 34f240fbf..99fea901c 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -118,7 +118,7 @@ 0 0 1617 - 24 + 22 @@ -135,7 +135,6 @@ - @@ -284,6 +283,26 @@ + + + + &Listen on + + + port + + + + + + + 1 + + + 5 + + + @@ -297,8 +316,18 @@ + + + + &Client Name + + + clientName + + + - + @@ -310,13 +339,10 @@ - - - - &Listen on - - - port + + + + Anonymous @@ -330,30 +356,17 @@ - - - - 1 - - - 5 - - - - - + + - Anonymous + Automatic - - + + - &Client Name - - - clientName + Public IP @@ -1694,7 +1707,7 @@ font-size: 14pt tabWidget urlEdit idealPeers - forceAddress + listenIP port clientName transactionQueue diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 36b6176f4..1ae139cce 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -251,7 +251,8 @@ void Main::addNewId(QString _ids) NetworkPreferences Main::netPrefs() const { - return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked()); + 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()); } void Main::onKeysChanged() @@ -675,9 +676,10 @@ void Main::writeSettings() } s.setValue("upnp", ui->upnp->isChecked()); - s.setValue("forceAddress", ui->forceAddress->text()); +#warning fixme +// s.setValue("forceAddress", ui->forceAddress->text()); s.setValue("usePast", ui->usePast->isChecked()); - s.setValue("localNetworking", ui->localNetworking->isChecked()); +// s.setValue("localNetworking", ui->localNetworking->isChecked()); s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked()); s.setValue("natSpec", ui->natSpec->isChecked()); @@ -744,9 +746,10 @@ void Main::readSettings(bool _skipGeometry) } ui->upnp->setChecked(s.value("upnp", true).toBool()); - ui->forceAddress->setText(s.value("forceAddress", "").toString()); +#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->localNetworking->setChecked(s.value("localNetworking", true).toBool()); ui->forceMining->setChecked(s.value("forceMining", false).toBool()); on_forceMining_triggered(); ui->paranoia->setChecked(s.value("paranoia", false).toBool()); diff --git a/eth/main.cpp b/eth/main.cpp index e0cf76193..abac6462c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -121,8 +121,9 @@ void help() << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl #endif << " -K,--kill-blockchain First kill the blockchain." << endl - << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl - << " -L,--local-networking Use peers whose addresses are local." << endl + << " --listen-ip Listen on the given port for incoming connections (default: 30303)." << endl + << " -l,--listen Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl + << " -u,--public-ip Force public ip to given (default: auto)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl << " -n,--upnp Use upnp for NAT (default: on)." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl @@ -131,7 +132,6 @@ void help() << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl << " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl - << " -u,--public-ip Force public ip to given (default; auto)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl @@ -199,7 +199,9 @@ enum class NodeMode int main(int argc, char** argv) { + string listenIP; unsigned short listenPort = 30303; + string publicIP; string remoteHost; unsigned short remotePort = 30303; string dbPath; @@ -211,10 +213,8 @@ int main(int argc, char** argv) #if ETH_JSONRPC int jsonrpc = -1; #endif - string publicIP; bool bootstrap = false; bool upnp = true; - bool useLocal = false; bool forceMining = false; bool killChain = false; bool jit = false; @@ -250,7 +250,9 @@ int main(int argc, char** argv) for (int i = 1; i < argc; ++i) { string arg = argv[i]; - if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) + if (arg == "--listen-ip" && i + 1 < argc) + listenIP = argv[++i]; + else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) listenPort = (short)atoi(argv[++i]); else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc) publicIP = argv[++i]; @@ -271,8 +273,6 @@ int main(int argc, char** argv) return -1; } } - else if (arg == "-L" || arg == "--local-networking") - useLocal = true; else if (arg == "-K" || arg == "--kill-blockchain") killChain = true; else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) @@ -421,7 +421,8 @@ int main(int argc, char** argv) StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); - NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); +#warning fixme + NetworkPreferences netPrefs(listenPort); 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( diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp index b995723c3..7051322a9 100644 --- a/libp2p/Common.cpp +++ b/libp2p/Common.cpp @@ -28,7 +28,7 @@ const unsigned dev::p2p::c_protocolVersion = 3; bool p2p::isPublicAddress(std::string const& _addressToCheck) { - return isPublicAddress(bi::address::from_string(_addressToCheck)); + return _addressToCheck.empty() ? false : isPublicAddress(bi::address::from_string(_addressToCheck)); } bool p2p::isPublicAddress(bi::address const& _addressToCheck) @@ -67,7 +67,7 @@ bool p2p::isPrivateAddress(bi::address const& _addressToCheck) bool p2p::isPrivateAddress(std::string const& _addressToCheck) { - return isPrivateAddress(bi::address::from_string(_addressToCheck)); + return _addressToCheck.empty() ? false : isPrivateAddress(bi::address::from_string(_addressToCheck)); } // Helper function to determine if an address is localhost @@ -86,7 +86,7 @@ bool p2p::isLocalHostAddress(bi::address const& _addressToCheck) bool p2p::isLocalHostAddress(std::string const& _addressToCheck) { - return isLocalHostAddress(bi::address::from_string(_addressToCheck)); + return _addressToCheck.empty() ? false : isLocalHostAddress(bi::address::from_string(_addressToCheck)); } std::string p2p::reasonOf(DisconnectReason _r) diff --git a/libp2p/Network.h b/libp2p/Network.h index 127b5ea04..0e3a08398 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -58,16 +58,18 @@ public: struct NetworkPreferences { - // Network Preferences with unspecified Public IP - NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), listenIPAddress(i), publicIPAddress(), traverseNAT(u) {} + // Default Network Preferences + NetworkPreferences(unsigned short lp = 30303): listenPort(lp) {} + + // Network Preferences with specific Listen IP + NetworkPreferences(std::string l, unsigned short lp = 30303, bool u = true): publicIPAddress(), listenIPAddress(l), listenPort(lp), traverseNAT(u) {} // Network Preferences with intended Public IP - NetworkPreferences(std::string publicIP, unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), listenIPAddress(i), publicIPAddress(publicIP), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); } + NetworkPreferences(std::string publicIP, std::string l = std::string(), unsigned short lp = 30303, bool u = true): publicIPAddress(publicIP), listenIPAddress(l), listenPort(lp), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); } - unsigned short listenPort = 30303; - std::string listenIPAddress; std::string publicIPAddress; - + std::string listenIPAddress; + unsigned short listenPort = 30303; bool traverseNAT = true; }; diff --git a/libp2p/Peer.h b/libp2p/Peer.h index 8774b6578..bfa2eaeb6 100644 --- a/libp2p/Peer.h +++ b/libp2p/Peer.h @@ -47,7 +47,6 @@ namespace p2p * those peers. Modifying these properties via a storage backend alleviates * Host of the responsibility. (&& remove save/restoreNetwork) * @todo reimplement recording of historical session information on per-transport basis - * @todo rebuild nodetable when localNetworking is enabled/disabled * @todo move attributes into protected */ class Peer: public Node diff --git a/neth/main.cpp b/neth/main.cpp index a844da92d..cd0944425 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -84,8 +84,9 @@ void help() << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl #endif << " -K,--kill-blockchain First kill the blockchain." << endl - << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl - << " -L,--local-networking Use peers whose addresses are local." << endl + << " --listen-ip Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl + << " -l,--listen Listen on the given port for incoming connections (default: 30303)." << endl + << " -u,--public-ip Force public ip to given (default; auto)." << endl << " -m,--mining Enable mining (default: off)" << endl << " -n,--upnp Use upnp for NAT (default: on)." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl @@ -94,7 +95,6 @@ void help() << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl << " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl - << " -u,--public-ip Force public ip to given (default; auto)." << endl << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl << " -x,--peers Attempt to connect to given number of peers (default: 5)." << endl << " -V,--version Show the version and exit." << endl @@ -321,7 +321,9 @@ enum class NodeMode int main(int argc, char** argv) { + string listenIP; unsigned short listenPort = 30303; + string publicIP; string remoteHost; unsigned short remotePort = 30303; string dbPath; @@ -332,10 +334,8 @@ int main(int argc, char** argv) #if ETH_JSONRPC int jsonrpc = 8080; #endif - string publicIP; bool bootstrap = false; bool upnp = true; - bool useLocal = false; bool forceMining = false; bool killChain = false; bool jit = false; @@ -371,7 +371,9 @@ int main(int argc, char** argv) for (int i = 1; i < argc; ++i) { string arg = argv[i]; - if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) + if (arg == "--listen-ip" && i + 1 < argc) + listenIP = argv[++i]; + else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) listenPort = (short)atoi(argv[++i]); else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc) publicIP = argv[++i]; @@ -392,8 +394,6 @@ int main(int argc, char** argv) return -1; } } - else if (arg == "-L" || arg == "--local-networking") - useLocal = true; else if (arg == "-K" || arg == "--kill-blockchain") killChain = true; else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) @@ -535,6 +535,8 @@ int main(int argc, char** argv) } } + + if (!clientName.empty()) clientName += "/"; @@ -542,7 +544,7 @@ int main(int argc, char** argv) StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); - NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); + NetworkPreferences netPrefs(publicIP, listenIP ,listenPort, upnp); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); std::string clientImplString = "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); dev::WebThreeDirect web3( @@ -687,7 +689,9 @@ int main(int argc, char** argv) { unsigned port; iss >> port; - web3.setNetworkPreferences(NetworkPreferences((short)port, publicIP, upnp)); + if (port) + netPrefs.listenPort = port; + web3.setNetworkPreferences(netPrefs); web3.startNetwork(); } else if (cmd == "connect") diff --git a/test/peer.cpp b/test/peer.cpp index bfb4680d3..b90fc7404 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -35,8 +35,8 @@ BOOST_AUTO_TEST_CASE(host) auto oldLogVerbosity = g_logVerbosity; g_logVerbosity = 10; - NetworkPreferences host1prefs(30301, "127.0.0.1", false, true); - NetworkPreferences host2prefs(30302, "127.0.0.1", false, true); + NetworkPreferences host1prefs("127.0.0.1", 30301, false); + NetworkPreferences host2prefs("127.0.0.1", 30302, false); Host host1("Test", host1prefs); host1.start(); @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(save_nodes) std::list hosts; for (auto i:{0,1,2,3,4,5}) { - Host* h = new Host("Test", NetworkPreferences(30300 + i, "127.0.0.1", false, true)); + Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 30300 + i, false)); h->setIdealPeerCount(10); // starting host is required so listenport is available h->start(); From 93593a8751b0d05f45828a7d7f8a0013e76de78d Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 27 Mar 2015 22:47:19 +0100 Subject: [PATCH 07/21] updae legacy codepath --- libp2p/Session.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index d7bfca34e..65dedb302 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -216,12 +216,8 @@ bool Session::interpret(PacketType _t, RLP const& _r) NodeId id = _r[i][2].toHash(); clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")"; -// clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")" << isPrivateAddress(peerAddress) << this->id().abridged() << isPrivateAddress(endpoint().address()) << m_server->m_peers.count(id) << (m_server->m_peers.count(id) ? isPrivateAddress(m_server->m_peers.at(id)->address.address()) : -1); - // todo: draft spec: ignore if dist(us,item) - dist(us,them) > 1 - - // TODO: isPrivate - if (!m_server->m_netPrefs.localNetworking && isPrivateAddress(peerAddress)) + if (!isPublicAddress(peerAddress)) goto CONTINUE; // Private address. Ignore. if (!id) From 29f40bff0f0e4b7aa3a229660c535dc30dfe190f Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 28 Mar 2015 09:39:04 +0100 Subject: [PATCH 08/21] makePeer and support setting listen IP. --- alethzero/CMakeLists.txt | 5 +- alethzero/Connect.cpp | 62 ++++++++++++++++++++ alethzero/Connect.h | 50 ++++++++++++++++ alethzero/Connect.ui | 123 +++++++++++++++++++++++++++++++++++++++ alethzero/Main.ui | 51 ++++++++-------- alethzero/MainWin.cpp | 53 ++++++++++------- alethzero/MainWin.h | 3 + eth/main.cpp | 9 ++- libp2p/Common.cpp | 1 + libp2p/Common.h | 3 +- libp2p/Host.cpp | 51 ++++++---------- libp2p/Host.h | 10 +++- libp2p/Network.cpp | 25 ++++++++ libp2p/Network.h | 3 + libp2p/NodeTable.cpp | 27 +++------ libp2p/NodeTable.h | 2 +- libp2p/Session.cpp | 2 +- libwebthree/WebThree.cpp | 16 +++-- libwebthree/WebThree.h | 42 +++++++++---- neth/main.cpp | 6 +- test/peer.cpp | 8 +-- 21 files changed, 414 insertions(+), 138 deletions(-) create mode 100644 alethzero/Connect.cpp create mode 100644 alethzero/Connect.h create mode 100644 alethzero/Connect.ui diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 49c847a16..c81c86222 100644 --- a/alethzero/CMakeLists.txt +++ b/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) @@ -32,8 +33,8 @@ 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 + ICON alethzero + UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui WIN_RESOURCES alethzero.rc ) diff --git a/alethzero/Connect.cpp b/alethzero/Connect.cpp new file mode 100644 index 000000000..076ebafe0 --- /dev/null +++ b/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 . +*/ +/** @file Connect.cpp + * @author Alex Leverington + * @date 2015 + */ + +#include "Connect.h" + +#include +#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(); +} diff --git a/alethzero/Connect.h b/alethzero/Connect.h new file mode 100644 index 000000000..d8059acd4 --- /dev/null +++ b/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 . +*/ +/** @file Connect.h + * @author Alex Leverington + * @date 2015 + */ + +#pragma once + +#include +#include + +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; +}; diff --git a/alethzero/Connect.ui b/alethzero/Connect.ui new file mode 100644 index 000000000..9a0522e5f --- /dev/null +++ b/alethzero/Connect.ui @@ -0,0 +1,123 @@ + + + Connect + + + Qt::WindowModal + + + + 0 + 0 + 343 + 178 + + + + + 0 + 0 + + + + + 343 + 178 + + + + Connect to Peer + + + true + + + + + + + + + 311 + 0 + + + + true + + + + + + + Node Id + + + + + + + Required (Always Connect to this Peer) + + + false + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + Enter a peer to which a connection may be made: + + + + + + + + + buttonBox + accepted() + Connect + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Connect + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 99fea901c..b59c9ce2d 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -134,7 +134,7 @@ - + @@ -283,7 +283,7 @@ - + &Listen on @@ -303,7 +303,7 @@ - + 1024 @@ -316,17 +316,7 @@ - - - - &Client Name - - - clientName - - - - + @@ -339,13 +329,6 @@ - - - - Anonymous - - - @@ -356,20 +339,37 @@ - + Automatic - + Public IP + + + + &Client Name + + + clientName + + + + + + + Anonymous + + + @@ -1456,12 +1456,12 @@ font-size: 14pt Show &Anonymous Accounts - + true - Use &Past Peers + &Drop Past Peers @@ -1709,7 +1709,6 @@ font-size: 14pt idealPeers listenIP port - clientName transactionQueue pendingInfo blockChainFilter diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1ae139cce..4e5ed49a3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -28,6 +28,7 @@ //pragma GCC diagnostic ignored "-Werror=pedantic" #include #include +#include #include #include #include @@ -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 diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index ba89b455a..fccbc855d 100644 --- a/alethzero/MainWin.h +++ b/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 m_dappHost; DappLoader* m_dappLoader; QWebEnginePage* m_webPage; + + Connect m_connect; }; diff --git a/eth/main.cpp b/eth/main.cpp index abac6462c..206a6df57 100644 --- a/eth/main.cpp +++ b/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 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") { diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp index 7051322a9..95c96e346 100644 --- a/libp2p/Common.cpp +++ b/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) { diff --git a/libp2p/Common.h b/libp2p/Common.h index 3303c9c07..c9aee9a0e 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -50,7 +50,8 @@ namespace p2p /// Peer network protocol version. extern const unsigned c_protocolVersion; - +extern const unsigned c_defaultIPPort; + using NodeId = h512; bool isPrivateAddress(bi::address const& _addressToCheck); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 3835b9504..ac9e9671b 100644 --- a/libp2p/Host.cpp +++ b/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) @@ -403,37 +399,14 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short cwarn << "Private port being recorded - setting to 0"; _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 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() == dev::p2p::c_protocolVersion) diff --git a/libp2p/Host.h b/libp2p/Host.h index 7a18380c3..0df24ca79 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -94,6 +94,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 std::shared_ptr registerCapability(T* _t) { _t->m_host = this; auto ret = std::shared_ptr(_t); m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = ret; return ret; } @@ -103,10 +106,10 @@ public: template std::shared_ptr cap() const { try { return std::static_pointer_cast(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; }; } diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 7be54d9fb..42208ad60 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -206,3 +207,27 @@ bi::tcp::endpoint Network::traverseNAT(std::set const& _ifAddresses return upnpep; } + +bi::tcp::endpoint Network::resolveHost(ba::io_service& _ioService, string const& _addr) +{ + vector 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; +} + diff --git a/libp2p/Network.h b/libp2p/Network.h index 0e3a08398..46034aef3 100644 --- a/libp2p/Network.h +++ b/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 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 diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index c230c5441..7b9852672 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -101,6 +101,7 @@ shared_ptr NodeTable::addNode(Node const& _node) shared_ptr 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); } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 6a167930d..9ff28b7f1 100644 --- a/libp2p/NodeTable.h +++ b/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 { diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 65dedb302..dac588149 100644 --- a/libp2p/Session.cpp +++ b/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:; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 6c6414741..b2c6765b5 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -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()); +} + + diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 242639af4..adb691753 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -63,9 +63,12 @@ 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; @@ -137,22 +140,37 @@ 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(); } diff --git a/neth/main.cpp b/neth/main.cpp index cd0944425..4d9870b44 100644 --- a/neth/main.cpp +++ b/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") { diff --git a/test/peer.cpp b/test/peer.cpp index b90fc7404..48431504f 100644 --- a/test/peer.cpp +++ b/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)); From 549ab8860918cebecb215aa955c13cff95a5b6ec Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 28 Mar 2015 10:06:04 +0100 Subject: [PATCH 09/21] garbage collect timers --- libp2p/Host.cpp | 7 +++++++ libp2p/Host.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index ac9e9671b..7c34b31f5 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -560,6 +560,13 @@ void Host::run(boost::system::error_code const&) Guard l(x_connecting); m_connecting.remove_if([](std::weak_ptr h){ return h.lock(); }); } + { + Guard l(x_timers); + m_timers.remove_if([](std::shared_ptr t) + { + return t->expires_from_now().total_milliseconds() > 0; + }); + } for (auto p: m_sessions) if (auto pp = p.second.lock()) diff --git a/libp2p/Host.h b/libp2p/Host.h index 0df24ca79..deb84a4ff 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -223,7 +223,9 @@ private: std::set m_requiredPeers; Mutex x_requiredPeers; + /// Deadline timers used for isolated network events. GC'd by run. std::list> m_timers; + Mutex x_timers; /// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run()) /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method. From b05546fef645d5b73b882df49cf2c086415d7ebe Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 28 Mar 2015 10:07:13 +0100 Subject: [PATCH 10/21] dealloc basic timers first --- libp2p/Host.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libp2p/Host.h b/libp2p/Host.h index deb84a4ff..b58939eb1 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -222,10 +222,6 @@ private: /// Peers we try to connect regardless of p2p network. std::set m_requiredPeers; Mutex x_requiredPeers; - - /// Deadline timers used for isolated network events. GC'd by run. - std::list> m_timers; - Mutex x_timers; /// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run()) /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method. @@ -238,6 +234,10 @@ private: unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. std::map> m_capabilities; ///< Each of the capabilities we support. + + /// Deadline timers used for isolated network events. GC'd by run. + std::list> m_timers; + Mutex x_timers; std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. bool m_accepting = false; From 88fa4830554a8afe3db23b6bb31c25fedc67af5b Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 28 Mar 2015 10:25:13 +0100 Subject: [PATCH 11/21] fix neth. fix issue w/udp listening to 30303. --- libp2p/Host.cpp | 9 ++++----- libp2p/Host.h | 4 ++-- libp2p/Network.h | 34 ++++++++++++++++------------------ neth/main.cpp | 2 +- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 7c34b31f5..2354ed5d3 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -316,12 +316,12 @@ void Host::determinePublic() ep = Network::traverseNAT(ifAddresses, m_netPrefs.listenPort, natIFAddr); if (lset && natIFAddr != laddr) - // if listen address is set we use it, even if upnp returns different + // if listen address is set, Host will use it, even if upnp returns different clog(NetWarn) << "Listen address" << laddr << "differs from local address" << natIFAddr << "returned by UPnP!"; if (pset && ep.address() != paddr) { - // if public address is set we advertise it, even if upnp returns different + // if public address is set, Host will advertise it, even if upnp returns different clog(NetWarn) << "Specified public address" << paddr << "differs from external address" << ep.address() << "returned by UPnP!"; ep.address(paddr); } @@ -635,10 +635,9 @@ void Host::startedWorking() runAcceptor(); } else - clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "Listen port is invalid or unavailable. Node Table using default port (30303)."; + clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "TCP Listen port is invalid or unavailable."; - // this doesn't work unless local-networking is enabled because the port is -1 - m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort() > 0 ? listenPort() : 30303)); + m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort())); m_nodeTable->setEventHandler(new HostNodeTableHandler(*this)); restoreNetwork(&m_restoreNetwork); diff --git a/libp2p/Host.h b/libp2p/Host.h index b58939eb1..66ad373e3 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -124,10 +124,10 @@ public: size_t peerCount() const; /// Get the address we're listening on currently. - std::string listenAddress() const { return m_tcpPublic.address().to_string(); } + std::string listenAddress() const { return m_netPrefs.listenIPAddress.empty() ? "0.0.0.0" : m_netPrefs.listenIPAddress; } /// Get the port we're listening on currently. - unsigned short listenPort() const { return m_tcpPublic.port(); } + unsigned short listenPort() const { return m_netPrefs.listenPort; } /// Serialise the set of known peers. bytes saveNetwork() const; diff --git a/libp2p/Network.h b/libp2p/Network.h index 46034aef3..5f5ebc868 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -37,7 +37,22 @@ namespace dev namespace p2p { -struct NetworkPreferences; +struct NetworkPreferences +{ + // Default Network Preferences + NetworkPreferences(unsigned short lp = 30303): listenPort(lp) {} + + // Network Preferences with specific Listen IP + NetworkPreferences(std::string l, unsigned short lp = 30303, bool u = true): publicIPAddress(), listenIPAddress(l), listenPort(lp), traverseNAT(u) {} + + // Network Preferences with intended Public IP + NetworkPreferences(std::string publicIP, std::string l = std::string(), unsigned short lp = 30303, bool u = true): publicIPAddress(publicIP), listenIPAddress(l), listenPort(lp), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); } + + std::string publicIPAddress; + std::string listenIPAddress; + unsigned short listenPort = 30303; + bool traverseNAT = true; +}; /** * @brief Network Class @@ -58,23 +73,6 @@ public: /// 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 -{ - // Default Network Preferences - NetworkPreferences(unsigned short lp = 30303): listenPort(lp) {} - - // Network Preferences with specific Listen IP - NetworkPreferences(std::string l, unsigned short lp = 30303, bool u = true): publicIPAddress(), listenIPAddress(l), listenPort(lp), traverseNAT(u) {} - - // Network Preferences with intended Public IP - NetworkPreferences(std::string publicIP, std::string l = std::string(), unsigned short lp = 30303, bool u = true): publicIPAddress(publicIP), listenIPAddress(l), listenPort(lp), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); } - - std::string publicIPAddress; - std::string listenIPAddress; - unsigned short listenPort = 30303; - bool traverseNAT = true; -}; } } diff --git a/neth/main.cpp b/neth/main.cpp index 4d9870b44..e7dde3cc6 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -544,7 +544,7 @@ int main(int argc, char** argv) StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); - NetworkPreferences netPrefs(publicIP, listenIP ,listenPort, upnp); + 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 = "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); dev::WebThreeDirect web3( From 4e62b874e8884aa287e4988d625642a031c13d6e Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 28 Mar 2015 10:37:33 +0100 Subject: [PATCH 12/21] fix dialogue. hard-code localhost address so ipv6 address isn't resolved. --- alethzero/Connect.cpp | 5 +++-- alethzero/MainWin.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/alethzero/Connect.cpp b/alethzero/Connect.cpp index 076ebafe0..cf19f83b8 100644 --- a/alethzero/Connect.cpp +++ b/alethzero/Connect.cpp @@ -28,7 +28,7 @@ Connect::Connect(QWidget *parent) : QDialog(parent), ui(new Ui::Connect) { - reset(); + ui->setupUi(this); } Connect::~Connect() @@ -43,7 +43,8 @@ void Connect::setEnvironment(QStringList const& _nodes) void Connect::reset() { - ui->setupUi(this); + ui->nodeId->clear(); + ui->required->setChecked(false); } QString Connect::host() diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4e5ed49a3..2b0750d46 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -142,7 +142,7 @@ Main::Main(QWidget *parent) : #endif #if ETH_DEBUG - m_servers.append("localhost:30300"); + m_servers.append("127.0.0.1:30300"); #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); From b3393ffcbadbbb985744721a9c8d3bde1ac7af0e Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 28 Mar 2015 20:40:03 +0100 Subject: [PATCH 13/21] style --- libp2p/Host.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 2354ed5d3..cc0d75fdb 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -400,7 +400,8 @@ void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short _tcpPeerPort = 0; } - if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(_addr, _udpNodePort), bi::tcp::endpoint(_addr, _tcpPeerPort)))); + 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, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr, unsigned short _tcpPort) From 45c3bea8f13fdbfa3a42c95d42f8d15983b4c3f6 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 28 Mar 2015 23:54:05 +0100 Subject: [PATCH 14/21] prevent exception when invalid IP entered into listen-ip or public-ip fields in AZ --- alethzero/MainWin.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2b0750d46..eb09d4991 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -252,11 +252,30 @@ void Main::addNewId(QString _ids) NetworkPreferences Main::netPrefs() const { + auto listenip = ui->listenIP->text().toStdString(); + try + { + listenip = bi::address::from_string(listenip).to_string(); + } + catch (...) + { + listenip = ""; + } + auto publicip = ui->forcePublicIP->text().toStdString(); + try + { + publicip = bi::address::from_string(publicip).to_string(); + } + catch (...) + { + publicip = ""; + } + 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()); + return NetworkPreferences(listenip, ui->port->value(), ui->upnp->isChecked()); } void Main::onKeysChanged() From 521bf5b384f81c74c3166856d8afc833eafe002f Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 29 Mar 2015 22:10:34 +0200 Subject: [PATCH 15/21] style --- alethzero/Connect.cpp | 30 +++++++++++++++--------------- alethzero/Connect.h | 41 +++++++++++++++++++++-------------------- alethzero/MainWin.cpp | 29 ++++++++++++++--------------- libp2p/NodeTable.cpp | 4 ++-- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/alethzero/Connect.cpp b/alethzero/Connect.cpp index cf19f83b8..32fa74f38 100644 --- a/alethzero/Connect.cpp +++ b/alethzero/Connect.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file Connect.cpp * @author Alex Leverington @@ -25,15 +25,15 @@ #include "ui_Connect.h" Connect::Connect(QWidget *parent) : - QDialog(parent), - ui(new Ui::Connect) + QDialog(parent), + ui(new Ui::Connect) { - ui->setupUi(this); + ui->setupUi(this); } Connect::~Connect() { - delete ui; + delete ui; } void Connect::setEnvironment(QStringList const& _nodes) diff --git a/alethzero/Connect.h b/alethzero/Connect.h index d8059acd4..89b25617c 100644 --- a/alethzero/Connect.h +++ b/alethzero/Connect.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file Connect.h * @author Alex Leverington @@ -29,22 +29,23 @@ namespace dev { namespace p2p { class Host; } } class Connect : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit Connect(QWidget *parent = 0); - ~Connect(); + explicit Connect(QWidget* _parent = 0); + ~Connect(); - void setEnvironment(QStringList const& _nodes); - + void setEnvironment(QStringList const& _nodes); + + /// clear dialogue inputs void reset(); + + // Form field values: QString host(); - QString nodeId(); - bool required(); - + private: - Ui::Connect *ui; + Ui::Connect* ui; }; diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index eb09d4991..712318442 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -252,30 +252,30 @@ void Main::addNewId(QString _ids) NetworkPreferences Main::netPrefs() const { - auto listenip = ui->listenIP->text().toStdString(); + auto listenIP = ui->listenIP->text().toStdString(); try { - listenip = bi::address::from_string(listenip).to_string(); + listenIP = bi::address::from_string(listenIP).to_string(); } catch (...) { - listenip = ""; + listenIP = ""; } - auto publicip = ui->forcePublicIP->text().toStdString(); + auto publicIP = ui->forcePublicIP->text().toStdString(); try { - publicip = bi::address::from_string(publicip).to_string(); + publicIP = bi::address::from_string(publicIP).to_string(); } catch (...) { - publicip = ""; + publicIP = ""; } - if (isPublicAddress(publicip)) - return NetworkPreferences(publicip, ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked()); + if (isPublicAddress(publicIP)) + return NetworkPreferences(publicIP, ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked()); else - return NetworkPreferences(listenip, ui->port->value(), ui->upnp->isChecked()); + return NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked()); } void Main::onKeysChanged() @@ -1790,21 +1790,20 @@ void Main::on_connect_triggered() if (m_connect.exec() == QDialog::Accepted) { bool required = m_connect.required(); - string host(m_connect.host().toUtf8().constData()); - NodeId nodeid; + string host(m_connect.host().toStdString()); + NodeId nodeID; try { - string nstr(m_connect.nodeId().toUtf8().constData()); - nodeid = NodeId(fromHex(nstr)); + nodeID = NodeId(fromHex(m_connect.nodeId().toStdString())); } catch (BadHexCharacter()) {} m_connect.reset(); if (required) - web3()->requirePeer(nodeid, host); + web3()->requirePeer(nodeID, host); else - web3()->addNode(nodeid, host); + web3()->addNode(nodeID, host); } } diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 7b9852672..407b99942 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -555,8 +555,8 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) if (connected) { 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)); + 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); } From 55986db3774419a410f0c4c9b9a832d50b484040 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 29 Mar 2015 22:11:10 +0200 Subject: [PATCH 16/21] synchronous resolver --- libp2p/Network.cpp | 10 +++++++--- libp2p/Network.h | 2 +- libwebthree/WebThree.h | 9 +++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 42208ad60..61028d458 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -208,8 +208,10 @@ bi::tcp::endpoint Network::traverseNAT(std::set const& _ifAddresses return upnpep; } -bi::tcp::endpoint Network::resolveHost(ba::io_service& _ioService, string const& _addr) +bi::tcp::endpoint Network::resolveHost(string const& _addr) { + static boost::asio::io_service s_resolverIoService; + vector split; boost::split(split, _addr, boost::is_any_of(":")); unsigned port = split.size() > 1 ? stoi(split[1]) : c_defaultIPPort; @@ -223,9 +225,11 @@ bi::tcp::endpoint Network::resolveHost(ba::io_service& _ioService, string const& { boost::system::error_code ec; // resolve returns an iterator (host can resolve to multiple addresses) - bi::tcp::resolver r(_ioService); + bi::tcp::resolver r(s_resolverIoService); auto it = r.resolve({split[0], toString(port)}, ec); - if (!ec) + if (ec) + clog(NetWarn) << "Error resolving host address " << _addr << ":" << ec.message(); + else ep = *it; } return ep; diff --git a/libp2p/Network.h b/libp2p/Network.h index 5f5ebc868..4259511b5 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -71,7 +71,7 @@ public: static bi::tcp::endpoint traverseNAT(std::set 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); + static bi::tcp::endpoint resolveHost(std::string const& _host); }; } diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index adb691753..a0e5cc666 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -145,7 +145,7 @@ public: 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)); } + void addNode(p2p::NodeId const& _node, std::string const& _hostString) { addNode(_node, p2p::Network::resolveHost(_hostString)); } /// Add node to connect to. void addNode(bi::tcp::endpoint const& _endpoint) { addNode(p2p::NodeId(), _endpoint); } @@ -157,11 +157,8 @@ public: 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(); } - + void requirePeer(p2p::NodeId const& _node, std::string const& _hostString) { requirePeer(_node, p2p::Network::resolveHost(_hostString)); } + /// Save peers dev::bytes saveNetwork() override; From 86092b27ed266de9e820ebbc76316e1d964bc21e Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 29 Mar 2015 22:24:05 +0200 Subject: [PATCH 17/21] remove unused method --- libp2p/Host.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libp2p/Host.h b/libp2p/Host.h index 66ad373e3..c161f8437 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -94,9 +94,6 @@ 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 std::shared_ptr registerCapability(T* _t) { _t->m_host = this; auto ret = std::shared_ptr(_t); m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = ret; return ret; } From 8568370a4924cf8daadce514303d1b0e21a38ef9 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 29 Mar 2015 22:38:28 +0200 Subject: [PATCH 18/21] use explicit name of const --- libp2p/Network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 5db2d8219..74bc8bd45 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -214,7 +214,7 @@ bi::tcp::endpoint Network::resolveHost(string const& _addr) vector split; boost::split(split, _addr, boost::is_any_of(":")); - unsigned port = split.size() > 1 ? stoi(split[1]) : c_defaultIPPort; + unsigned port = split.size() > 1 ? stoi(split[1]) : dev::p2p::c_defaultIPPort; bi::tcp::endpoint ep(bi::address(), port); boost::system::error_code ec; From 1cd510a541cb92f59a960dddee014883a45a1ee2 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 29 Mar 2015 23:14:43 +0200 Subject: [PATCH 19/21] coding standards --- alethzero/Connect.h | 10 +++++++--- alethzero/MainWin.cpp | 8 ++++---- libp2p/Network.h | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/alethzero/Connect.h b/alethzero/Connect.h index 89b25617c..917c98d67 100644 --- a/alethzero/Connect.h +++ b/alethzero/Connect.h @@ -35,17 +35,21 @@ public: explicit Connect(QWidget* _parent = 0); ~Connect(); + /// Populate host chooser with default host entries void setEnvironment(QStringList const& _nodes); /// clear dialogue inputs void reset(); - // Form field values: - + /// @returns host string chosen or entered QString host(); + + /// @returns NodeId entered QString nodeId(); + + /// @returns true if Required is checked bool required(); private: - Ui::Connect* ui; + Ui::Connect* ui; }; diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1784fbf96..0de7e2cb8 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -259,7 +259,7 @@ NetworkPreferences Main::netPrefs() const } catch (...) { - listenIP = ""; + listenIP.clear(); } auto publicIP = ui->forcePublicIP->text().toStdString(); @@ -269,11 +269,11 @@ NetworkPreferences Main::netPrefs() const } catch (...) { - publicIP = ""; + publicIP.clear(); } if (isPublicAddress(publicIP)) - return NetworkPreferences(publicIP, ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked()); + return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked()); else return NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked()); } @@ -1796,7 +1796,7 @@ void Main::on_connect_triggered() { nodeID = NodeId(fromHex(m_connect.nodeId().toStdString())); } - catch (BadHexCharacter()) {} + catch (BadHexCharacter&) {} m_connect.reset(); diff --git a/libp2p/Network.h b/libp2p/Network.h index 4185cfea5..d02ce3cbe 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -43,10 +43,10 @@ struct NetworkPreferences NetworkPreferences(unsigned short lp = 30303): listenPort(lp) {} // Network Preferences with specific Listen IP - NetworkPreferences(std::string l, unsigned short lp = 30303, bool u = true): publicIPAddress(), listenIPAddress(l), listenPort(lp), traverseNAT(u) {} + NetworkPreferences(std::string const& l, unsigned short lp = 30303, bool u = true): publicIPAddress(), listenIPAddress(l), listenPort(lp), traverseNAT(u) {} // Network Preferences with intended Public IP - NetworkPreferences(std::string publicIP, std::string l = std::string(), unsigned short lp = 30303, bool u = true): publicIPAddress(publicIP), listenIPAddress(l), listenPort(lp), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); } + NetworkPreferences(std::string const& publicIP, std::string const& l = std::string(), unsigned short lp = 30303, bool u = true): publicIPAddress(publicIP), listenIPAddress(l), listenPort(lp), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); } std::string publicIPAddress; std::string listenIPAddress; From b9918f94facc74c15852a0e68c35657690a951a9 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 30 Mar 2015 01:01:28 +0200 Subject: [PATCH 20/21] bugfix. handle recv after disconnect. --- libp2p/UDP.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 68160d053..374f986b0 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -203,7 +203,10 @@ void UDPSocket::doRead() auto self(UDPSocket::shared_from_this()); m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) { - if (_ec) + // ASIO Safety: It is possible that ASIO will call lambda w/o an error + // and after the socket has been disconnected. Checking m_closed + // guarantees that m_host will not be called after disconnect(). + if (_ec || m_closed) return disconnectWithError(_ec); assert(_len); @@ -222,7 +225,7 @@ void UDPSocket::doWrite() auto self(UDPSocket::shared_from_this()); m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t) { - if (_ec) + if (_ec || m_closed) return disconnectWithError(_ec); else { From c83062e76a7f9f7aad8fbc03e84c014646b1f87e Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 30 Mar 2015 01:08:19 +0200 Subject: [PATCH 21/21] coding standards --- alethzero/Connect.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/alethzero/Connect.h b/alethzero/Connect.h index 917c98d67..8209a78af 100644 --- a/alethzero/Connect.h +++ b/alethzero/Connect.h @@ -35,19 +35,19 @@ public: explicit Connect(QWidget* _parent = 0); ~Connect(); - /// Populate host chooser with default host entries + /// Populate host chooser with default host entries. void setEnvironment(QStringList const& _nodes); - /// clear dialogue inputs + /// Clear dialogue inputs. void reset(); - /// @returns host string chosen or entered + /// @returns the host string, as chosen or entered by the user. Assumed to be "hostOrIP:port" (:port is optional). QString host(); - /// @returns NodeId entered + /// @returns the identity of the node, as entered by the user. Assumed to be a 64-character hex string. QString nodeId(); - /// @returns true if Required is checked + /// @returns true if Required is checked by the user, indicating that the host is a required Peer. bool required(); private: