diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index ac764961aa460deb441d25cf5dfb4b038af08730..93fb6412147fec7f76f090ec76abfb4287d827f5 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -74,6 +74,8 @@ public class I2PTunnel implements Logging, EventDispatcher { public static String host = System.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1"); public static String listenHost = host; + public static long readTimeout = -1; + private static final String nocli_args[] = { "-nocli", "-die"}; private List tasks = new ArrayList(); @@ -201,6 +203,8 @@ public class I2PTunnel implements Logging, EventDispatcher { runConfig(args, l); } else if ("listen_on".equals(cmdname)) { runListenOn(args, l); + } else if ("read_timeout".equals(cmdname)) { + runReadTimeout(args, l); } else if ("genkeys".equals(cmdname)) { runGenKeys(args, l); } else if ("gentextkeys".equals(cmdname)) { @@ -235,6 +239,7 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("Command list:"); l.log("config <i2phost> <i2pport>"); l.log("listen_on <ip>"); + l.log("read_timeout <msecs>"); l.log("owndest yes|no"); l.log("ping <args>"); l.log("server <host> <port> <privkeyfile>"); @@ -291,10 +296,11 @@ public class I2PTunnel implements Logging, EventDispatcher { notifyEvent("serverTaskId", new Integer(-1)); return; } - I2PTunnelTask task; - task = new I2PTunnelServer(serverHost, portNum, privKeyFile, args[2], l, (EventDispatcher) this); - addtask(task); - notifyEvent("serverTaskId", new Integer(task.getId())); + I2PTunnelServer serv = new I2PTunnelServer(serverHost, portNum, privKeyFile, args[2], l, (EventDispatcher) this); + serv.setReadTimeout(readTimeout); + serv.startRunning(); + addtask(serv); + notifyEvent("serverTaskId", new Integer(serv.getId())); return; } else { l.log("server <host> <port> <privkeyfile>"); @@ -336,10 +342,11 @@ public class I2PTunnel implements Logging, EventDispatcher { return; } - I2PTunnelTask task; - task = new I2PTunnelServer(serverHost, portNum, args[2], l, (EventDispatcher) this); - addtask(task); - notifyEvent("serverTaskId", new Integer(task.getId())); + I2PTunnelServer serv = new I2PTunnelServer(serverHost, portNum, args[2], l, (EventDispatcher) this); + serv.setReadTimeout(readTimeout); + serv.startRunning(); + addtask(serv); + notifyEvent("serverTaskId", new Integer(serv.getId())); } else { l.log("textserver <host> <port> <privkey>"); l.log(" creates a server that sends all incoming data\n" + " of its destination to host:port."); @@ -510,7 +517,31 @@ public class I2PTunnel implements Logging, EventDispatcher { } else { l.log("listen_on <ip>"); l.log(" sets the interface to listen for the I2PClient."); + notifyEvent("listen_onResult", "error"); + } + } + + /** + * Specify the read timeout going to be used for newly-created I2PSockets + * + * Sets the event "read_timeoutResult" = "ok" or "error" after the interface has been specified + * + * @param args {hostname} + * @param l logger to receive events and output + */ + public void runReadTimeout(String args[], Logging l) { + if (args.length == 1) { + try { + readTimeout = Long.parseLong(args[0]); + } catch (NumberFormatException e) { + notifyEvent("read_timeoutResult", "error"); + } notifyEvent("listen_onResult", "ok"); + } else { + l.log("read_timeout <msecs>"); + l.log(" sets the read timeout (in milliseconds) for I2P connections\n" + +" Negative values will make the connections wait forever"); + notifyEvent("read_timeoutResult", "error"); } } @@ -1000,4 +1031,4 @@ public class I2PTunnel implements Logging, EventDispatcher { public Object waitEventValue(String n) { return _event.waitEventValue(n); } -} \ No newline at end of file +} diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java index ad2246ed4eca0829e44d4394c3fc3e2cedd44c64..b81ee71ca82795fc0961bb16173162cd331bfd8d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java @@ -6,6 +6,7 @@ package net.i2p.i2ptunnel; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Socket; import java.net.SocketException; @@ -116,7 +117,7 @@ public class I2PTunnelRunner extends I2PThread { _log.error("Interrupted", ex); } catch (IOException ex) { ex.printStackTrace(); - _log.error("Error forwarding", ex); + _log.debug("Error forwarding", ex); } finally { try { if (s != null) s.close(); @@ -163,11 +164,13 @@ public class I2PTunnelRunner extends I2PThread { } catch (SocketException ex) { // this *will* occur when the other threads closes the socket synchronized (finishLock) { - if (!finished) - _log.error("Error reading and writing", ex); - else - _log.warn("You may ignore this", ex); + if (!finished) { + _log.debug("Socket closed - error reading and writing", + ex); + } } + } catch (InterruptedIOException ex) { + _log.debug("Socket read timed out - closing StreamForwarder"); } catch (IOException ex) { if (!finished) _log.error("Error forwarding", ex); @@ -188,4 +191,4 @@ public class I2PTunnelRunner extends I2PThread { } } } -} \ No newline at end of file +} diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java index e3401ebd109bde15c70ce79ab197092d8166333d..a219b4e40049d0da4812a1f8b302631b7d2dc880 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java @@ -40,6 +40,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { private Logging l; + private long readTimeout = -1; + public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis) { super(host + ":" + port + " <- " + privData, notifyThis); ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData)); @@ -57,8 +59,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } } - public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, - EventDispatcher notifyThis) { + public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis) { super(host + ":" + port + " <- " + privkeyname, notifyThis); init(host, port, privData, privkeyname, l); } @@ -78,11 +79,37 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { l.log("Ready!"); notifyEvent("openServerResult", "ok"); open = true; + } + + /** + * Start running the I2PTunnelServer. + * + */ + public void startRunning() { Thread t = new I2PThread(this); t.setName("Server"); t.start(); } + /** + * Set the read idle timeout for newly-created connections (in + * milliseconds). After this time expires without data being reached from + * the I2P network, the connection itself will be closed. + */ + public void setReadTimeout(long ms) { + readTimeout = ms; + } + + /** + * Get the read idle timeout for newly-created connections (in + * milliseconds). + * + * @return The read timeout used for connections + */ + public long getReadTimeout() { + return readTimeout; + } + public boolean close(boolean forced) { if (!open) return true; synchronized (lock) { @@ -115,6 +142,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { //local is fast, so synchronously. Does not need that many //threads. try { + i2ps.setReadTimeout(readTimeout); Socket s = new Socket(remoteHost, remotePort); new I2PTunnelRunner(s, i2ps, slock, null); } catch (SocketException ex) {