forked from I2P_Developers/i2p.i2p
i2ptunnel: Retry accept after router soft restart (ticket #2003)
This sends the router restart indication from I2CP router side to client side to streaming to I2PTunnelServer via a new streaming exception.
This commit is contained in:
@@ -37,6 +37,7 @@ import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.client.streaming.RouterRestartException;
|
||||
import net.i2p.crypto.SigType;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.Hash;
|
||||
@@ -554,8 +555,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
I2PServerSocket ci2pss = i2pss;
|
||||
if (ci2pss == null)
|
||||
throw new I2PException("I2PServerSocket closed");
|
||||
// returns non-null as of 0.9.17
|
||||
i2ps = ci2pss.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
if (_usePool) {
|
||||
try {
|
||||
_executor.execute(new Handler(i2ps));
|
||||
@@ -573,10 +574,19 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
// use only for standard servers that can't get slowlorissed! Not for http or irc
|
||||
blockingHandle(i2ps);
|
||||
}
|
||||
} catch (RouterRestartException rre) {
|
||||
// Delay and loop if router is soft restarting
|
||||
_log.logAlways(Log.WARN, "Waiting for router restart");
|
||||
if (i2ps != null) try { i2ps.close(); } catch (IOException ioe) {}
|
||||
try {
|
||||
Thread.sleep(2*60*1000);
|
||||
} catch (InterruptedException ie) {}
|
||||
// This should be the same as before, but we have to call getServerSocket()
|
||||
// so sockMgr will call ConnectionManager.setAllowIncomingConnections(true) again
|
||||
i2pss = sockMgr.getServerSocket();
|
||||
} catch (I2PException ipe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
|
||||
// TODO delay and loop if internal router is soft restarting?
|
||||
open = false;
|
||||
if (i2ps != null) try { i2ps.close(); } catch (IOException ioe) {}
|
||||
break;
|
||||
|
||||
@@ -29,6 +29,7 @@ public interface I2PServerSocket {
|
||||
*
|
||||
* @throws I2PException if there is a problem with reading a new socket
|
||||
* from the data available (e.g. the I2PSession is closed)
|
||||
* @throws RouterRestartException (extends I2PException) if the router is apparently restarting, since 0.9.34
|
||||
* @throws ConnectException if the I2PServerSocket is closed, or if interrupted.
|
||||
* Not actually thrown through 0.9.16; thrown as of 0.9.17
|
||||
* @throws SocketTimeoutException if a timeout was previously set with setSoTimeout and the timeout has been reached.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
|
||||
/**
|
||||
* An I2PException thrown from I2PServerSocket.accept()
|
||||
* when the router is restarting.
|
||||
*
|
||||
* @since 0.9.34
|
||||
*/
|
||||
public class RouterRestartException extends I2PException {}
|
||||
@@ -6,6 +6,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.RouterRestartException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
@@ -27,6 +28,7 @@ class ConnectionHandler {
|
||||
private final SimpleTimer2 _timer;
|
||||
private volatile boolean _active;
|
||||
private int _acceptTimeout;
|
||||
private boolean _restartPending;
|
||||
|
||||
/** max time after receiveNewSyn() and before the matched accept() */
|
||||
private static final int DEFAULT_ACCEPT_TIMEOUT = 3*1000;
|
||||
@@ -48,14 +50,27 @@ class ConnectionHandler {
|
||||
_acceptTimeout = DEFAULT_ACCEPT_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* The router told us it's going to restart.
|
||||
* Call instead of setActive(false).
|
||||
*
|
||||
* @since 0.9.34
|
||||
*/
|
||||
public synchronized void setRestartPending() {
|
||||
_restartPending = true;
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
public synchronized void setActive(boolean active) {
|
||||
// FIXME active=false this only kills for one thread in accept()
|
||||
// if there are more, they won't get a poison packet.
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("setActive(" + active + ") called, previously " + _active, new Exception("I did it"));
|
||||
// if starting, clear any old poison
|
||||
if (active && !_active)
|
||||
if (active && !_active) {
|
||||
_restartPending = false;
|
||||
_synQueue.clear();
|
||||
}
|
||||
boolean wasActive = _active;
|
||||
_active = active;
|
||||
if (wasActive && !active) {
|
||||
@@ -116,12 +131,13 @@ class ConnectionHandler {
|
||||
* than 1ms, wait indefinitely)
|
||||
* @return connection received. Prior to 0.9.17, or null if there was a timeout or the
|
||||
* handler was shut down. As of 0.9.17, never null.
|
||||
* @throws RouterRestartException (extends I2PException) if the router is apparently restarting, since 0.9.34
|
||||
* @throws ConnectException since 0.9.17, returned null before;
|
||||
* if the I2PServerSocket is closed, or if interrupted.
|
||||
* @throws SocketTimeoutException since 0.9.17, returned null before;
|
||||
* if a timeout was previously set with setSoTimeout and the timeout has been reached.
|
||||
*/
|
||||
public Connection accept(long timeoutMs) throws ConnectException, SocketTimeoutException {
|
||||
public Connection accept(long timeoutMs) throws RouterRestartException, ConnectException, SocketTimeoutException {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Accept("+ timeoutMs+") called");
|
||||
|
||||
@@ -137,6 +153,8 @@ class ConnectionHandler {
|
||||
break;
|
||||
sendReset(packet);
|
||||
}
|
||||
if (_restartPending)
|
||||
throw new RouterRestartException();
|
||||
throw new ConnectException("ServerSocket closed");
|
||||
}
|
||||
|
||||
@@ -174,8 +192,11 @@ class ConnectionHandler {
|
||||
}
|
||||
|
||||
if (syn != null) {
|
||||
if (syn.getOptionalDelay() == PoisonPacket.POISON_MAX_DELAY_REQUEST)
|
||||
if (syn.getOptionalDelay() == PoisonPacket.POISON_MAX_DELAY_REQUEST) {
|
||||
if (_restartPending)
|
||||
throw new RouterRestartException();
|
||||
throw new ConnectException("ServerSocket closed");
|
||||
}
|
||||
|
||||
// deal with forged / invalid syn packets in _manager.receiveConnection()
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ class I2PServerSocketFull implements I2PServerSocket {
|
||||
*
|
||||
* @throws I2PException if there is a problem with reading a new socket
|
||||
* from the data available (e.g. the I2PSession is closed)
|
||||
* @throws RouterRestartException (extends I2PException) if the router is apparently restarting, since 0.9.34
|
||||
* @throws ConnectException if the I2PServerSocket is closed, or if interrupted.
|
||||
* Not actually thrown through 0.9.16; thrown as of 0.9.17
|
||||
* @throws SocketTimeoutException if a timeout was previously set with setSoTimeout and the timeout has been reached.
|
||||
|
||||
@@ -350,6 +350,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
|
||||
*
|
||||
* @return connected I2PSocket, or null through 0.9.16, non-null as of 0.9.17
|
||||
* @throws I2PException if session is closed
|
||||
* @throws RouterRestartException (extends I2PException) if the router is apparently restarting, since 0.9.34
|
||||
* @throws ConnectException (since 0.9.17; I2PServerSocket interface always declared it)
|
||||
* @throws SocketTimeoutException if a timeout was previously set with setSoTimeout and the timeout has been reached.
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ class MessageHandler implements I2PSessionMuxedListener {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private final Set<I2PSocketManager.DisconnectListener> _listeners;
|
||||
private boolean _restartPending;
|
||||
|
||||
public MessageHandler(I2PAppContext ctx, ConnectionManager mgr) {
|
||||
_manager = mgr;
|
||||
@@ -104,7 +105,12 @@ class MessageHandler implements I2PSessionMuxedListener {
|
||||
_log.warn("I2PSession disconnected");
|
||||
_manager.disconnectAllHard();
|
||||
// kill anybody waiting in accept()
|
||||
_manager.getConnectionHandler().setActive(false);
|
||||
if (_restartPending) {
|
||||
_manager.getConnectionHandler().setRestartPending();
|
||||
_restartPending = false;
|
||||
} else {
|
||||
_manager.getConnectionHandler().setActive(false);
|
||||
}
|
||||
|
||||
for (I2PSocketManager.DisconnectListener lsnr : _listeners) {
|
||||
lsnr.sessionDisconnected();
|
||||
@@ -120,8 +126,9 @@ class MessageHandler implements I2PSessionMuxedListener {
|
||||
* @param error the actual error
|
||||
*/
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
_restartPending = message.contains("restart");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("error occurred: " + message + "- " + error.getMessage(), error);
|
||||
_log.warn("error occurred: " + message, error);
|
||||
//_manager.disconnectAllHard();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class DisconnectMessageHandler extends HandlerImpl {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
String reason = ((DisconnectMessage)message).getReason();
|
||||
session.propogateError(reason, new I2PSessionException("Disconnect Message received"));
|
||||
session.propogateError(reason, new I2PSessionException("Disconnect Message received: " + reason));
|
||||
session.destroySession(false);
|
||||
if (reason.contains("restart")) {
|
||||
Thread t = new I2PAppThread(new Reconnector(session), "Reconnect " + session, true);
|
||||
@@ -47,7 +47,7 @@ class DisconnectMessageHandler extends HandlerImpl {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
try { Thread.sleep(40*1000); } catch (InterruptedException ie) {}
|
||||
_session.reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
2018-02-18 zzz
|
||||
* i2ptunnel: Retry accept after router soft restart (ticket #2003)
|
||||
|
||||
2018-02-17 zzz
|
||||
* Console: Number formatting tweaks (ticket #1913)
|
||||
* i2psnark: folder.js cleanup (ticket #2168, PR #14)
|
||||
* i2ptunnel: Close sockets in finally{}
|
||||
* SusiMail: Fix mail save truncation
|
||||
|
||||
2018-02-16 zzz
|
||||
* i2psnark: Fix NPE on torrent not found (ticket #2167)
|
||||
* i2ptunnel: Change POST throttle response to 429
|
||||
|
||||
@@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 6;
|
||||
public final static long BUILD = 7;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
||||
Reference in New Issue
Block a user