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;