From 3a8ce64c84b5473750286d4f7c00a8113db1a8ef Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 27 Mar 2015 14:16:41 +0000
Subject: [PATCH 1/4] I2PTunnel client-side locking fixes (ticket #815) Checkin
of patches from Oct. 2013, based on 0.9.8.1. Had some issues back then, and
not tested recently. Prop from i2p.i2p to follow.
---
.../java/src/net/i2p/i2ptunnel/I2PTunnel.java | 28 +-
.../net/i2p/i2ptunnel/I2PTunnelClient.java | 5 -
.../i2p/i2ptunnel/I2PTunnelClientBase.java | 254 +++++++++++-------
.../i2p/i2ptunnel/I2PTunnelConnectClient.java | 5 -
.../i2p/i2ptunnel/I2PTunnelHTTPClient.java | 4 -
.../i2p/i2ptunnel/TunnelControllerGroup.java | 2 +-
6 files changed, 168 insertions(+), 130 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
index 296691b9d..aafaadb9d 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
@@ -707,13 +707,13 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
if (portNum <= 0)
throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]);
- I2PTunnelTask task;
ownDest = !isShared;
try {
String privateKeyFile = null;
if (args.length >= 4)
privateKeyFile = args[3];
- task = new I2PTunnelClient(portNum, args[1], l, ownDest, this, this, privateKeyFile);
+ I2PTunnelClientBase task = new I2PTunnelClient(portNum, args[1], l, ownDest, this, this, privateKeyFile);
+ task.startRunning();
addtask(task);
notifyEvent("clientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -786,10 +786,10 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
}
- I2PTunnelTask task;
ownDest = !isShared;
try {
- task = new I2PTunnelHTTPClient(clientPort, l, ownDest, proxy, this, this);
+ I2PTunnelClientBase task = new I2PTunnelHTTPClient(clientPort, l, ownDest, proxy, this, this);
+ task.startRunning();
addtask(task);
notifyEvent("httpclientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -855,10 +855,10 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
}
- I2PTunnelTask task;
ownDest = !isShared;
try {
- task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, this, this);
+ I2PTunnelClientBase task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, this, this);
+ task.startRunning();
addtask(task);
} catch (IllegalArgumentException iae) {
String msg = "Invalid I2PTunnel configuration to create a CONNECT client connecting to the router at " + host + ':'+ port +
@@ -917,13 +917,13 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
}
- I2PTunnelTask task;
ownDest = !isShared;
try {
String privateKeyFile = null;
if (args.length >= 4)
privateKeyFile = args[3];
- task = new I2PTunnelIRCClient(_port, args[1], l, ownDest, this, this, privateKeyFile);
+ I2PTunnelClientBase task = new I2PTunnelIRCClient(_port, args[1], l, ownDest, this, this, privateKeyFile);
+ task.startRunning();
addtask(task);
notifyEvent("ircclientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -977,7 +977,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
ownDest = !isShared;
try {
- I2PTunnelTask task = new I2PSOCKSTunnel(_port, l, ownDest, this, this, null);
+ I2PTunnelClientBase task = new I2PSOCKSTunnel(_port, l, ownDest, this, this, null);
+ task.startRunning();
addtask(task);
notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -1024,7 +1025,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
if (args.length == 3)
privateKeyFile = args[2];
try {
- I2PTunnelTask task = new I2PSOCKSIRCTunnel(_port, l, ownDest, this, this, privateKeyFile);
+ I2PTunnelClientBase task = new I2PSOCKSIRCTunnel(_port, l, ownDest, this, this, privateKeyFile);
+ task.startRunning();
addtask(task);
notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -1437,9 +1439,11 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
*/
private void runPing(String allargs, Logging l) {
if (allargs.length() != 0) {
- I2PTunnelTask task;
// pings always use the main destination
- task = new I2Ping(allargs, l, false, this, this);
+ I2PTunnelTask task = new I2Ping(allargs, l, false, this, this);
+ // TODO
+ //I2PTunnelClientBase task = new I2Ping(allargs, l, false, this, this);
+ //task.startRunning();
addtask(task);
notifyEvent("pingTaskId", Integer.valueOf(task.getId()));
} else {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
index fa3bfb94e..e6aaa905b 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
@@ -32,11 +32,6 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
"Standard client on " + tunnel.listenHost + ':' + localPort,
tunnel, pkf);
- if (waitEventValue("openBaseClientResult").equals("error")) {
- notifyEvent("openClientResult", "error");
- return;
- }
-
StringTokenizer tok = new StringTokenizer(destinations, ", ");
dests = new ArrayList(1);
while (tok.hasMoreTokens()) {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index 0f52c8fbb..7c3be06b0 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -26,6 +26,7 @@ import java.util.concurrent.ThreadFactory;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
@@ -52,6 +53,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
protected Destination dest = null;
private int localPort;
+ private final String _handlerName;
private boolean listenerReady = false;
@@ -96,6 +98,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
chained = true;
sockMgr = sktMgr;
_clientId = clientId;
+ _handlerName = "chained";
this.localPort = localPort;
this.l = l;
_ownDest = true; // == ! shared client
@@ -111,31 +114,14 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
_executor = new CustomThreadPoolExecutor();
}
- Thread t = new I2PAppThread(this, "Client " + tunnel.listenHost + ':' + localPort);
- t.start();
- open = true;
- synchronized (this) {
- while (!listenerReady && open) {
- try {
- wait();
- } catch (InterruptedException e) {
- // ignore
- }
- }
- }
-
- if (open && listenerReady) {
- l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
- notifyEvent("openBaseClientResult", "ok");
- } else {
- l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs");
- notifyEvent("openBaseClientResult", "error");
- }
+ startup();
}
/**
* The main constructor.
- * This may take a LONG time if building and starting a new manager.
+ *
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
*
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -149,7 +135,9 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* Use this to build a client with a persistent private key.
- * This may take a LONG time if building and starting a new manager.
+ *
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
*
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @param pkf Path to the private key file, or null to generate a transient key
@@ -165,7 +153,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
this.localPort = localPort;
this.l = l;
_ownDest = ownDest; // == ! shared client
-
+ _handlerName = handlerName;
_context = tunnel.getContext();
_context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
@@ -194,53 +182,12 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
if (!dccEnabled)
tunnel.getClientOptions().setProperty("i2cp.dontPublishLeaseSet", "true");
- boolean openNow = !Boolean.parseBoolean(tunnel.getClientOptions().getProperty("i2cp.delayOpen"));
- if (openNow) {
- while (sockMgr == null) {
- verifySocketManager();
- if (sockMgr == null) {
- _log.error("Unable to connect to router and build tunnels for " + handlerName);
- // FIXME there is a loop in buildSocketManager(), do we really need another one here?
- // no matter, buildSocketManager() now throws an IllegalArgumentException
- try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
- }
- }
- // can't be null unless we limit the loop above
- //if (sockMgr == null) {
- // l.log("Invalid I2CP configuration");
- // throw new IllegalArgumentException("Socket manager could not be created");
- //}
- l.log("Tunnels ready for client: " + handlerName);
-
- } // else delay creating session until createI2PSocket() is called
-
- Thread t = new I2PAppThread(this);
- t.setName("Client " + _clientId);
- t.start();
- open = true;
- synchronized (this) {
- while (!listenerReady && open) {
- try {
- wait();
- } catch (InterruptedException e) {
- // ignore
- }
- }
- }
-
- if (open && listenerReady) {
- if (openNow)
- l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
- else
- l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort + ", delaying tunnel open until required");
- notifyEvent("openBaseClientResult", "ok");
- } else {
- l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs");
- notifyEvent("openBaseClientResult", "error");
- }
}
/**
+ * Create the manager if it doesn't exist, AND connect it to the router and
+ * build tunnels.
+ *
* Sets the this.sockMgr field if it is null, or if we want a new one.
* This may take a LONG time if building a new manager.
*
@@ -272,6 +219,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
this.sockMgr = getSocketManager();
}
}
+ connectManager();
}
/** this is ONLY for shared clients */
@@ -280,7 +228,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* This is ONLY for shared clients.
- * This may take a LONG time if building a new manager.
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
+ * Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -292,7 +241,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* This is ONLY for shared clients.
- * This may take a LONG time if building a new manager.
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
+ * Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -304,7 +254,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* This is ONLY for shared clients.
- * This may take a LONG time if building a new manager.
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
+ * Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -335,7 +286,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
/**
- * This may take a LONG time.
+ * For NON-SHARED clients (ownDest = true).
+ *
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
+ * Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -345,7 +299,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
return buildSocketManager(getTunnel(), this.privKeyFile, this.l);
}
/**
- * This may take a LONG time.
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
+ * Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -359,7 +314,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
private static final int MAX_RETRIES = 4;
/**
- * This may take a LONG time.
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
+ * Call verifySocketManager() for that.
*
* @param pkf absolute path or null
* @return non-null
@@ -371,7 +327,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
/**
- * This may take a LONG time.
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
+ * Call verifySocketManager() for that.
*
* @param pkf absolute path or null
* @return non-null
@@ -388,36 +345,61 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
try {
portNum = Integer.parseInt(tunnel.port);
} catch (NumberFormatException nfe) {
- _log.log(Log.CRIT, "Invalid port specified [" + tunnel.port + "], reverting to " + portNum);
+ throw new IllegalArgumentException("Invalid port specified [" + tunnel.port + "]", nfe);
}
}
I2PSocketManager sockManager = null;
- // FIXME: Can't stop a tunnel from the UI while it's in this loop (no session yet)
- int retries = 0;
- while (sockManager == null) {
+ FileInputStream fis = null;
+ try {
if (pkf != null) {
// Persistent client dest
- FileInputStream fis = null;
- try {
- fis = new FileInputStream(pkf);
- sockManager = I2PSocketManagerFactory.createManager(fis, tunnel.host, portNum, props);
- } catch (IOException ioe) {
- if (log != null)
- log.log("Error opening key file " + ioe);
- _log.error("Error opening key file", ioe);
- throw new IllegalArgumentException("Error opening key file " + ioe);
- } finally {
- if (fis != null)
- try { fis.close(); } catch (IOException ioe) {}
- }
+ fis = new FileInputStream(pkf);
+ sockManager = I2PSocketManagerFactory.createDisconnectedManager(fis, tunnel.host, portNum, props);
} else {
- sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props);
+ sockManager = I2PSocketManagerFactory.createDisconnectedManager(null, tunnel.host, portNum, props);
}
-
- if (sockManager == null) {
- // try to make this error sensible as it will happen... sadly we can't get to the listenPort, only the listenHost
- String msg = "Unable to connect to the router at " + tunnel.host + ':' + portNum +
+ } catch (I2PSessionException ise) {
+ throw new IllegalArgumentException("Can't create socket manager", ise);
+ } catch (IOException ioe) {
+ if (log != null)
+ log.log("Error opening key file " + ioe);
+ _log.error("Error opening key file", ioe);
+ throw new IllegalArgumentException("Error opening key file " + ioe);
+ } finally {
+ if (fis != null)
+ try { fis.close(); } catch (IOException ioe) {}
+ }
+ sockManager.setName("Client");
+ if (_log.shouldLog(Log.INFO))
+ _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Built a new socket manager [s=" + sockManager.getSession() + "]");
+ tunnel.addSession(sockManager.getSession());
+ return sockManager;
+ }
+
+
+ /**
+ * Warning, blocks while connecting to router and building tunnels;
+ * This may take a LONG time.
+ *
+ * @throws IllegalArgumentException if the I2CP configuration is b0rked so
+ * badly that we cant create a socketManager
+ * @since 0.9.20
+ */
+ private void connectManager() {
+ // shadows instance _log
+ Log _log = getTunnel().getContext().logManager().getLog(I2PTunnelClientBase.class);
+ Logging log = this.l;
+ int retries = 0;
+ while (sockMgr.getSession().isClosed()) {
+ try {
+ sockMgr.getSession().connect();
+ } catch (I2PSessionException ise) {
+ // try to make this error sensible as it will happen...
+ String portNum = getTunnel().port;
+ if (portNum == null)
+ portNum = "7654";
+ String msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum +
" and build tunnels for the client";
if (++retries < MAX_RETRIES) {
if (log != null)
@@ -434,11 +416,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {}
}
}
- sockManager.setName("Client");
- if (_log.shouldLog(Log.INFO))
- _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Built a new socket manager [s=" + sockManager.getSession() + "]");
- tunnel.addSession(sockManager.getSession());
- return sockManager;
}
public final int getLocalPort() {
@@ -457,11 +434,65 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
/**
- * Actually start working on incoming connections. *Must* be
+ * Actually open the local socket and start working on incoming connections. *Must* be
* called by derived classes after initialization.
*
+ * (this wasn't actually true until 0.9.20)
+ *
+ * This will be fast if i2cp.delayOpen is true, but could take
+ * a LONG TIME if it is false, as it connects to the router and builds tunnels.
+ *
*/
public void startRunning() {
+ boolean openNow = !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.delayOpen"));
+ if (openNow) {
+ while (sockMgr == null) {
+ verifySocketManager();
+ if (sockMgr == null) {
+ _log.error("Unable to connect to router and build tunnels for " + _handlerName);
+ // FIXME there is a loop in buildSocketManager(), do we really need another one here?
+ // no matter, buildSocketManager() now throws an IllegalArgumentException
+ try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
+ }
+ }
+ // can't be null unless we limit the loop above
+ //if (sockMgr == null) {
+ // l.log("Invalid I2CP configuration");
+ // throw new IllegalArgumentException("Socket manager could not be created");
+ //}
+ l.log("Tunnels ready for client: " + _handlerName);
+
+ } // else delay creating session until createI2PSocket() is called
+ startup();
+ }
+
+ private void startup() {
+ // prevent JVM exit when running outside the router
+ boolean isDaemon = getTunnel().getContext().isRouterContext();
+ Thread t = new I2PAppThread(this, "Client " + _clientId, isDaemon);
+ t.start();
+ open = true;
+ synchronized (this) {
+ while (!listenerReady && open) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+
+ if (open && listenerReady) {
+ boolean openNow = !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.delayOpen"));
+ if (openNow)
+ l.log("Client ready, listening on " + getTunnel().listenHost + ':' + localPort);
+ else
+ l.log("Client ready, listening on " + getTunnel().listenHost + ':' + localPort + ", delaying tunnel open until required");
+ notifyEvent("openBaseClientResult", "ok");
+ } else {
+ l.log("Client error for " + getTunnel().listenHost + ':' + localPort + ", check logs");
+ notifyEvent("openBaseClientResult", "error");
+ }
synchronized (startLock) {
startRunning = true;
startLock.notify();
@@ -521,8 +552,25 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
* @return a new I2PSocket
*/
public I2PSocket createI2PSocket(Destination dest) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
+ return createI2PSocket(dest, 0);
+ }
+
+ /**
+ * Create a new I2PSocket towards to the specified destination,
+ * adding it to the list of connections actually managed by this
+ * tunnel.
+ *
+ * @param dest The destination to connect to
+ * @param port The destination port to connect to 0 - 65535
+ * @return a new I2PSocket
+ * @since 0.9.20
+ */
+ public I2PSocket createI2PSocket(Destination dest, int port)
+ throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
verifySocketManager();
- return createI2PSocket(dest, getDefaultOptions());
+ I2PSocketOptions opts = getDefaultOptions();
+ opts.setPort(port);
+ return createI2PSocket(dest, opts);
}
/**
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
index 142aaf49b..dd01bf47c 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
@@ -106,11 +106,6 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
I2PTunnel tunnel) throws IllegalArgumentException {
super(localPort, ownDest, l, notifyThis, "HTTPS Proxy on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel);
- if (waitEventValue("openBaseClientResult").equals("error")) {
- notifyEvent("openConnectClientResult", "error");
- return;
- }
-
if (wwwProxy != null) {
StringTokenizer tok = new StringTokenizer(wwwProxy, ", ");
while (tok.hasMoreTokens())
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
index 9fcc9e02e..c7f257216 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
@@ -206,10 +206,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_proxyNonce = Long.toString(_context.random().nextLong());
//proxyList = new ArrayList(); // We won't use outside of i2p
- if(waitEventValue("openBaseClientResult").equals("error")) {
- notifyEvent("openHTTPClientResult", "error");
- return;
- }
if(wwwProxy != null) {
StringTokenizer tok = new StringTokenizer(wwwProxy, ", ");
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java
index d20d0be55..16cb43ad1 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java
@@ -246,7 +246,7 @@ public class TunnelControllerGroup implements ClientApp {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
if (controller.getStartOnLoad())
- controller.startTunnel();
+ controller.startTunnelBackground();
}
}
}
From 9dc2ae0d7e25abc48e12017f336272a416e80407 Mon Sep 17 00:00:00 2001
From: zzz
Date: Sat, 28 Mar 2015 10:25:45 +0000
Subject: [PATCH 2/4] fixup after prop
---
.../java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index 05e9550a7..abac27504 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -104,11 +104,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_log = _context.logManager().getLog(getClass());
- synchronized (_executorLock) {
- if (_executor == null)
- _executor = new CustomThreadPoolExecutor();
- }
-
startup();
}
From 485acd6c8db7218a3ab66113d1a795f76198686e Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 2 Apr 2015 20:52:40 +0000
Subject: [PATCH 3/4] Remove all the startRunning() calls in constructors,
which duplicated the new ones in I2PTunnel, causing all sorts of trouble. May
still need more locking. TBD.
---
.../java/src/net/i2p/i2ptunnel/I2PTunnelClient.java | 6 +++---
.../src/net/i2p/i2ptunnel/I2PTunnelClientBase.java | 4 +++-
.../net/i2p/i2ptunnel/I2PTunnelConnectClient.java | 5 +++--
.../net/i2p/i2ptunnel/I2PTunnelHTTPBidirProxy.java | 5 +++--
.../net/i2p/i2ptunnel/I2PTunnelHTTPBidirServer.java | 4 +++-
.../src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java | 13 +++++++------
.../src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java | 5 +++--
.../src/net/i2p/i2ptunnel/irc/DCCClientManager.java | 1 +
.../net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java | 5 +++--
.../src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java | 9 ++++++---
10 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
index b346039db..93785e326 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
@@ -32,6 +32,9 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
protected long readTimeout = DEFAULT_READ_TIMEOUT;
/**
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
* @param destinations peers we target, comma- or space-separated. Since 0.9.9, each dest may be appended with :port
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
@@ -63,9 +66,6 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
}
setName(getLocalPort() + " -> " + destinations);
-
- startRunning();
-
notifyEvent("openClientResult", "ok");
}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index abac27504..972818cdd 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -398,7 +398,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
if (log != null)
log.log("Error opening key file " + ioe);
_log.error("Error opening key file", ioe);
- throw new IllegalArgumentException("Error opening key file " + ioe);
+ throw new IllegalArgumentException("Error opening key file", ioe);
} finally {
if (fis != null)
try { fis.close(); } catch (IOException ioe) {}
@@ -500,6 +500,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
private void startup() {
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("startup " + _clientId, new Exception("I did it"));
// prevent JVM exit when running outside the router
boolean isDaemon = getTunnel().getContext().isRouterContext();
Thread t = new I2PAppThread(this, "Client " + _clientId, isDaemon);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
index ffe669f91..876321866 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
@@ -77,6 +77,9 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.
";
/**
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
@@ -92,8 +95,6 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
}
setName("HTTPS Proxy on " + tunnel.listenHost + ':' + localPort);
-
- startRunning();
}
/**
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirProxy.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirProxy.java
index 56c2e7550..4dbd5e654 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirProxy.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirProxy.java
@@ -30,6 +30,9 @@ public class I2PTunnelHTTPBidirProxy extends I2PTunnelHTTPClient implements Runn
/**
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
@@ -38,8 +41,6 @@ public class I2PTunnelHTTPBidirProxy extends I2PTunnelHTTPClient implements Runn
// proxyList = new ArrayList();
setName(getLocalPort() + " -> HTTPClient [NO PROXIES]");
- startRunning();
-
notifyEvent("openHTTPClientResult", "ok");
}
}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirServer.java
index d97482e04..2a3118567 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirServer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirServer.java
@@ -32,7 +32,9 @@ public class I2PTunnelHTTPBidirServer extends I2PTunnelHTTPServer {
bidir = true;
/* start the httpclient */
- task = new I2PTunnelHTTPBidirProxy(localPort, l, sockMgr, getTunnel(), getEventDispatcher(), __serverId);
+ I2PTunnelClientBase client = new I2PTunnelHTTPBidirProxy(localPort, l, sockMgr, getTunnel(), getEventDispatcher(), __serverId);
+ client.startRunning();
+ task = client;
sockMgr.setName("Server"); // TO-DO: Need to change this to "Bidir"!
getTunnel().addSession(sockMgr.getSession());
l.log("Ready!");
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
index 1426fd398..6dcfd32b7 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
@@ -192,6 +192,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
* This constructor always starts the tunnel (ignoring the i2cp.delayOpen option).
* It is used to add a client to an existing socket manager.
*
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
* @param sockMgr the existing socket manager
*/
public I2PTunnelHTTPClient(int localPort, Logging l, I2PSocketManager sockMgr, I2PTunnel tunnel, EventDispatcher notifyThis, long clientId) {
@@ -200,12 +203,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// proxyList = new ArrayList();
setName("HTTP Proxy on " + getTunnel().listenHost + ':' + localPort);
- startRunning();
-
notifyEvent("openHTTPClientResult", "ok");
}
/**
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
@@ -225,9 +229,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
setName("HTTP Proxy on " + tunnel.listenHost + ':' + localPort);
-
- startRunning();
-
notifyEvent("openHTTPClientResult", "ok");
}
@@ -607,6 +608,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_("i2paddresshelper cannot help you with a destination like that!") +
"
").getBytes("UTF-8"));
writeFooter(out);
+ reader.drain();
// XXX: should closeSocket(s) be in a finally block?
} catch (IOException ioe) {
// ignore
@@ -721,7 +723,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
out.write(getErrorPage("localhost", ERR_LOCALHOST).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
- s.close();
} catch (IOException ioe) {
// ignore
} finally {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
index 344c72197..e8fac6812 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
@@ -41,6 +41,9 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
public static final String PROP_DCC = "i2ptunnel.ircclient.enableDCC";
/**
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
* @param destinations peers we target, comma- or space-separated. Since 0.9.9, each dest may be appended with :port
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
@@ -81,8 +84,6 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
_dccEnabled = Boolean.parseBoolean(tunnel.getClientOptions().getProperty(PROP_DCC));
// TODO add some prudent tunnel options (or is it too late?)
- startRunning();
-
notifyEvent("openIRCClientResult", "ok");
}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/DCCClientManager.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/DCCClientManager.java
index 42af9abf2..753da65ec 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/DCCClientManager.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/DCCClientManager.java
@@ -109,6 +109,7 @@ public class DCCClientManager extends EventReceiver {
I2PTunnelDCCClient cTunnel = new I2PTunnelDCCClient(b32, localPort, port, l, sockMgr,
_dispatch, _tunnel, ++_id);
cTunnel.attachEventDispatcher(this);
+ cTunnel.startRunning();
int lport = cTunnel.getLocalPort();
if (_log.shouldLog(Log.WARN))
_log.warn("Opened client tunnel at port " + lport +
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java
index fcca71cb9..f5b434e3b 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java
@@ -37,6 +37,9 @@ public class I2PTunnelDCCClient extends I2PTunnelClientBase {
public static final String CONNECT_STOP_EVENT = "connectionStopped";
/**
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
* @param dest the target, presumably b32
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @throws IllegalArgumentException if the I2PTunnel does not contain
@@ -51,8 +54,6 @@ public class I2PTunnelDCCClient extends I2PTunnelClientBase {
_expires = tunnel.getContext().clock().now() + INBOUND_EXPIRE;
setName("DCC send -> " + dest + ':' + remotePort);
-
- startRunning();
}
/**
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java
index 498d75a18..6f8f6b3d3 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java
@@ -33,7 +33,12 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase {
// I2PSOCKSTunnel(localPort, l, ownDest, (EventDispatcher)null);
//}
- /** @param pkf private key file name or null for transient key */
+ /**
+ * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
+ * or open the local socket. You MUST call startRunning() for that.
+ *
+ * @param pkf private key file name or null for transient key
+ */
public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) {
super(localPort, ownDest, l, notifyThis, "SOCKS Proxy on " + tunnel.listenHost + ':' + localPort, tunnel, pkf);
@@ -44,8 +49,6 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase {
setName("SOCKS Proxy on " + tunnel.listenHost + ':' + localPort);
parseOptions();
- startRunning();
-
notifyEvent("openSOCKSTunnelResult", "ok");
}
From 2f5f91a0849c298b62735ab8e6b413bd2f56422f Mon Sep 17 00:00:00 2001
From: zzz
Date: Wed, 8 Apr 2015 11:52:02 +0000
Subject: [PATCH 4/4] log tweaks
---
.../i2p/i2ptunnel/I2PTunnelClientBase.java | 20 ++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index 972818cdd..a2c408973 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -420,31 +420,33 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
* @since 0.9.20
*/
private void connectManager() {
- // shadows instance _log
- Log _log = getTunnel().getContext().logManager().getLog(I2PTunnelClientBase.class);
- Logging log = this.l;
int retries = 0;
while (sockMgr.getSession().isClosed()) {
try {
sockMgr.getSession().connect();
} catch (I2PSessionException ise) {
+ // shadows instance _log
+ Log _log = getTunnel().getContext().logManager().getLog(I2PTunnelClientBase.class);
+ Logging log = this.l;
// try to make this error sensible as it will happen...
String portNum = getTunnel().port;
if (portNum == null)
portNum = "7654";
- String msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum +
+ String msg;
+ if (getTunnel().getContext().isRouterContext())
+ msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum +
" and build tunnels for the client";
+ else
+ msg = "Unable to build tunnels for the client";
if (++retries < MAX_RETRIES) {
if (log != null)
log.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds");
- _log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds");
+ _log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds", ise);
} else {
if (log != null)
log.log(msg + ", giving up");
- _log.log(Log.CRIT, msg + ", giving up");
- // not clear if callers can handle null
- //return null;
- throw new IllegalArgumentException(msg);
+ _log.log(Log.CRIT, msg + ", giving up", ise);
+ throw new IllegalArgumentException(msg, ise);
}
try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {}
}