From 48afd8543e6f0e9a81b8abdc0d94cfe8bf24a666 Mon Sep 17 00:00:00 2001 From: knaccc Date: Mon, 4 Feb 2019 04:13:23 +0000 Subject: [PATCH] shutdown fixes --- .../getmonero/i2p/zero/gui/Controller.java | 6 ++-- .../src/org/getmonero/i2p/zero/gui/Gui.java | 2 +- .../src/org/getmonero/i2p/zero/Main.java | 2 +- .../org/getmonero/i2p/zero/RouterWrapper.java | 16 +++++----- .../org/getmonero/i2p/zero/TunnelControl.java | 30 +++++++++++-------- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java index 10d48f5..1672469 100644 --- a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java +++ b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java @@ -108,7 +108,7 @@ public class Controller { tunnelRemoveButton.setOnAction(e->{ Tunnel t = tunnelsTableView.getSelectionModel().getSelectedItem(); getRouterWrapper().getTunnelControl().getTunnelList().removeTunnel(t); - t.destroy(); + t.destroy(false); tunnelRemoveButton.setDisable(true); }); @@ -188,7 +188,7 @@ public class Controller { getEepSiteTunnel().start(); } else { - getEepSiteTunnel().destroy(); + getEepSiteTunnel().destroy(false); } } }); @@ -247,7 +247,7 @@ public class Controller { else { masterToggle.setImage(new Image("org/getmonero/i2p/zero/gui/toggle-off.png")); statusLabel.setVisible(false); - routerWrapper.stop(); + routerWrapper.stop(false); tunnelTableList.clear(); tunnelAddButton.setDisable(true); } diff --git a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java index bdd08f1..d9ec6c1 100644 --- a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java +++ b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java @@ -61,7 +61,7 @@ public class Gui extends Application { @Override public void stop() throws Exception { isStopping = true; - if(controller.getRouterWrapper().isStarted()) controller.getRouterWrapper().stop(); + if(controller.getRouterWrapper().isStarted()) controller.getRouterWrapper().stop(true); } public boolean isStopping() { diff --git a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java index 30352ee..e81991a 100644 --- a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java +++ b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java @@ -37,7 +37,7 @@ public class Main { RouterWrapper routerWrapper = new RouterWrapper(p); routerWrapper.start(); - Runtime.getRuntime().addShutdownHook(new Thread(()->routerWrapper.stop())); + Runtime.getRuntime().addShutdownHook(new Thread(()->routerWrapper.stop(true))); } diff --git a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java index f00f57d..a10502b 100644 --- a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java +++ b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java @@ -98,18 +98,20 @@ public class RouterWrapper { } - public void stop() { + public void stop(boolean fastStop) { if(!started) return; started = false; - tunnelControl.stop(); + tunnelControl.stop(fastStop); System.out.println("I2P router will shut down gracefully"); router.shutdownGracefully(); - // don't wait more than 2 seconds for shutdown. If tunnels are still opening, they can pause for up to 20 seconds, which is too long - new Thread(()->{ - try { Thread.sleep(2000); } catch (InterruptedException e) {} - System.exit(0); - }).start(); + if(fastStop) { + // don't wait more than 2 seconds for shutdown. If tunnels are still opening, they can pause for up to 20 seconds, which is too long + new Thread(() -> { + try { Thread.sleep(2000); } catch (InterruptedException e) {} + System.exit(0); + }).start(); + } } long lastTriggerTimestamp = 0; diff --git a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java index d921ef4..38239c3 100644 --- a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java +++ b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java @@ -184,11 +184,15 @@ public class TunnelControl implements Runnable { return tunnel==null ? "opening" : "open"; } public boolean getEnabled() { return enabled; } - public void destroy() { + public void destroy(boolean fastDestroy) { new Thread(()->{ - // subsequent line commented out, because the tunnels will sleep for 20 seconds at a time, which is too long - // while(tunnel==null) { try { Thread.sleep(100); } catch (InterruptedException e) {} } // wait for tunnel to be established before closing it - if(tunnel!=null) tunnel.runClose(new String[]{"forced", "all"}, tunnel); + // tunnels may sleep for 20 seconds while waiting to open. we may be in a hurry + if(!fastDestroy) { + while(tunnel==null) { try { Thread.sleep(100); } catch (InterruptedException e) {} } // wait for tunnel to be established before closing it + } + if(tunnel!=null) { + tunnel.runClose(new String[]{"forced", "all"}, tunnel); + } }).start(); } } @@ -300,10 +304,10 @@ public class TunnelControl implements Runnable { } @Override - public void destroy() { + public void destroy(boolean fastDestroy) { try { server.stop(); - super.destroy(); + super.destroy(fastDestroy); } catch (Exception e) { throw new RuntimeException(e); @@ -508,7 +512,7 @@ public class TunnelControl implements Runnable { case "server.destroy": { String dest = args[1]; tunnelList.getTunnelsCopyStream().filter(t -> t.getType().equals("server") && ((ServerTunnel) t).dest.equals(dest)).forEach(t -> { - t.destroy(); + t.destroy(false); tunnelList.removeTunnel(t); }); out.println("OK"); @@ -536,7 +540,7 @@ public class TunnelControl implements Runnable { case "client.destroy": { int port = Integer.parseInt(args[1]); tunnelList.getTunnelsCopyStream().filter(t->t.getType().equals("client") && ((ClientTunnel) t).port == port).forEach(t->{ - t.destroy(); + t.destroy(false); tunnelList.removeTunnel(t); }); out.println("OK"); @@ -561,7 +565,7 @@ public class TunnelControl implements Runnable { case "socks.destroy": { int port = Integer.parseInt(args[1]); tunnelList.getTunnelsCopyStream().filter(t -> t.getType().equals("socks") && ((SocksTunnel) t).port == port).forEach(t -> { - t.destroy(); + t.destroy(false); tunnelList.removeTunnel(t); }); out.println("OK"); @@ -585,7 +589,7 @@ public class TunnelControl implements Runnable { case "http.destroy": { int port = Integer.parseInt(args[1]); tunnelList.getTunnelsCopyStream().filter(t -> t.getType().equals("http") && ((SocksTunnel) t).port == port).forEach(t -> { - t.destroy(); + t.destroy(false); tunnelList.removeTunnel(t); }); out.println("OK"); @@ -601,7 +605,7 @@ public class TunnelControl implements Runnable { case "all.destroy": { tunnelList.getTunnelsCopyStream().forEach(t -> { - t.destroy(); + t.destroy(false); tunnelList.removeTunnel(t); }); out.println("OK"); @@ -648,10 +652,10 @@ public class TunnelControl implements Runnable { } - public void stop() { + public void stop(boolean fastStop) { stopping = true; try { - getTunnelList().tunnels.forEach(TunnelControl.Tunnel::destroy); + getTunnelList().tunnels.forEach(t->t.destroy(fastStop)); controlServerSocket.close(); } catch (Exception e) {