Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection handling fixes #31

Merged
16 changes: 16 additions & 0 deletions core/src/main/java/org/bitcoinj/core/PeerAddress.java
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,22 @@ public boolean equals(Object o) {

}

public boolean equalsIgnoringMetadata(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

PeerAddress that = (PeerAddress) o;

if (port != that.port) return false;
// Don't compare the time field
// if (time != that.time) return false;
if (addr != null ? !addr.equals(that.addr) : that.addr != null) return false;
if (hostname != null ? !hostname.equals(that.hostname) : that.hostname != null) return false;
// Don't compare the services field
// return !(services != null ? !services.equals(that.services) : that.services != null);
return true;
}

@Override
public int hashCode() {
int result = addr != null ? addr.hashCode() : 0;
Expand Down
47 changes: 22 additions & 25 deletions core/src/main/java/org/bitcoinj/core/PeerGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -621,16 +621,15 @@ public void go() {
long delay = retryTime - now;
log.info("Waiting {} msec before next connect attempt {}", delay, addrToTry == null ? "" : "to " + addrToTry);

if (!isAlreadyAdded(addrToTry))
inactives.add(addrToTry);
inactives.add(addrToTry);
executor.schedule(this, delay, TimeUnit.MILLISECONDS);
return;
}

// BitcoinJ gets too many connections after a connection loss and reconnect as it adds up a lot of
// potential candidates and then try to connect to all of those when getting connection again.
// A check for maxConnections is required to not exceed connections.
if(pendingPeers.size() + peers.size() < maxConnections)
if (countConnectedAndPendingPeers() < getMaxConnections())
connectTo(addrToTry, false, vConnectTimeoutMillis);
} finally {
lock.unlock();
Expand All @@ -641,17 +640,6 @@ public void go() {
}
};

private boolean isAlreadyAdded(PeerAddress peerAddress) {
boolean isAlreadyAdded = false;
for (PeerAddress a : inactives) {
if (a.getHostname() != null && a.getHostname().equals(peerAddress.getHostname())) {
isAlreadyAdded = true;
break;
}
}
return isAlreadyAdded;
}

private void triggerConnections() {
// Run on a background thread due to the need to potentially retry and back off in the background.
if (!executor.isShutdown())
Expand Down Expand Up @@ -1048,13 +1036,18 @@ private boolean addInactive(PeerAddress peerAddress) {
lock.lock();
try {
// Deduplicate
if (backoffMap.containsKey(peerAddress)) {
boolean backoffMapContainsPeerAddress = false;
for (PeerAddress a : backoffMap.keySet()) {
if (a.equalsIgnoringMetadata(peerAddress)) {
backoffMapContainsPeerAddress = true;
break;
}
}
if (backoffMapContainsPeerAddress) {
return false;
}
backoffMap.put(peerAddress, new ExponentialBackoff(peerBackoffParams));

if (!isAlreadyAdded(peerAddress))
inactives.offer(peerAddress);
inactives.offer(peerAddress);

return true;
} finally {
Expand Down Expand Up @@ -1249,6 +1242,7 @@ public ListenableFuture stopAsync() {
public void run() {
try {
log.info("Stopping ...");
setDownloadPeer(null);
// Blocking close of all sockets.
channels.stopAsync();
channels.awaitTerminated();
Expand Down Expand Up @@ -1848,12 +1842,6 @@ protected void handlePeerDeath(final Peer peer, @Nullable Throwable exception) {
if (newDownloadPeer != null) {
setDownloadPeer(newDownloadPeer);

// When using BlockingClient we get errors at shutdown caused by
// startBlockChainDownloadFromPeer()
// We add another check to terminate here if we have been shut down already
if (!isRunning())
return;

if (downloadListener != null) {
startBlockChainDownloadFromPeer(newDownloadPeer);
}
Expand All @@ -1872,7 +1860,16 @@ protected void handlePeerDeath(final Peer peer, @Nullable Throwable exception) {
} else {
backoffMap.get(address).trackFailure();
// Put back on inactive list
inactives.offer(address);
boolean inactiveContainsAddress = false;
for (PeerAddress a : inactives) {
if (a.equalsIgnoringMetadata(address)) {
inactiveContainsAddress = true;
break;
}
}
if (!inactiveContainsAddress) {
inactives.offer(address);
}
}

if (numPeers < getMaxConnections()) {
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/java/org/bitcoinj/net/BlockingClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,11 @@ public synchronized void writeBytes(byte[] message) throws IOException {
OutputStream stream = socket.getOutputStream();
stream.write(message);
stream.flush();
} else {
log.warn("Attempted to write to a closed socket.");
}
} catch (IOException e) {
if(!(e instanceof SocketException && e.toString().equals("Socket is closed")))
log.error("Error writing message to connection, closing connection", e);
log.error("Error writing message to connection, closing connection", e);
closeConnection();
throw e;
}
Expand Down