diff --git a/network/src/main/java/io/bitsquare/p2p/P2PService.java b/network/src/main/java/io/bitsquare/p2p/P2PService.java index 48268effeb..45e63c82b1 100644 --- a/network/src/main/java/io/bitsquare/p2p/P2PService.java +++ b/network/src/main/java/io/bitsquare/p2p/P2PService.java @@ -55,9 +55,11 @@ import static com.google.common.base.Preconditions.checkNotNull; public class P2PService implements SetupListener, MessageListener, ConnectionListener, RequestDataManager.Listener, HashMapChangedListener { private static final Logger log = LoggerFactory.getLogger(P2PService.class); + public static final int MAX_CONNECTIONS_DEFAULT = 12; private final SeedNodesRepository seedNodesRepository; private final int port; + private final int maxConnections; private final File torDir; private Clock clock; private final Optional optionalEncryptionService; @@ -104,8 +106,32 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis Clock clock, @Nullable EncryptionService encryptionService, @Nullable KeyRing keyRing) { + this( + seedNodesRepository, + port, MAX_CONNECTIONS_DEFAULT, + torDir, + useLocalhost, + networkId, + storageDir, + clock, + encryptionService, + keyRing + ); + } + + @VisibleForTesting + public P2PService(SeedNodesRepository seedNodesRepository, + int port, int maxConnections, + File torDir, + boolean useLocalhost, + int networkId, + File storageDir, + Clock clock, + @Nullable EncryptionService encryptionService, + @Nullable KeyRing keyRing) { this.seedNodesRepository = seedNodesRepository; this.port = port; + this.maxConnections = maxConnections; this.torDir = torDir; this.clock = clock; @@ -124,7 +150,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis networkNode.addMessageListener(this); Set seedNodeAddresses = seedNodesRepository.getSeedNodeAddresses(useLocalhost, networkId); - peerManager = new PeerManager(networkNode, seedNodeAddresses, storageDir, clock); + peerManager = new PeerManager(networkNode, maxConnections, seedNodeAddresses, storageDir, clock); broadcaster = new Broadcaster(networkNode, peerManager); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java b/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java index 9649fc4b56..9f38a75735 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java @@ -28,32 +28,28 @@ public class PeerManager implements ConnectionListener { // Use a long delay as the bootstrapping peer might need a while until it knows its onion address private static final long REMOVE_ANONYMOUS_PEER_SEC = Timer.STRESS_TEST ? 10 : 120; - private static int MAX_CONNECTIONS; - private static int MIN_CONNECTIONS; - private static int MAX_CONNECTIONS_PEER; - private static int MAX_CONNECTIONS_NON_DIRECT; - - - private static int MAX_CONNECTIONS_ABSOLUTE; - private final boolean printReportedPeersDetails = true; - private boolean lostAllConnections; - - public static void setMaxConnections(int maxConnections) { - MAX_CONNECTIONS = maxConnections; - MIN_CONNECTIONS = Math.max(1, maxConnections - 4); - MAX_CONNECTIONS_PEER = MAX_CONNECTIONS + 4; - MAX_CONNECTIONS_NON_DIRECT = MAX_CONNECTIONS + 8; - MAX_CONNECTIONS_ABSOLUTE = MAX_CONNECTIONS + 18; - } - - static { - setMaxConnections(12); - } - private static final int MAX_REPORTED_PEERS = 1000; private static final int MAX_PERSISTED_PEERS = 500; private static final long MAX_AGE = TimeUnit.DAYS.toMillis(14); // max age for reported peers is 14 days + private final boolean printReportedPeersDetails = true; + private boolean lostAllConnections; + + private int maxConnections; + private int minConnections; + private int maxConnectionsPeer; + private int maxConnectionsNonDirect; + private int maxConnectionsAbsolute; + + // Modify this to change the relationships between connection limits. + private void setConnectionLimits(int maxConnections) { + this.maxConnections = maxConnections; + minConnections = Math.max(1, maxConnections - 4); + maxConnectionsPeer = maxConnections + 4; + maxConnectionsNonDirect = maxConnections + 8; + maxConnectionsAbsolute = maxConnections + 18; + } + /////////////////////////////////////////////////////////////////////////////////////////// // Listener @@ -90,7 +86,9 @@ public class PeerManager implements ConnectionListener { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public PeerManager(NetworkNode networkNode, Set seedNodeAddresses, File storageDir, Clock clock) { + public PeerManager(NetworkNode networkNode, int maxConnections, Set seedNodeAddresses, + File storageDir, Clock clock) { + setConnectionLimits(maxConnections); this.networkNode = networkNode; this.clock = clock; // seedNodeAddresses can be empty (in case there is only 1 seed node, the seed node starting up has no other seed nodes) @@ -139,7 +137,7 @@ public class PeerManager implements ConnectionListener { /////////////////////////////////////////////////////////////////////////////////////////// public int getMaxConnections() { - return MAX_CONNECTIONS_ABSOLUTE; + return maxConnectionsAbsolute; } public void addListener(Listener listener) { @@ -199,7 +197,7 @@ public class PeerManager implements ConnectionListener { removeSuperfluousSeedNodes(); removeTooOldReportedPeers(); removeTooOldPersistedPeers(); - checkMaxConnections(MAX_CONNECTIONS); + checkMaxConnections(maxConnections); } else { log.warn("We have stopped already. We ignore that checkMaxConnectionsTimer.run call."); } @@ -223,8 +221,8 @@ public class PeerManager implements ConnectionListener { if (candidates.size() == 0) { log.info("No candidates found. We check if we exceed our " + - "MAX_CONNECTIONS_PEER limit of {}", MAX_CONNECTIONS_PEER); - if (size > MAX_CONNECTIONS_PEER) { + "maxConnectionsPeer limit of {}", maxConnectionsPeer); + if (size > maxConnectionsPeer) { log.info("Lets try to remove ANY connection of type PEER."); candidates = allConnections.stream() .filter(e -> e.getPeerType() == Connection.PeerType.PEER) @@ -232,8 +230,8 @@ public class PeerManager implements ConnectionListener { if (candidates.size() == 0) { log.info("No candidates found. We check if we exceed our " + - "MAX_CONNECTIONS_NON_DIRECT limit of {}", MAX_CONNECTIONS_NON_DIRECT); - if (size > MAX_CONNECTIONS_NON_DIRECT) { + "maxConnectionsNonDirect limit of {}", maxConnectionsNonDirect); + if (size > maxConnectionsNonDirect) { log.info("Lets try to remove any connection which is not of type DIRECT_MSG_PEER."); candidates = allConnections.stream() .filter(e -> e.getPeerType() != Connection.PeerType.DIRECT_MSG_PEER) @@ -241,8 +239,8 @@ public class PeerManager implements ConnectionListener { if (candidates.size() == 0) { log.info("No candidates found. We check if we exceed our " + - "MAX_CONNECTIONS_ABSOLUTE limit of {}", MAX_CONNECTIONS_ABSOLUTE); - if (size > MAX_CONNECTIONS_ABSOLUTE) { + "maxConnectionsAbsolute limit of {}", maxConnectionsAbsolute); + if (size > maxConnectionsAbsolute) { log.info("Lets try to remove any connection."); candidates = allConnections.stream().collect(Collectors.toList()); } @@ -288,7 +286,7 @@ public class PeerManager implements ConnectionListener { private void removeSuperfluousSeedNodes() { Log.traceCall(); - if (networkNode.getConfirmedConnections().size() > MAX_CONNECTIONS) { + if (networkNode.getConfirmedConnections().size() > maxConnections) { Set connections = networkNode.getConfirmedConnections(); if (hasSufficientConnections()) { List candidates = connections.stream() @@ -346,7 +344,7 @@ public class PeerManager implements ConnectionListener { printNewReportedPeers(reportedPeersToAdd); // We check if the reported msg is not violating our rules - if (reportedPeersToAdd.size() <= (MAX_REPORTED_PEERS + PeerManager.MAX_CONNECTIONS_ABSOLUTE + 10)) { + if (reportedPeersToAdd.size() <= (MAX_REPORTED_PEERS + maxConnectionsAbsolute + 10)) { reportedPeers.addAll(reportedPeersToAdd); purgeReportedPeersIfExceeds(); @@ -367,7 +365,7 @@ public class PeerManager implements ConnectionListener { private void purgeReportedPeersIfExceeds() { Log.traceCall(); int size = reportedPeers.size(); - int limit = MAX_REPORTED_PEERS - MAX_CONNECTIONS_ABSOLUTE; + int limit = MAX_REPORTED_PEERS - maxConnectionsAbsolute; if (size > limit) { log.trace("We have already {} reported peers which exceeds our limit of {}." + "We remove random peers from the reported peers list.", size, limit); @@ -470,7 +468,7 @@ public class PeerManager implements ConnectionListener { /////////////////////////////////////////////////////////////////////////////////////////// public boolean hasSufficientConnections() { - return networkNode.getNodeAddressesOfConfirmedConnections().size() >= MIN_CONNECTIONS; + return networkNode.getNodeAddressesOfConfirmedConnections().size() >= minConnections; } public boolean isSeedNode(Peer reportedPeer) { diff --git a/network/src/main/java/io/bitsquare/p2p/seed/SeedNode.java b/network/src/main/java/io/bitsquare/p2p/seed/SeedNode.java index 389fa7fb91..300b46482c 100644 --- a/network/src/main/java/io/bitsquare/p2p/seed/SeedNode.java +++ b/network/src/main/java/io/bitsquare/p2p/seed/SeedNode.java @@ -30,6 +30,7 @@ public class SeedNode { public static final int MAX_CONNECTIONS_DEFAULT = 50; private NodeAddress mySeedNodeAddress = new NodeAddress("localhost:8001"); + private int maxConnections = MAX_CONNECTIONS_DEFAULT; // we keep default a higher connection size for seed nodes private boolean useLocalhost = false; private Set progArgSeedNodes; private P2PService seedNodeP2PService; @@ -67,13 +68,9 @@ public class SeedNode { Version.setBtcNetworkId(networkId); if (args.length > 2) { String arg2 = args[2]; - int maxConnections = Integer.parseInt(arg2); + maxConnections = Integer.parseInt(arg2); log.info("From processArgs: maxConnections=" + maxConnections); checkArgument(maxConnections < MAX_CONNECTIONS_LIMIT, "maxConnections seems to be a bit too high..."); - PeerManager.setMaxConnections(maxConnections); - } else { - // we keep default a higher connection size for seed nodes - PeerManager.setMaxConnections(MAX_CONNECTIONS_DEFAULT); } if (args.length > 3) { String arg3 = args[3]; @@ -107,11 +104,13 @@ public class SeedNode { } public void createAndStartP2PService(boolean useDetailedLogging) { - createAndStartP2PService(mySeedNodeAddress, useLocalhost, Version.getBtcNetworkId(), useDetailedLogging, progArgSeedNodes, null); + createAndStartP2PService(mySeedNodeAddress, maxConnections, useLocalhost, + Version.getBtcNetworkId(), useDetailedLogging, progArgSeedNodes, null); } @VisibleForTesting public void createAndStartP2PService(NodeAddress mySeedNodeAddress, + int maxConnections, boolean useLocalhost, int networkId, boolean useDetailedLogging, @@ -144,7 +143,8 @@ public class SeedNode { log.info("Created torDir at " + torDir.getAbsolutePath()); seedNodesRepository.setNodeAddressToExclude(mySeedNodeAddress); - seedNodeP2PService = new P2PService(seedNodesRepository, mySeedNodeAddress.port, torDir, useLocalhost, networkId, storageDir, new Clock(), null, null); + seedNodeP2PService = new P2PService(seedNodesRepository, mySeedNodeAddress.port, maxConnections, + torDir, useLocalhost, networkId, storageDir, new Clock(), null, null); seedNodeP2PService.start(listener); } diff --git a/network/src/test/java/io/bitsquare/p2p/PeerServiceTest.java b/network/src/test/java/io/bitsquare/p2p/PeerServiceTest.java index 8723561751..fb0fe75710 100644 --- a/network/src/test/java/io/bitsquare/p2p/PeerServiceTest.java +++ b/network/src/test/java/io/bitsquare/p2p/PeerServiceTest.java @@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch; // Run it once then lookup for onion address at: tor/hiddenservice/hostname and use that for the NodeAddress param. public class PeerServiceTest { private static final Logger log = LoggerFactory.getLogger(PeerServiceTest.class); + private static final int MAX_CONNECTIONS = 100; final boolean useLocalhost = true; private CountDownLatch latch; @@ -37,7 +38,6 @@ public class PeerServiceTest { public void setup() throws InterruptedException { LocalhostNetworkNode.setSimulateTorDelayTorNode(50); LocalhostNetworkNode.setSimulateTorDelayHiddenService(8); - PeerManager.setMaxConnections(100); if (useLocalhost) { seedNodeAddresses.add(new NodeAddress("localhost:8001")); @@ -127,7 +127,7 @@ public class PeerServiceTest { /* latch = new CountDownLatch(2); - seedNode.createAndStartP2PService(nodeAddress, useLocalhost, 2, true, + seedNode.createAndStartP2PService(nodeAddress, MAX_CONNECTIONS, useLocalhost, 2, true, seedNodeAddresses, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { @@ -181,7 +181,7 @@ public class PeerServiceTest { latch = new CountDownLatch(6); seedNode1 = new SeedNode("test_dummy_dir"); - seedNode1.createAndStartP2PService(nodeAddress1, useLocalhost, 2, true, seedNodeAddresses, new P2PServiceListener() { + seedNode1.createAndStartP2PService(nodeAddress1, MAX_CONNECTIONS, useLocalhost, 2, true, seedNodeAddresses, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { latch.countDown(); @@ -219,7 +219,7 @@ public class PeerServiceTest { Thread.sleep(500); seedNode2 = new SeedNode("test_dummy_dir"); - seedNode2.createAndStartP2PService(nodeAddress2, useLocalhost, 2, true, seedNodeAddresses, new P2PServiceListener() { + seedNode2.createAndStartP2PService(nodeAddress2, MAX_CONNECTIONS, useLocalhost, 2, true, seedNodeAddresses, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { latch.countDown(); @@ -456,7 +456,7 @@ public class PeerServiceTest { SeedNode seedNode = new SeedNode("test_dummy_dir"); latch = new CountDownLatch(1); - seedNode.createAndStartP2PService(new NodeAddress("localhost", port), useLocalhost, 2, true, seedNodeAddresses, new P2PServiceListener() { + seedNode.createAndStartP2PService(new NodeAddress("localhost", port), MAX_CONNECTIONS, useLocalhost, 2, true, seedNodeAddresses, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { latch.countDown(); diff --git a/network/src/test/java/io/bitsquare/p2p/TestUtils.java b/network/src/test/java/io/bitsquare/p2p/TestUtils.java index b5b40cdd95..25a6fdcc01 100644 --- a/network/src/test/java/io/bitsquare/p2p/TestUtils.java +++ b/network/src/test/java/io/bitsquare/p2p/TestUtils.java @@ -82,7 +82,7 @@ public class TestUtils { } CountDownLatch latch = new CountDownLatch(1); - seedNode.createAndStartP2PService(new NodeAddress("localhost", port), useLocalhost, 2, true, + seedNode.createAndStartP2PService(new NodeAddress("localhost", port), SeedNode.MAX_CONNECTIONS_DEFAULT, useLocalhost, 2, true, seedNodes, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { diff --git a/network/src/test/java/io/bitsquare/p2p/routing/PeerManagerTest.java b/network/src/test/java/io/bitsquare/p2p/routing/PeerManagerTest.java index 96ec47e6ca..f157d7d259 100644 --- a/network/src/test/java/io/bitsquare/p2p/routing/PeerManagerTest.java +++ b/network/src/test/java/io/bitsquare/p2p/routing/PeerManagerTest.java @@ -26,6 +26,7 @@ import java.util.concurrent.CountDownLatch; @Ignore public class PeerManagerTest { private static final Logger log = LoggerFactory.getLogger(PeerManagerTest.class); + private static final int MAX_CONNECTIONS = 100; final boolean useLocalhost = true; private CountDownLatch latch; @@ -37,7 +38,6 @@ public class PeerManagerTest { public void setup() throws InterruptedException { LocalhostNetworkNode.setSimulateTorDelayTorNode(50); LocalhostNetworkNode.setSimulateTorDelayHiddenService(8); - PeerManager.setMaxConnections(100); seedNodes = new HashSet<>(); if (useLocalhost) { @@ -84,7 +84,7 @@ public class PeerManagerTest { seedNodes.add(nodeAddress); seedNode1 = new SeedNode("test_dummy_dir"); latch = new CountDownLatch(2); - seedNode1.createAndStartP2PService(nodeAddress, useLocalhost, 2, true, + seedNode1.createAndStartP2PService(nodeAddress, MAX_CONNECTIONS, useLocalhost, 2, true, seedNodes, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { @@ -136,7 +136,7 @@ public class PeerManagerTest { latch = new CountDownLatch(6); seedNode1 = new SeedNode("test_dummy_dir"); - seedNode1.createAndStartP2PService(nodeAddress1, useLocalhost, 2, true, seedNodes, new P2PServiceListener() { + seedNode1.createAndStartP2PService(nodeAddress1, MAX_CONNECTIONS, useLocalhost, 2, true, seedNodes, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { latch.countDown(); @@ -174,7 +174,7 @@ public class PeerManagerTest { Thread.sleep(500); seedNode2 = new SeedNode("test_dummy_dir"); - seedNode2.createAndStartP2PService(nodeAddress2, useLocalhost, 2, true, seedNodes, new P2PServiceListener() { + seedNode2.createAndStartP2PService(nodeAddress2, MAX_CONNECTIONS, useLocalhost, 2, true, seedNodes, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { latch.countDown(); @@ -411,7 +411,7 @@ public class PeerManagerTest { SeedNode seedNode = new SeedNode("test_dummy_dir"); latch = new CountDownLatch(1); - seedNode.createAndStartP2PService(new NodeAddress("localhost", port), useLocalhost, 2, true, seedNodes, new P2PServiceListener() { + seedNode.createAndStartP2PService(new NodeAddress("localhost", port), MAX_CONNECTIONS, useLocalhost, 2, true, seedNodes, new P2PServiceListener() { @Override public void onRequestingDataCompleted() { latch.countDown();