diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 41ac2e856..b51443e63 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -55,16 +55,167 @@ static const set c_rejectAddresses = { {bi::address_v6::from_string("::")} }; +std::vector Host::getInterfaceAddresses() +{ + std::vector addresses; + +#ifdef _WIN32 + WSAData wsaData; + if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) + BOOST_THROW_EXCEPTION(NoNetworking()); + + char ac[80]; + if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) + { + clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name."; + WSACleanup(); + BOOST_THROW_EXCEPTION(NoNetworking()); + } + + struct hostent* phe = gethostbyname(ac); + if (phe == 0) + { + clog(NetWarn) << "Bad host lookup."; + WSACleanup(); + BOOST_THROW_EXCEPTION(NoNetworking()); + } + + for (int i = 0; phe->h_addr_list[i] != 0; ++i) + { + struct in_addr addr; + memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); + char *addrStr = inet_ntoa(addr); + bi::address address(bi::address::from_string(addrStr)); + if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + addresses.push_back(ad.to_v4()); + } + + WSACleanup(); +#else + ifaddrs* ifaddr; + if (getifaddrs(&ifaddr) == -1) + BOOST_THROW_EXCEPTION(NoNetworking()); + + for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0") + continue; + + if (ifa->ifa_addr->sa_family == AF_INET) + { + 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 (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + addresses.push_back(address); + } + else if (ifa->ifa_addr->sa_family == AF_INET6) + { + sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr); + in6_addr addr = sockaddr->sin6_addr; + boost::asio::ip::address_v6::bytes_type bytes; + memcpy(&bytes[0], addr.s6_addr, 16); + boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); + if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + addresses.push_back(address); + } + } + if (ifaddr!=NULL) freeifaddrs(ifaddr); + +#endif + + return std::move(addresses); +} + +int Host::listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort) +{ + int retport = -1; + 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 : _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(); + _acceptor->close(); + } + + // first attempt failed + _acceptor->close(); + continue; + } + } + return retport; +} + +bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) +{ + asserts(_listenPort); + + UPnP* upnp; + try + { + upnp = new UPnP; + } + // let m_upnp continue as null - we handle it properly. + catch (NoUPnPDevice) {} + + bi::tcp::endpoint upnpep; + if (upnp && upnp->isValid()) + { + bi::address paddr; + int p; + for (auto const& addr : _ifAddresses) + if (addr.is_v4() && isPrivateAddress(addr) && (p = upnp->addRedirect(addr.to_string().c_str(), _listenPort))) + { + paddr = addr; + break; + } + + auto eip = upnp->externalIP(); + bi::address eipaddr(bi::address::from_string(eip)); + if (p && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr)) + { + clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << p << "."; + clog(NetNote) << "External addr:" << eip; + o_upnpifaddr = paddr; + upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)p); + } + else + clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place)."; + + if(upnp) + delete upnp; + } + + return upnpep; +} + Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool _start): Worker("p2p", 0), m_clientVersion(_clientVersion), m_netPrefs(_n), + m_ifAddresses(getInterfaceAddresses()), m_ioService(new ba::io_service), m_acceptor(new bi::tcp::acceptor(*m_ioService)), m_socket(new bi::tcp::socket(*m_ioService)), m_key(KeyPair::create()) { - populateAddresses(); + for (auto address: m_ifAddresses) + if (address.is_v4()) + clog(NetNote) << "IP Address: " << address << " = " << (isPrivateAddress(address) ? "[LOCAL]" : "[PEER]"); + clog(NetNote) << "Id:" << id().abridged(); if (_start) start(); @@ -82,11 +233,16 @@ void Host::start() void Host::stop() { - // flag transition to shutdown network - // once m_run is false the scheduler will shutdown network and stopWorking() - m_run = false; + { + // prevent m_run from being set to false at same time as set to true by start() + lock_guard l(x_runtimer); + // once m_run is false the scheduler will shutdown network and stopWorking() + m_run = false; + } + + // we know shutdown is complete when m_timer is reset while (m_timer) - this_thread::sleep_for(chrono::milliseconds(100)); + this_thread::sleep_for(chrono::milliseconds(50)); stopWorking(); } @@ -142,162 +298,6 @@ void Host::seal(bytes& _b) _b[7] = len & 0xff; } -void Host::determinePublic(string const& _publicAddress, bool _upnp) -{ - if (_upnp) - try - { - m_upnp = new UPnP; - } - catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly. - - if (m_upnp && m_upnp->isValid() && m_peerAddresses.size()) - { - clog(NetNote) << "External addr:" << m_upnp->externalIP(); - int p; - - // iterate m_peerAddresses (populated by populateAddresses()) - for (auto const& addr : m_peerAddresses) - if (addr.is_v4() && (p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort))) - break; - if (p) - clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << "."; - else - { - // couldn't map - clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place). Assuming" << m_listenPort << "is local & external port."; - p = m_listenPort; - } - - auto eip = m_upnp->externalIP(); - if (eip == string("0.0.0.0") && _publicAddress.empty()) - m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p); - else - { - bi::address adr = bi::address::from_string(eip); - try - { - adr = bi::address::from_string(_publicAddress); - } - catch (...) {} - m_public = bi::tcp::endpoint(adr, (unsigned short)p); - m_addresses.push_back(m_public.address()); - } - } - else - { - // No UPnP - fallback on given public address or, if empty, the assumed peer address. - bi::address adr; - if (m_peerAddresses.size()) - { - // prefer local ipv4 over local ipv6 - for (auto const& ip: m_peerAddresses) - if (ip.is_v4()) - { - adr = ip; - break; - } - - if (adr.is_unspecified()) - adr = m_peerAddresses[0]; - } - - try - { - adr = bi::address::from_string(_publicAddress); - } - catch (...) {} - m_public = bi::tcp::endpoint(adr, m_listenPort); - m_addresses.push_back(adr); - } -} - -void Host::populateAddresses() -{ - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!m_ioService) - return; - -#ifdef _WIN32 - WSAData wsaData; - if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) - BOOST_THROW_EXCEPTION(NoNetworking()); - - char ac[80]; - if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) - { - clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name."; - WSACleanup(); - BOOST_THROW_EXCEPTION(NoNetworking()); - } - - struct hostent* phe = gethostbyname(ac); - if (phe == 0) - { - clog(NetWarn) << "Bad host lookup."; - WSACleanup(); - BOOST_THROW_EXCEPTION(NoNetworking()); - } - - for (int i = 0; phe->h_addr_list[i] != 0; ++i) - { - struct in_addr addr; - memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); - char *addrStr = inet_ntoa(addr); - bi::address ad(bi::address::from_string(addrStr)); - m_addresses.push_back(ad.to_v4()); - bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end(); - if (!isLocal) - m_peerAddresses.push_back(ad.to_v4()); - clog(NetNote) << "Address: " << ac << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]"); - } - - WSACleanup(); -#else - ifaddrs* ifaddr; - if (getifaddrs(&ifaddr) == -1) - BOOST_THROW_EXCEPTION(NoNetworking()); - - for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr || (strlen(ifa->ifa_name) > 2 && !strncmp(ifa->ifa_name, "lo0", 3))) { - continue; - } - - if (ifa->ifa_addr->sa_family == AF_INET) - { - 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 (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) - m_peerAddresses.push_back(address); - - // Log IPv4 Address: - auto addr4 = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; - char addressBuffer[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, addr4, addressBuffer, INET_ADDRSTRLEN); - printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } - else if (ifa->ifa_addr->sa_family == AF_INET6) - { - sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr); - in6_addr addr = sockaddr->sin6_addr; - boost::asio::ip::address_v6::bytes_type bytes; - memcpy(&bytes[0], addr.s6_addr, 16); - boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); - if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) - m_peerAddresses.push_back(address); - - // Log IPv6 Address: - auto addr6 = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; - char addressBuffer[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, addr6, addressBuffer, INET6_ADDRSTRLEN); - printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } - } - if (ifaddr!=NULL) freeifaddrs(ifaddr); - -#endif -} - shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) { RecursiveGuard l(x_peers); @@ -375,6 +375,69 @@ Nodes Host::potentialPeers(RangeMask const& _known) return ret; } +void Host::determinePublic(string const& _publicAddress, bool _upnp) +{ + 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)) && find(c_rejectAddresses.begin(), c_rejectAddresses.end(), addr) == c_rejectAddresses.end()) + 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 ? false : find(c_rejectAddresses.begin(), c_rejectAddresses.end(), reqpublicaddr) == c_rejectAddresses.end(); + if (!reqpublicaddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking))) + { + if (!m_peerAddresses.count(reqpublicaddr)) + m_peerAddresses.insert(reqpublicaddr); + m_public = reqpublic; + return; + } + + // if address wasn't provided, then use first public ipv4 address found + for (auto addr: m_peerAddresses) + if (addr.is_v4() && !isPrivateAddress(addr)) + { + m_public = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort); + return; + } + + // or find address via upnp + if (_upnp) + { + bi::address upnpifaddr; + bi::tcp::endpoint upnpep = traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr); + if (!upnpep.address().is_unspecified() && !upnpifaddr.is_unspecified()) + { + if (!m_peerAddresses.count(upnpep.address())) + m_peerAddresses.insert(upnpep.address()); + m_public = upnpep; + return; + } + } + + // 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_public = bi::tcp::endpoint(addr, m_listenPort); + return; + } + + // otherwise address is unspecified + m_public = bi::tcp::endpoint(bi::address(), m_listenPort); +} + void Host::ensureAccepting() { // return if there's no io-server (quit called) or we're not listening @@ -636,79 +699,49 @@ void Host::run(boost::system::error_code const& error) static unsigned s_lasttick = 0; s_lasttick += c_timerInterval; - if (error) - // tood: error handling. + if (error || !m_ioService) { + // timer died or io service went away, so stop here m_timer.reset(); return; } - - // no timer means this is first run and network must be started - if (!m_timer) - // run once when host worker thread calls startedWorking() + + // network running + if (m_run) { - // reset io service and create deadline timer - m_ioService->reset(); - m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); - m_run = true; - - // try to open acceptor (ipv4; todo: update for ipv6) - for (unsigned i = 0; i < 2; ++i) + if (s_lasttick == c_timerInterval * 50) { - // try to connect w/listenPort, else attempt net-allocated port - bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : m_netPrefs.listenPort); - try - { - m_acceptor->open(endpoint.protocol()); - m_acceptor->set_option(ba::socket_base::reuse_address(true)); - m_acceptor->bind(endpoint); - m_acceptor->listen(); - m_listenPort = i ? m_acceptor->local_endpoint().port() : m_netPrefs.listenPort; - 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(); - m_listenPort = -1; - } - - // first attempt failed - m_acceptor->close(); - continue; - } + growPeers(); + prunePeers(); + s_lasttick = 0; } - // start capability threads - for (auto const& h: m_capabilities) - h.second->onStarting(); + if (m_hadNewNodes) + { + for (auto p: m_peers) + if (auto pp = p.second.lock()) + pp->serviceNodesRequest(); + + m_hadNewNodes = false; + } - // determine public IP, but only if we're able to listen for connections - // todo: visualize when listen is unavailable in UI - if (m_listenPort) + if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s. { - determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); - ensureAccepting(); + for (auto p: m_peers) + if (auto pp = p.second.lock()) + if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60)) + pp->disconnect(PingTimeout); + pingAll(); } - // if m_public address is valid then add us to node list - // todo: abstract empty() and emplace logic - if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) - noteNode(id(), m_public, Origin::Perfect, false); + auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); }; + m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); + m_timer->async_wait(runcb); - clog(NetNote) << "Id:" << id().abridged(); - } - - // io service went away, so stop here - if (!m_ioService) - { - m_timer.reset(); return; } - - // network stopped; disconnect peers + + // network stopping if (!m_run) { // close acceptor @@ -745,50 +778,60 @@ void Host::run(boost::system::error_code const& error) if (m_socket->is_open()) m_socket->close(); - if (m_upnp != nullptr) - delete m_upnp; - // m_run is false, so we're stopping; kill timer s_lasttick = 0; + + // causes parent thread's stop() to continue which calls stopWorking() m_timer.reset(); + + // stop ioservice (stops blocking worker thread, allowing thread to join) if (!!m_ioService) m_ioService->stop(); return; } - - - if (s_lasttick == c_timerInterval * 10) - { - growPeers(); - prunePeers(); - s_lasttick = 0; - } - - if (m_hadNewNodes) - { - for (auto p: m_peers) - if (auto pp = p.second.lock()) - pp->serviceNodesRequest(); - - m_hadNewNodes = false; - } - - if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s. - { - for (auto p: m_peers) - if (auto pp = p.second.lock()) - if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60)) - pp->disconnect(PingTimeout); - pingAll(); - } - - auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); }; - m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); - m_timer->async_wait(runcb); } void Host::startedWorking() { + if (asserts(!m_timer)) + { + // no timer means this is first run and network must be started + // (run once when host worker thread calls startedWorking()) + + { + // prevent m_run from being set to true at same time as set to false by stop() + // don't release mutex until m_timer is set so in case stop() is called at same + // time, stop will wait on m_timer and graceful network shutdown. + lock_guard l(x_runtimer); + // reset io service and create deadline timer + m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); + m_run = true; + } + m_ioService->reset(); + + // try to open acceptor (todo: ipv6) + m_listenPort = listen4(m_acceptor.get(), m_netPrefs.listenPort); + + // start capability threads + for (auto const& h: m_capabilities) + h.second->onStarting(); + + // 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); + ensureAccepting(); + } + + // if m_public address is valid then add us to node list + // todo: abstract empty() and emplace logic + if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) + noteNode(id(), m_public, Origin::Perfect, false); + + clog(NetNote) << "Id:" << id().abridged(); + } + run(boost::system::error_code()); } diff --git a/libp2p/Host.h b/libp2p/Host.h index b60949278..c619b6867 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -121,13 +121,24 @@ class Host: public Worker friend class HostCapabilityFace; friend struct Node; + /// Static network interface methods +public: + /// @returns public and private interface addresses + static std::vector getInterfaceAddresses(); + + /// Try to bind and listen on _listenPort, else attempt net-allocated port. + static int listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort); + + /// 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); + public: /// Start server, listening for connections on the given port. Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bool _start = false); /// Will block on network process events. virtual ~Host(); - + /// Basic peer network protocol version. unsigned protocolVersion() const; @@ -144,7 +155,7 @@ public: void connect(bi::tcp::endpoint const& _ep); void connect(std::shared_ptr const& _n); - /// @returns true if we have the a peer of the given id. + /// @returns true iff we have a peer of the given id. bool havePeer(NodeId _id) const; /// Set ideal number of peers. @@ -172,14 +183,14 @@ public: void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } - /// Start network. + /// Start network. @threadsafe void start(); - /// Stop network. + /// Stop network. @threadsafe void stop(); - /// @returns if network is running - bool isStarted() const { return isWorking(); } + /// @returns if network is running. + bool isStarted() const { return m_run; } /// Reset acceptor, socket, and IO service. Called by deallocator. Maybe called by implementation when ordered deallocation is required. void quit(); @@ -191,13 +202,12 @@ public: std::shared_ptr node(NodeId _id) const { if (m_nodes.count(_id)) return m_nodes.at(_id); return std::shared_ptr(); } private: - void seal(bytes& _b); - void populateAddresses(); - - /// Try UPNP or listen to assumed address. Requires valid m_listenPort. + /// Populate m_peerAddresses with available public addresses. void determinePublic(std::string const& _publicAddress, bool _upnp); void ensureAccepting(); + + void seal(bytes& _b); void growPeers(); void prunePeers(); @@ -206,7 +216,6 @@ private: virtual void startedWorking(); /// Called by startedWorking. Not thread-safe; to be called only be worker callback. void run(boost::system::error_code const& error); ///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions. - bool m_run = false; /// Run network virtual void doWork(); @@ -214,9 +223,15 @@ private: std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId()); Nodes potentialPeers(RangeMask const& _known); + bool m_run = false; ///< Whether network is running. + std::mutex x_runtimer; ///< Start/stop mutex. + std::string m_clientVersion; ///< Our version string. NetworkPreferences m_netPrefs; ///< Network settings. + + /// Interface addresses (private, public) + std::vector m_ifAddresses; ///< Interface addresses. int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized. @@ -227,7 +242,6 @@ private: std::unique_ptr m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms. static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. - UPnP* m_upnp = nullptr; ///< UPnP helper. bi::tcp::endpoint m_public; ///< Our public listening endpoint. KeyPair m_key; ///< Our unique ID. @@ -247,13 +261,11 @@ private: std::vector m_nodesList; RangeMask m_ready; ///< Indices into m_nodesList over to which nodes we are not currently connected, connecting or otherwise ignoring. - RangeMask m_private; ///< Indices into m_nodesList over to which nodes are private. - - unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. + RangeMask m_private; ///< Indices into m_nodesList over to which nodes are private. - // Our addresses. - std::vector m_addresses; ///< Addresses for us. - std::vector m_peerAddresses; ///< Addresses that peers (can) know us by. + unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. + + std::set m_peerAddresses; ///< Public addresses that peers (can) know us by. // Our capabilities. std::map> m_capabilities; ///< Each of the capabilities we support. diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index c4385df5f..958473870 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -344,7 +344,7 @@ bool Session::interpret(RLP const& _r) // goto CONTINUE; // Wierd port. // Avoid our random other addresses that they might end up giving us. - for (auto i: m_server->m_addresses) + for (auto i: m_server->m_peerAddresses) if (ep.address() == i && ep.port() == m_server->listenPort()) goto CONTINUE;