diff --git a/Builds/VisualStudio/stellar-core.vcxproj b/Builds/VisualStudio/stellar-core.vcxproj index 734d201dcb..b8f5e697a3 100644 --- a/Builds/VisualStudio/stellar-core.vcxproj +++ b/Builds/VisualStudio/stellar-core.vcxproj @@ -425,6 +425,7 @@ exit /b 0 + @@ -608,6 +609,7 @@ exit /b 0 + diff --git a/Builds/VisualStudio/stellar-core.vcxproj.filters b/Builds/VisualStudio/stellar-core.vcxproj.filters index ca5ee962ab..58f874eade 100644 --- a/Builds/VisualStudio/stellar-core.vcxproj.filters +++ b/Builds/VisualStudio/stellar-core.vcxproj.filters @@ -852,6 +852,9 @@ main\generated + + overlay + @@ -1466,6 +1469,9 @@ main + + overlay + diff --git a/src/main/Config.cpp b/src/main/Config.cpp index 2f2ebc70e5..88a6d27849 100644 --- a/src/main/Config.cpp +++ b/src/main/Config.cpp @@ -11,6 +11,7 @@ #include "main/ExternalQueue.h" #include "main/StellarCoreVersion.h" #include "scp/LocalNode.h" +#include "util/Fs.h" #include "util/Logging.h" #include "util/types.h" @@ -67,7 +68,7 @@ Config::Config() : NODE_SEED(SecretKey::random()) TARGET_PEER_CONNECTIONS = 8; MAX_ADDITIONAL_PEER_CONNECTIONS = -1; MAX_PEER_CONNECTIONS = 12; - MAX_PENDING_CONNECTIONS = 5000; + MAX_PENDING_CONNECTIONS = 500; PEER_AUTHENTICATION_TIMEOUT = 2; PEER_TIMEOUT = 30; PREFERRED_PEERS_ONLY = false; @@ -527,6 +528,17 @@ Config::load(std::string const& filename) static_cast(MAX_ADDITIONAL_PEER_CONNECTIONS + TARGET_PEER_CONNECTIONS)); + // ensure that max pending connections is not above what the system + // supports + MAX_PENDING_CONNECTIONS = static_cast( + std::min(MAX_PENDING_CONNECTIONS, fs::getMaxConnections())); + + // enforce TARGET_PEER_CONNECTIONS <= MAX_PEER_CONNECTIONS <= + // MAX_PENDING_CONNECTIONS + MAX_PEER_CONNECTIONS = + std::min(MAX_PEER_CONNECTIONS, MAX_PENDING_CONNECTIONS); + TARGET_PEER_CONNECTIONS = + std::min(TARGET_PEER_CONNECTIONS, MAX_PEER_CONNECTIONS); validateConfig(); } catch (cpptoml::toml_parse_exception& ex) diff --git a/src/overlay/LoopbackPeer.cpp b/src/overlay/LoopbackPeer.cpp index 509070edea..bf3e76e345 100644 --- a/src/overlay/LoopbackPeer.cpp +++ b/src/overlay/LoopbackPeer.cpp @@ -28,7 +28,7 @@ LoopbackPeer::LoopbackPeer(Application& app, PeerRole role) : Peer(app, role) } PeerBareAddress -LoopbackPeer::makeAddress(unsigned short remoteListeningPort) const +LoopbackPeer::makeAddress(int remoteListeningPort) const { if (remoteListeningPort <= 0 || remoteListeningPort > UINT16_MAX) { @@ -36,7 +36,8 @@ LoopbackPeer::makeAddress(unsigned short remoteListeningPort) const } else { - return PeerBareAddress{"127.0.0.1", remoteListeningPort}; + return PeerBareAddress{ + "127.0.0.1", static_cast(remoteListeningPort)}; } } diff --git a/src/overlay/LoopbackPeer.h b/src/overlay/LoopbackPeer.h index 4407d3ce47..0ba7a82a63 100644 --- a/src/overlay/LoopbackPeer.h +++ b/src/overlay/LoopbackPeer.h @@ -53,8 +53,7 @@ class LoopbackPeer : public Peer Stats mStats; void sendMessage(xdr::msg_ptr&& xdrBytes) override; - PeerBareAddress - makeAddress(unsigned short remoteListeningPort) const override; + PeerBareAddress makeAddress(int remoteListeningPort) const override; AuthCert getAuthCert() override; void processInQueue(); diff --git a/src/overlay/OverlayManagerImpl.cpp b/src/overlay/OverlayManagerImpl.cpp index fe30d8fd26..e25f730570 100644 --- a/src/overlay/OverlayManagerImpl.cpp +++ b/src/overlay/OverlayManagerImpl.cpp @@ -135,7 +135,16 @@ OverlayManagerImpl::connectTo(PeerRecord& pr) pr.backOff(mApp.getClock()); pr.storePeerRecord(mApp.getDatabase()); - addPendingPeer(TCPPeer::initiate(mApp, pr.getAddress())); + if (getPendingPeersCount() < mApp.getConfig().MAX_PENDING_CONNECTIONS) + { + addPendingPeer(TCPPeer::initiate(mApp, pr.getAddress())); + } + else + { + CLOG(DEBUG, "Overlay") + << "reached maximum number of pending connections, backing off " + << pr.toString(); + } } else { @@ -222,7 +231,11 @@ OverlayManagerImpl::getPreferredPeersFromConfig() std::vector OverlayManagerImpl::getPeersToConnectTo(int maxNum) { - const int batchSize = std::max(20, maxNum); + // don't connect to too many peers at once + maxNum = std::min(maxNum, 50); + + // batch is how many peers to load from the database every time + const int batchSize = std::max(50, maxNum); std::vector peers; diff --git a/src/overlay/OverlayManagerTests.cpp b/src/overlay/OverlayManagerTests.cpp index e75a42028d..f640d59982 100644 --- a/src/overlay/OverlayManagerTests.cpp +++ b/src/overlay/OverlayManagerTests.cpp @@ -40,7 +40,7 @@ class PeerStub : public Peer mAddress = addres; } virtual PeerBareAddress - makeAddress(unsigned short) const override + makeAddress(int) const override { REQUIRE(false); // should not be called return {}; diff --git a/src/overlay/Peer.cpp b/src/overlay/Peer.cpp index b0128669c5..46c2b71ca4 100644 --- a/src/overlay/Peer.cpp +++ b/src/overlay/Peer.cpp @@ -378,19 +378,25 @@ Peer::sendGetScpState(uint32 ledgerSeq) void Peer::sendPeers() { - // send top 50 peers we know about + StellarMessage newMsg; + newMsg.type(PEERS); + uint32 maxPeerCount = std::min(50, newMsg.peers().max_size()); + + // send top peers we know about vector peerList; PeerRecord::loadPeerRecords(mApp.getDatabase(), 50, mApp.getClock().now(), [&](PeerRecord const& pr) { - if (!pr.getAddress().isPrivate() && - pr.getAddress() != mAddress) + bool r = peerList.size() < maxPeerCount; + if (r) { - peerList.emplace_back(pr); + if (!pr.getAddress().isPrivate() && + pr.getAddress() != mAddress) + { + peerList.emplace_back(pr); + } } - return peerList.size() < 50; + return r; }); - StellarMessage newMsg; - newMsg.type(PEERS); newMsg.peers().reserve(peerList.size()); for (auto const& pr : peerList) { diff --git a/src/overlay/Peer.h b/src/overlay/Peer.h index 694f230521..c4df871d64 100644 --- a/src/overlay/Peer.h +++ b/src/overlay/Peer.h @@ -178,8 +178,7 @@ class Peer : public std::enable_shared_from_this, } virtual AuthCert getAuthCert(); - virtual PeerBareAddress - makeAddress(unsigned short remoteListeningPort) const = 0; + virtual PeerBareAddress makeAddress(int remoteListeningPort) const = 0; void startIdleTimer(); void idleTimerExpired(asio::error_code const& error); diff --git a/src/overlay/PeerBareAddress.cpp b/src/overlay/PeerBareAddress.cpp index 1f00b264e9..aac7ffe67a 100644 --- a/src/overlay/PeerBareAddress.cpp +++ b/src/overlay/PeerBareAddress.cpp @@ -58,7 +58,7 @@ PeerBareAddress::PeerBareAddress(PeerAddress const& pa) : mType{Type::IPv4} ip << (int)pa.ip.ipv4()[0] << "." << (int)pa.ip.ipv4()[1] << "." << (int)pa.ip.ipv4()[2] << "." << (int)pa.ip.ipv4()[3]; mIP = ip.str(); - mPort = pa.port; + mPort = static_cast(pa.port); } PeerBareAddress @@ -150,7 +150,7 @@ PeerBareAddress::toString() const return mIP + ":" + std::to_string(mPort); } default: - assert(false); + abort(); } } diff --git a/src/overlay/PeerRecord.cpp b/src/overlay/PeerRecord.cpp index 1c62a7814d..0d94e40df4 100644 --- a/src/overlay/PeerRecord.cpp +++ b/src/overlay/PeerRecord.cpp @@ -125,7 +125,7 @@ PeerRecord::loadPeerRecords(Database& db, int batchSize, try { int offset = 0; - bool didSomething; + bool lastRes; do { tm nextAttemptMax = VirtualClock::pointToTm(nextAttemptCutoff); @@ -141,14 +141,14 @@ PeerRecord::loadPeerRecords(Database& db, int batchSize, st.exchange(use(batchSize)); st.exchange(use(offset)); - didSomething = false; + lastRes = false; loadPeerRecords(db, prep, [&](PeerRecord const& pr) { offset++; - didSomething = true; - return pred(pr); + lastRes = pred(pr); + return lastRes; }); - } while (didSomething); + } while (lastRes); } catch (soci_error& err) { diff --git a/src/overlay/TCPPeer.cpp b/src/overlay/TCPPeer.cpp index ca1392d617..ec724d7ace 100644 --- a/src/overlay/TCPPeer.cpp +++ b/src/overlay/TCPPeer.cpp @@ -113,7 +113,7 @@ TCPPeer::~TCPPeer() } PeerBareAddress -TCPPeer::makeAddress(unsigned short remoteListeningPort) const +TCPPeer::makeAddress(int remoteListeningPort) const { asio::error_code ec; auto ep = mSocket->next_layer().remote_endpoint(ec); @@ -123,7 +123,9 @@ TCPPeer::makeAddress(unsigned short remoteListeningPort) const } else { - return PeerBareAddress{ep.address().to_string(), remoteListeningPort}; + return PeerBareAddress{ + ep.address().to_string(), + static_cast(remoteListeningPort)}; } } diff --git a/src/overlay/TCPPeer.h b/src/overlay/TCPPeer.h index 62d9f75720..32e2494199 100644 --- a/src/overlay/TCPPeer.h +++ b/src/overlay/TCPPeer.h @@ -35,8 +35,7 @@ class TCPPeer : public Peer bool mDelayedShutdown{false}; bool mShutdownScheduled{false}; - PeerBareAddress - makeAddress(unsigned short remoteListeningPort) const override; + PeerBareAddress makeAddress(int remoteListeningPort) const override; void recvMessage(); void sendMessage(xdr::msg_ptr&& xdrBytes) override; diff --git a/src/util/Fs.cpp b/src/util/Fs.cpp index 63f9cab0cc..fa7c7d1538 100644 --- a/src/util/Fs.cpp +++ b/src/util/Fs.cpp @@ -15,6 +15,7 @@ #include #else #include +#include #include #endif @@ -440,5 +441,30 @@ checkNoGzipSuffix(std::string const& filename) throw std::runtime_error("filename ends in .gz"); } } + +#ifdef _WIN32 + +int +getMaxConnections() +{ + // on Windows, there is no limit on handles + // only limits based on ephemeral ports, etc + return 32000; +} + +#else +int +getMaxConnections() +{ + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) == 0) + { + // leave some buffer + return (rl.rlim_cur * 3) / 4; + } + // could not query the limit, default to a value that should work + return 64; +} +#endif } } diff --git a/src/util/Fs.h b/src/util/Fs.h index c11c30c625..644cd7d226 100644 --- a/src/util/Fs.h +++ b/src/util/Fs.h @@ -85,5 +85,8 @@ std::string remoteName(std::string const& type, std::string const& hexStr, void checkGzipSuffix(std::string const& filename); void checkNoGzipSuffix(std::string const& filename); + +// returns the maximum number of connections that can be done at the same time +int getMaxConnections(); } } diff --git a/src/xdr/Stellar-overlay.x b/src/xdr/Stellar-overlay.x index 79ae734138..474c0b4856 100644 --- a/src/xdr/Stellar-overlay.x +++ b/src/xdr/Stellar-overlay.x @@ -112,7 +112,7 @@ case DONT_HAVE: case GET_PEERS: void; case PEERS: - PeerAddress peers<>; + PeerAddress peers<100>; case GET_TX_SET: uint256 txSetHash;