From 0c7a3a3a39713638f31728d722042bc7f678d28d Mon Sep 17 00:00:00 2001 From: str4d <str4d@mail.i2p> Date: Tue, 15 Jul 2014 12:54:22 +0000 Subject: [PATCH] Stubs for I2CP connections over Unix domain sockets --- .../net/i2p/client/DomainSocketFactory.java | 45 +++++++++++++++++++ .../src/net/i2p/client/I2PSessionImpl.java | 23 ++++++++-- .../router/client/ClientListenerRunner.java | 7 +-- .../net/i2p/router/client/ClientManager.java | 34 ++++++++++---- .../client/DomainClientListenerRunner.java | 29 ++++++++++++ .../client/SSLClientListenerRunner.java | 2 +- 6 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 core/java/src/net/i2p/client/DomainSocketFactory.java create mode 100644 router/java/src/net/i2p/router/client/DomainClientListenerRunner.java diff --git a/core/java/src/net/i2p/client/DomainSocketFactory.java b/core/java/src/net/i2p/client/DomainSocketFactory.java new file mode 100644 index 0000000000..280236e5e7 --- /dev/null +++ b/core/java/src/net/i2p/client/DomainSocketFactory.java @@ -0,0 +1,45 @@ +package net.i2p.client; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +import net.i2p.I2PAppContext; + +/** + * Bridge to Unix domain socket (or similar). + * <p/> + * This is a stub that does nothing. + * This class is replaced in the Android build. + * + * @author str4d + * @since 0.9.15 + */ +public class DomainSocketFactory { + public static String I2CP_SOCKET_ADDRESS = "net.i2p.client.i2cp"; + + /** + * @throws UnsupportedOperationException always + */ + public DomainSocketFactory(I2PAppContext context) { + throw new UnsupportedOperationException(); + } + + /** + * Override in Android. + * @throws IOException + * @throws UnsupportedOperationException always + */ + public Socket createSocket(String name) throws IOException { + throw new UnsupportedOperationException(); + } + + /** + * Override in Android. + * @throws IOException + * @throws UnsupportedOperationException always + */ + public ServerSocket createServerSocket(String name) throws IOException { + throw new UnsupportedOperationException(); + } +} diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index 20aa43550b..fd60b7404b 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -52,6 +52,7 @@ import net.i2p.util.LHMCache; import net.i2p.util.Log; import net.i2p.util.OrderedProperties; import net.i2p.util.SimpleTimer2; +import net.i2p.util.SystemVersion; import net.i2p.util.VersionComparator; /** @@ -157,6 +158,12 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa protected static final String PROP_USER = "i2cp.username"; protected static final String PROP_PW = "i2cp.password"; + /** + * Use Unix domain socket (or similar) to connect to a router + * @since 0.9.15 + */ + protected static final String PROP_DOMAIN_SOCKET = "i2cp.domainSocket"; + private static final long VERIFY_USAGE_TIME = 60*1000; private static final long MAX_SEND_WAIT = 10*1000; @@ -279,6 +286,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa if (_context.isRouterContext()) // just for logging return "[internal connection]"; + else if (SystemVersion.isAndroid() && + Boolean.parseBoolean(_options.getProperty(PROP_DOMAIN_SOCKET))) + // just for logging + return "[Domain socket connection]"; return _options.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1"); } @@ -287,7 +298,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa * @since 0.9.7 was in loadConfig() */ private int getPort() { - if (_context.isRouterContext()) + if (_context.isRouterContext() || + (SystemVersion.isAndroid() && + Boolean.parseBoolean(_options.getProperty(PROP_DOMAIN_SOCKET)))) // just for logging return 0; String portNum = _options.getProperty(I2PClient.PROP_TCP_PORT, LISTEN_PORT + ""); @@ -447,7 +460,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa try { // protect w/ closeSocket() synchronized(_stateLock) { - // If we are in the router JVM, connect using the interal queue + // If we are in the router JVM, connect using the internal queue if (_context.isRouterContext()) { // _socket and _writer remain null InternalClientManager mgr = _context.internalClientManager(); @@ -457,7 +470,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa _queue = mgr.connect(); _reader = new QueuedI2CPMessageReader(_queue, this); } else { - if (Boolean.parseBoolean(_options.getProperty(PROP_ENABLE_SSL))) { + if (SystemVersion.isAndroid() && + Boolean.parseBoolean(_options.getProperty(PROP_DOMAIN_SOCKET))) { + final DomainSocketFactory fact = new DomainSocketFactory(_context); + _socket = fact.createSocket(DomainSocketFactory.I2CP_SOCKET_ADDRESS); + } else if (Boolean.parseBoolean(_options.getProperty(PROP_ENABLE_SSL))) { try { I2PSSLSocketFactory fact = new I2PSSLSocketFactory(_context, false, "certificates/i2cp"); _socket = fact.createSocket(_hostname, _portNum); diff --git a/router/java/src/net/i2p/router/client/ClientListenerRunner.java b/router/java/src/net/i2p/router/client/ClientListenerRunner.java index 9b169ca757..44d7811b6b 100644 --- a/router/java/src/net/i2p/router/client/ClientListenerRunner.java +++ b/router/java/src/net/i2p/router/client/ClientListenerRunner.java @@ -64,7 +64,9 @@ class ClientListenerRunner implements Runnable { return new ServerSocket(_port, 0, InetAddress.getByName(listenInterface)); } } - + + public void run() { runServer(); } + /** * Start up the socket listener, listens for connections, and * fires those connections off via {@link #runConnection runConnection}. @@ -72,7 +74,7 @@ class ClientListenerRunner implements Runnable { * failure. * */ - public void runServer() { + protected void runServer() { _running = true; int curDelay = 1000; while (_running) { @@ -173,5 +175,4 @@ class ClientListenerRunner implements Runnable { _socket = null; } catch (IOException ioe) {} } - public void run() { runServer(); } } diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java index 96e6ac20b6..c982671b75 100644 --- a/router/java/src/net/i2p/router/client/ClientManager.java +++ b/router/java/src/net/i2p/router/client/ClientManager.java @@ -10,8 +10,10 @@ package net.i2p.router.client; import java.io.IOException; import java.io.Writer; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; @@ -37,6 +39,7 @@ import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; import net.i2p.util.I2PThread; import net.i2p.util.Log; +import net.i2p.util.SystemVersion; /** * Coordinate connections and various tasks @@ -45,7 +48,7 @@ import net.i2p.util.Log; */ class ClientManager { private final Log _log; - protected ClientListenerRunner _listener; + protected List<ClientListenerRunner> _listeners; // Destination --> ClientConnectionRunner // Locked for adds/removes but not lookups private final Map<Destination, ClientConnectionRunner> _runners; @@ -87,6 +90,7 @@ class ClientManager { // "How large are messages received by the client?", // "ClientMessages", // new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + _listeners = new ArrayList<ClientListenerRunner>(); _runners = new ConcurrentHashMap<Destination, ClientConnectionRunner>(); _runnersByHash = new ConcurrentHashMap<Hash, ClientConnectionRunner>(); _pendingRunners = new HashSet<ClientConnectionRunner>(); @@ -105,14 +109,22 @@ class ClientManager { /** Todo: Start a 3rd listener for IPV6? */ protected void startListeners() { + ClientListenerRunner listener; + if (SystemVersion.isAndroid()) { + listener = new DomainClientListenerRunner(_ctx, this); + Thread t = new I2PThread(listener, "DomainClientListener", true); + t.start(); + _listeners.add(listener); + } if (!_ctx.getBooleanProperty(PROP_DISABLE_EXTERNAL)) { // there's no option to start both an SSL and non-SSL listener if (_ctx.getBooleanProperty(PROP_ENABLE_SSL)) - _listener = new SSLClientListenerRunner(_ctx, this, _port); + listener = new SSLClientListenerRunner(_ctx, this, _port); else - _listener = new ClientListenerRunner(_ctx, this, _port); - Thread t = new I2PThread(_listener, "ClientListener:" + _port, true); + listener = new ClientListenerRunner(_ctx, this, _port); + Thread t = new I2PThread(listener, "ClientListener:" + _port, true); t.start(); + _listeners.add(listener); } _isStarted = true; } @@ -132,8 +144,9 @@ class ClientManager { public synchronized void shutdown(String msg) { _isStarted = false; _log.info("Shutting down the ClientManager"); - if (_listener != null) - _listener.stopListening(); + for (ClientListenerRunner listener : _listeners) + listener.stopListening(); + _listeners.clear(); Set<ClientConnectionRunner> runners = new HashSet<ClientConnectionRunner>(); synchronized (_runners) { for (ClientConnectionRunner runner : _runners.values()) { @@ -169,8 +182,13 @@ class ClientManager { return hisQueue; } - public boolean isAlive() { - return _isStarted && (_listener == null || _listener.isListening()); + public synchronized boolean isAlive() { + boolean listening = true; + if (!_listeners.isEmpty()) { + for (ClientListenerRunner listener : _listeners) + listening = listening && listener.isListening(); + } + return _isStarted && (_listeners.isEmpty() || listening); } public void registerConnection(ClientConnectionRunner runner) { diff --git a/router/java/src/net/i2p/router/client/DomainClientListenerRunner.java b/router/java/src/net/i2p/router/client/DomainClientListenerRunner.java new file mode 100644 index 0000000000..89dbae6b72 --- /dev/null +++ b/router/java/src/net/i2p/router/client/DomainClientListenerRunner.java @@ -0,0 +1,29 @@ +package net.i2p.router.client; + +import java.io.IOException; +import java.net.ServerSocket; + +import net.i2p.client.DomainSocketFactory; +import net.i2p.router.RouterContext; + +/** + * Unix domain socket version of ClientListenerRunner. + * This is a stub that does nothing. + * This class is replaced in the Android build. + * + * @since 0.9.15 + */ +public class DomainClientListenerRunner extends ClientListenerRunner { + public DomainClientListenerRunner(RouterContext context, ClientManager manager) { + super(context, manager, -1); + } + + /** + * @throws IOException + */ + @Override + protected ServerSocket getServerSocket() throws IOException { + final DomainSocketFactory fact = new DomainSocketFactory(_context); + return fact.createServerSocket(DomainSocketFactory.I2CP_SOCKET_ADDRESS); + } +} diff --git a/router/java/src/net/i2p/router/client/SSLClientListenerRunner.java b/router/java/src/net/i2p/router/client/SSLClientListenerRunner.java index fcd008ad68..948cb7527a 100644 --- a/router/java/src/net/i2p/router/client/SSLClientListenerRunner.java +++ b/router/java/src/net/i2p/router/client/SSLClientListenerRunner.java @@ -181,7 +181,7 @@ class SSLClientListenerRunner extends ClientListenerRunner { * Create (if necessary) and load the key store, then run. */ @Override - public void runServer() { + protected void runServer() { File keyStore = new File(_context.getConfigDir(), "keystore/i2cp.ks"); if (verifyKeyStore(keyStore) && initializeFactory(keyStore)) { super.runServer(); -- GitLab