From ce3db7ed9f2a68b8847e4bec0896050a72d2ca9c Mon Sep 17 00:00:00 2001 From: zzz <zzz@i2pmail.org> Date: Sat, 6 Feb 2021 10:54:43 -0500 Subject: [PATCH] Util: EepGet timeout fixes part 1 (WIP) SocketTimeout fix for total timeout remaining less than inactivity timeout SocketTimeout javadoc fixes EepHead check for null SocketTimeout, javadoc fixes --- core/java/src/net/i2p/util/EepHead.java | 16 +++-- core/java/src/net/i2p/util/SocketTimeout.java | 63 +++++++++++++++---- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/core/java/src/net/i2p/util/EepHead.java b/core/java/src/net/i2p/util/EepHead.java index 8a01f552d2..692f451e57 100644 --- a/core/java/src/net/i2p/util/EepHead.java +++ b/core/java/src/net/i2p/util/EepHead.java @@ -163,7 +163,9 @@ public class EepHead extends EepGet { " (use -c or -p :0 for no proxy)"); } - /** return true if the URL was completely retrieved */ + /** + * @param timeout may be null as of 0.9.49 + */ @Override protected void doFetch(SocketTimeout timeout) throws IOException { _aborted = false; @@ -171,11 +173,13 @@ public class EepHead extends EepGet { if (_aborted) throw new IOException("Timed out reading the HTTP headers"); - timeout.resetTimer(); - if (_fetchInactivityTimeout > 0) - timeout.setInactivityTimeout(_fetchInactivityTimeout); - else - timeout.setInactivityTimeout(60*1000); + if (timeout != null) { + timeout.resetTimer(); + if (_fetchInactivityTimeout > 0) + timeout.setInactivityTimeout(_fetchInactivityTimeout); + else + timeout.setInactivityTimeout(60*1000); + } // Should we even follow redirects for HEAD? if (_redirectLocation != null) { diff --git a/core/java/src/net/i2p/util/SocketTimeout.java b/core/java/src/net/i2p/util/SocketTimeout.java index 5b6df3a6ab..5beed69631 100644 --- a/core/java/src/net/i2p/util/SocketTimeout.java +++ b/core/java/src/net/i2p/util/SocketTimeout.java @@ -5,12 +5,20 @@ import java.net.Socket; import java.util.Date; /** - * This should be deprecated. - * It is only used by EepGet and Syndie. + * Implements one or two timers; one for inactivity, that is reset by resetTimer(), + * and optionally, a total time since instantiation, that is configured by setTotalTimeoutPeriod(). + * + * On timer expiration, this will close a provided socket, and/or run a configured job. + * + * Deprecated for external use. + * It is only used by EepGet, its subclasses, and Syndie. + * Take care not to break Syndie. * The only advantage seems to be a total timeout period, which is the second * argument to EepGet.fetch(headerTimeout, totalTimeout, inactivityTimeout), * which is most likely always set to -1. * + * Not for use by plugins or external applications, subject to change. + * * Use socket.setsotimeout instead? */ public class SocketTimeout extends SimpleTimer2.TimedEvent { @@ -22,23 +30,31 @@ public class SocketTimeout extends SimpleTimer2.TimedEvent { private volatile boolean _cancelled; private volatile Runnable _command; + /** + * @param delay greater than zero + */ public SocketTimeout(long delay) { this(null, delay); } + /** + * If socket is non-null, or is set later by setSocket(), + * it will be closed when the timer expires. + * + * @param socket may be null + * @param delay greater than zero + */ public SocketTimeout(Socket socket, long delay) { super(SimpleTimer2.getInstance()); _inactivityDelay = delay; _targetSocket = socket; - _cancelled = false; _lastActivity = _startTime = System.currentTimeMillis(); - _totalTimeoutTime = -1; schedule(delay); } public void timeReached() { if (_cancelled) return; - - if ( ( (_totalTimeoutTime > 0) && (_totalTimeoutTime <= System.currentTimeMillis()) ) || - (_inactivityDelay + _lastActivity <= System.currentTimeMillis()) ) { + long now = System.currentTimeMillis(); + if ((_totalTimeoutTime > 0 && _totalTimeoutTime <= now) || + (_inactivityDelay + _lastActivity <= now)) { if (_targetSocket != null) { try { if (!_targetSocket.isClosed()) @@ -46,8 +62,12 @@ public class SocketTimeout extends SimpleTimer2.TimedEvent { } catch (IOException ioe) {} } if (_command != null) _command.run(); - } else { - schedule(_inactivityDelay); + } else { + if (_totalTimeoutTime > 0) { + schedule(Math.min(_inactivityDelay, _totalTimeoutTime - now)); + } else { + schedule(_inactivityDelay); + } } } @@ -61,17 +81,38 @@ public class SocketTimeout extends SimpleTimer2.TimedEvent { return super.cancel(); } + /** + * If non-null, will be closed when the timer expires. + */ public void setSocket(Socket s) { _targetSocket = s; } + + /** + * Call when there is activity + */ public void resetTimer() { _lastActivity = System.currentTimeMillis(); } - public void setInactivityTimeout(long timeout) { _inactivityDelay = timeout; } + /** + * Changes the delay provided in the constructor + * + * @param delay greater than zero + */ + public void setInactivityTimeout(long delay) { _inactivityDelay = delay; } + + /** + * If greater than zero, must be greater than the inactivity timeout. + * + * @param timeoutPeriod Time since constructed, or less than or equal to zero to disable + */ public void setTotalTimeoutPeriod(long timeoutPeriod) { if (timeoutPeriod > 0) _totalTimeoutTime = _startTime + timeoutPeriod; else - _totalTimeoutTime = -1; + _totalTimeoutTime = 0; } + /** + * If non-null, will be run when the timer expires. + */ public void setTimeoutCommand(Runnable job) { _command = job; } @Override -- GitLab