From c5432a209858ac9b9642a46e51a057f7ff330bf5 Mon Sep 17 00:00:00 2001
From: str4d <str4d@mail.i2p>
Date: Sun, 22 May 2016 01:18:16 +0000
Subject: [PATCH] Dynamically load domain socket code

---
 .../net/i2p/client/DomainSocketFactory.java   | 45 -------------------
 .../net/i2p/client/impl/I2PSessionImpl.java   | 29 +++++++++---
 .../net/i2p/router/client/ClientManager.java  | 30 +++++++++++--
 .../client/DomainClientListenerRunner.java    | 31 -------------
 4 files changed, 49 insertions(+), 86 deletions(-)
 delete mode 100644 core/java/src/net/i2p/client/DomainSocketFactory.java
 delete 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
deleted file mode 100644
index e32deebdd7..0000000000
--- a/core/java/src/net/i2p/client/DomainSocketFactory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-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.14
- */
-public class DomainSocketFactory {
-    public static final 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/impl/I2PSessionImpl.java b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java
index 78e18c0e8a..84bed6adf5 100644
--- a/core/java/src/net/i2p/client/impl/I2PSessionImpl.java
+++ b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java
@@ -14,6 +14,9 @@ import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.security.GeneralSecurityException;
@@ -29,7 +32,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import net.i2p.CoreVersion;
 import net.i2p.I2PAppContext;
-import net.i2p.client.DomainSocketFactory;
 import net.i2p.client.I2PClient;
 import net.i2p.client.I2PSession;
 import net.i2p.client.I2PSessionException;
@@ -597,9 +599,24 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
                     _reader = new QueuedI2CPMessageReader(_queue, this);
                 } else {
                     if (SystemVersion.isAndroid() &&
-                            Boolean.parseBoolean(_options.getProperty(PROP_DOMAIN_SOCKET))) {
-                        final DomainSocketFactory fact = new DomainSocketFactory(_context);
-                        _socket = fact.createSocket(DomainSocketFactory.I2CP_SOCKET_ADDRESS);
+                            _options.getProperty(PROP_DOMAIN_SOCKET) != null) {
+                        try {
+                            Class<?> clazz = Class.forName("net.i2p.client.DomainSocketFactory");
+                            Constructor<?> ctor = clazz.getDeclaredConstructor(I2PAppContext.class);
+                            Object fact = ctor.newInstance(_context);
+                            Method createSocket = clazz.getDeclaredMethod("createSocket", String.class);
+                            _socket = (Socket) createSocket.invoke(fact, _options.getProperty(PROP_DOMAIN_SOCKET));
+                        } catch (ClassNotFoundException e) {
+                            throw new I2PSessionException("Cannot load DomainSocketFactory", e);
+                        } catch (NoSuchMethodException e) {
+                            throw new I2PSessionException("Cannot load DomainSocketFactory", e);
+                        } catch (InstantiationException e) {
+                            throw new I2PSessionException("Cannot load DomainSocketFactory", e);
+                        } catch (IllegalAccessException e) {
+                            throw new I2PSessionException("Cannot load DomainSocketFactory", e);
+                        } catch (InvocationTargetException e) {
+                            throw new I2PSessionException("Cannot load DomainSocketFactory", e);
+                        }
                     } else if (Boolean.parseBoolean(_options.getProperty(PROP_ENABLE_SSL))) {
                         try {
                             I2PSSLSocketFactory fact = new I2PSSLSocketFactory(_context, false, "certificates/i2cp");
@@ -684,8 +701,8 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
             if (_context.isRouterContext())
                 msg = "Failed to build tunnels";
             else if (SystemVersion.isAndroid() &&
-                    Boolean.parseBoolean(_options.getProperty(PROP_DOMAIN_SOCKET)))
-                msg = "Failed to bind to the router and build tunnels";
+                    _options.getProperty(PROP_DOMAIN_SOCKET) != null)
+                msg = "Failed to bind to the router on " + _options.getProperty(PROP_DOMAIN_SOCKET) + " and build tunnels";
             else
                 msg = "Cannot connect to the router on " + _hostname + ':' + _portNum + " and build tunnels";
             throw new I2PSessionException(getPrefix() + msg, ioe);
diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java
index 9c16aeb474..fbea7a7f21 100644
--- a/router/java/src/net/i2p/router/client/ClientManager.java
+++ b/router/java/src/net/i2p/router/client/ClientManager.java
@@ -10,6 +10,8 @@ package net.i2p.router.client;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -123,10 +125,30 @@ class ClientManager {
     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);
+            try {
+                Class<? extends ClientListenerRunner> clazz = Class.forName(
+                        "net.i2p.router.client.DomainClientListenerRunner"
+                    ).asSubclass(ClientListenerRunner.class);
+                Constructor<? extends ClientListenerRunner> ctor =
+                    clazz.getDeclaredConstructor(RouterContext.class,
+                                                 ClientManager.class);
+                listener = ctor.newInstance(_ctx, this);
+                Thread t = new I2PThread(listener, "DomainClientListener", true);
+                t.start();
+                _listeners.add(listener);
+            } catch (ClassNotFoundException e) {
+                _log.warn("Could not find DomainClientListenerRunner class", e);
+            } catch (ClassCastException e) {
+                _log.error("Error creating DomainClientListenerRunner", e);
+            } catch (NoSuchMethodException e) {
+                _log.error("Error creating DomainClientListenerRunner", e);
+            } catch (InstantiationException e) {
+                _log.error("Error creating DomainClientListenerRunner", e);
+            } catch (IllegalAccessException e) {
+                _log.error("Error creating DomainClientListenerRunner", e);
+            } catch (InvocationTargetException e) {
+                _log.error("Error creating DomainClientListenerRunner", e);
+            }
         }
         if (!_ctx.getBooleanProperty(PROP_DISABLE_EXTERNAL)) {
             // there's no option to start both an SSL and non-SSL listener
diff --git a/router/java/src/net/i2p/router/client/DomainClientListenerRunner.java b/router/java/src/net/i2p/router/client/DomainClientListenerRunner.java
deleted file mode 100644
index 0f28a494f4..0000000000
--- a/router/java/src/net/i2p/router/client/DomainClientListenerRunner.java
+++ /dev/null
@@ -1,31 +0,0 @@
-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.
- * <p/>
- * This is a stub that does nothing.
- * This class is replaced in the Android build.
- *
- * @author str4d
- * @since 0.9.14
- */
-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);
-    }
-}
-- 
GitLab