close connecting sockets and interrupt read thread on shutdown

This commit is contained in:
Craig Raw 2022-11-16 08:16:56 +02:00
parent a05fcba6d9
commit 0260a12663
10 changed files with 61 additions and 32 deletions

View file

@ -944,6 +944,8 @@ public class AppController implements Initializable {
if(AppServices.isConnected()) { if(AppServices.isConnected()) {
return "Connected to " + Config.get().getServerDisplayName() + (currentBlockHeight != null ? " at height " + currentBlockHeight : "") + return "Connected to " + Config.get().getServerDisplayName() + (currentBlockHeight != null ? " at height " + currentBlockHeight : "") +
(Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? "\nWarning! You are connected to a public server and sharing your transaction data with it.\nFor better privacy, consider using your own Bitcoin Core node or private Electrum server." : ""); (Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? "\nWarning! You are connected to a public server and sharing your transaction data with it.\nFor better privacy, consider using your own Bitcoin Core node or private Electrum server." : "");
} else if(AppServices.isConnecting()) {
return "Connecting...";
} }
return "Disconnected"; return "Disconnected";

View file

@ -1139,10 +1139,12 @@ public class AppServices {
@Subscribe @Subscribe
public void requestDisconnect(RequestDisconnectEvent event) { public void requestDisconnect(RequestDisconnectEvent event) {
onlineProperty.set(false); onlineProperty.set(false);
//Ensure services don't try to reconnect //Ensure services don't try to reconnect later
connectionService.cancel(); Platform.runLater(() -> {
ratesService.cancel(); connectionService.cancel();
versionCheckService.cancel(); ratesService.cancel();
versionCheckService.cancel();
});
} }
@Subscribe @Subscribe

View file

@ -1063,6 +1063,7 @@ public class ElectrumServer {
private final ReentrantLock bwtStartLock = new ReentrantLock(); private final ReentrantLock bwtStartLock = new ReentrantLock();
private final Condition bwtStartCondition = bwtStartLock.newCondition(); private final Condition bwtStartCondition = bwtStartLock.newCondition();
private Throwable bwtStartException; private Throwable bwtStartException;
private boolean shutdown;
public ConnectionService() { public ConnectionService() {
this(true); this(true);
@ -1195,7 +1196,7 @@ public class ElectrumServer {
} }
public boolean isConnecting() { public boolean isConnecting() {
return isRunning() && Config.get().getServerType() == ServerType.BITCOIN_CORE && bwt.isRunning() && !bwt.isReady(); return isRunning() && firstCall && (Config.get().getServerType() != ServerType.BITCOIN_CORE || (bwt.isRunning() && !bwt.isReady()));
} }
public boolean isConnectionRunning() { public boolean isConnectionRunning() {
@ -1203,7 +1204,11 @@ public class ElectrumServer {
} }
public boolean isConnected() { public boolean isConnected() {
return isRunning() && (Config.get().getServerType() != ServerType.BITCOIN_CORE || (bwt.isRunning() && bwt.isReady())); return isRunning() && !firstCall && (Config.get().getServerType() != ServerType.BITCOIN_CORE || (bwt.isRunning() && bwt.isReady()));
}
public boolean isShutdown() {
return shutdown;
} }
@Override @Override
@ -1219,6 +1224,11 @@ public class ElectrumServer {
} }
private void shutdown() { private void shutdown() {
shutdown = true;
if(reader != null && reader.isAlive()) {
reader.interrupt();
}
if(Config.get().getServerType() == ServerType.BITCOIN_CORE && bwt.isRunning()) { if(Config.get().getServerType() == ServerType.BITCOIN_CORE && bwt.isRunning()) {
Bwt.DisconnectionService disconnectionService = bwt.getDisconnectionService(); Bwt.DisconnectionService disconnectionService = bwt.getDisconnectionService();
disconnectionService.setOnSucceeded(workerStateEvent -> { disconnectionService.setOnSucceeded(workerStateEvent -> {

View file

@ -29,13 +29,11 @@ public class ProxyTcpOverTlsTransport extends TcpOverTlsTransport {
} }
@Override @Override
protected Socket createSocket() throws IOException { protected void createSocket() throws IOException {
InetSocketAddress proxyAddr = new InetSocketAddress(proxy.getHost(), proxy.getPortOrDefault(DEFAULT_PROXY_PORT)); InetSocketAddress proxyAddr = new InetSocketAddress(proxy.getHost(), proxy.getPortOrDefault(DEFAULT_PROXY_PORT));
Socket underlying = new Socket(new Proxy(Proxy.Type.SOCKS, proxyAddr)); socket = new Socket(new Proxy(Proxy.Type.SOCKS, proxyAddr));
underlying.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(DEFAULT_PORT))); socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(DEFAULT_PORT)));
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(underlying, proxy.getHost(), proxy.getPortOrDefault(DEFAULT_PROXY_PORT), true); socket = sslSocketFactory.createSocket(socket, proxy.getHost(), proxy.getPortOrDefault(DEFAULT_PROXY_PORT), true);
startHandshake(sslSocket); startHandshake((SSLSocket)socket);
return sslSocket;
} }
} }

View file

@ -9,7 +9,7 @@ import javax.net.ssl.*;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.InetSocketAddress;
import java.security.*; import java.security.*;
import java.security.cert.*; import java.security.cert.*;
import java.security.cert.Certificate; import java.security.cert.Certificate;
@ -86,10 +86,10 @@ public class TcpOverTlsTransport extends TcpTransport {
return trustManagerFactory.getTrustManagers(); return trustManagerFactory.getTrustManagers();
} }
protected Socket createSocket() throws IOException { protected void createSocket() throws IOException {
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(server.getHost(), server.getPortOrDefault(DEFAULT_PORT)); socket = sslSocketFactory.createSocket();
startHandshake(sslSocket); socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(DEFAULT_PORT)));
return sslSocket; startHandshake((SSLSocket)socket);
} }
protected void startHandshake(SSLSocket sslSocket) throws IOException { protected void startHandshake(SSLSocket sslSocket) throws IOException {

View file

@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLHandshakeException;
import java.io.*; import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -36,7 +37,7 @@ public class TcpTransport implements CloseableTransport, TimeoutCounter {
protected final SocketFactory socketFactory; protected final SocketFactory socketFactory;
protected final int[] readTimeouts; protected final int[] readTimeouts;
private Socket socket; protected Socket socket;
private String response; private String response;
@ -231,7 +232,7 @@ public class TcpTransport implements CloseableTransport, TimeoutCounter {
public void connect() throws ServerException { public void connect() throws ServerException {
try { try {
socket = createSocket(); createSocket();
log.debug("Created " + socket); log.debug("Created " + socket);
socket.setSoTimeout(SOCKET_READ_TIMEOUT_MILLIS); socket.setSoTimeout(SOCKET_READ_TIMEOUT_MILLIS);
running = true; running = true;
@ -250,8 +251,9 @@ public class TcpTransport implements CloseableTransport, TimeoutCounter {
return socket != null && running && !closed; return socket != null && running && !closed;
} }
protected Socket createSocket() throws IOException { protected void createSocket() throws IOException {
return socketFactory.createSocket(server.getHost(), server.getPortOrDefault(DEFAULT_PORT)); socket = socketFactory.createSocket();
socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(DEFAULT_PORT)));
} }
public boolean isClosed() { public boolean isClosed() {

View file

@ -26,9 +26,10 @@ public class TorTcpOverTlsTransport extends TcpOverTlsTransport {
} }
@Override @Override
protected Socket createSocket() throws IOException { protected void createSocket() throws IOException {
TorTcpTransport torTcpTransport = new TorTcpTransport(server); TorTcpTransport torTcpTransport = new TorTcpTransport(server);
Socket socket = torTcpTransport.createSocket(); torTcpTransport.createSocket();
socket = torTcpTransport.socket;
try { try {
Field socketField = socket.getClass().getDeclaredField("socket"); Field socketField = socket.getClass().getDeclaredField("socket");
@ -41,9 +42,7 @@ public class TorTcpOverTlsTransport extends TcpOverTlsTransport {
log.error("Could not set socket connected status", e); log.error("Could not set socket connected status", e);
} }
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, server.getHost(), server.getPortOrDefault(DEFAULT_PORT), true); socket = sslSocketFactory.createSocket(socket, server.getHost(), server.getPortOrDefault(DEFAULT_PORT), true);
startHandshake(sslSocket); startHandshake((SSLSocket)socket);
return sslSocket;
} }
} }

View file

@ -19,11 +19,11 @@ public class TorTcpTransport extends TcpTransport {
} }
@Override @Override
protected Socket createSocket() throws IOException { protected void createSocket() throws IOException {
if(!AppServices.isTorRunning()) { if(!AppServices.isTorRunning()) {
throw new IllegalStateException("Can't create Tor socket, Tor is not running"); throw new IllegalStateException("Can't create Tor socket, Tor is not running");
} }
return new TorSocket(server.getHost(), server.getPort(), "sparrow"); socket = new TorSocket(server.getHost(), server.getPort(), "sparrow");
} }
} }

View file

@ -175,6 +175,9 @@ public class ServerPreferencesController extends PreferencesDetailController {
EventManager.get().register(this); EventManager.get().register(this);
getMasterController().closingProperty().addListener((observable, oldValue, newValue) -> { getMasterController().closingProperty().addListener((observable, oldValue, newValue) -> {
EventManager.get().unregister(this); EventManager.get().unregister(this);
if(connectionService != null && connectionService.isRunning()) {
connectionService.cancel();
}
}); });
Platform.runLater(this::setupValidation); Platform.runLater(this::setupValidation);
@ -360,7 +363,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
boolean isConnected = AppServices.isConnecting() || AppServices.isConnected(); boolean isConnected = AppServices.isConnecting() || AppServices.isConnected();
if(AppServices.isConnecting()) { if(Config.get().getServerType() == ServerType.BITCOIN_CORE && AppServices.isConnecting()) {
testResults.appendText("Connecting to server, please wait..."); testResults.appendText("Connecting to server, please wait...");
} }
@ -380,7 +383,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
editConnection.managedProperty().bind(editConnection.visibleProperty()); editConnection.managedProperty().bind(editConnection.visibleProperty());
editConnection.setVisible(isConnected); editConnection.setVisible(isConnected);
editConnection.setDisable(AppServices.isConnecting()); editConnection.setDisable(Config.get().getServerType() == ServerType.BITCOIN_CORE && AppServices.isConnecting());
editConnection.setOnAction(event -> { editConnection.setOnAction(event -> {
EventManager.get().post(new RequestDisconnectEvent()); EventManager.get().post(new RequestDisconnectEvent());
setFieldsEditable(true); setFieldsEditable(true);
@ -536,6 +539,11 @@ public class ServerPreferencesController extends PreferencesDetailController {
}); });
connectionService.setOnFailed(workerStateEvent -> { connectionService.setOnFailed(workerStateEvent -> {
EventManager.get().unregister(connectionService); EventManager.get().unregister(connectionService);
if(connectionService.isShutdown()) {
connectionService.cancel();
return;
}
showConnectionFailure(workerStateEvent.getSource().getException()); showConnectionFailure(workerStateEvent.getSource().getException());
connectionService.cancel(); connectionService.cancel();

View file

@ -95,6 +95,9 @@ public class ServerTestDialog extends DialogWindow {
close(); close();
Platform.runLater(() -> { Platform.runLater(() -> {
if(connectionService != null && connectionService.isRunning()) {
connectionService.cancel();
}
if(Config.get().getMode() == Mode.ONLINE && !(AppServices.isConnecting() || AppServices.isConnected())) { if(Config.get().getMode() == Mode.ONLINE && !(AppServices.isConnecting() || AppServices.isConnected())) {
EventManager.get().post(new RequestConnectEvent()); EventManager.get().post(new RequestConnectEvent());
} }
@ -145,6 +148,11 @@ public class ServerTestDialog extends DialogWindow {
}); });
connectionService.setOnFailed(workerStateEvent -> { connectionService.setOnFailed(workerStateEvent -> {
EventManager.get().unregister(connectionService); EventManager.get().unregister(connectionService);
if(connectionService.isShutdown()) {
connectionService.cancel();
return;
}
showConnectionFailure(workerStateEvent.getSource().getException()); showConnectionFailure(workerStateEvent.getSource().getException());
connectionService.cancel(); connectionService.cancel();
}); });