* I2CP: Implement an internal "socket" class that
allows clients in the same JVM to connect to the router without going through the kernel
This commit is contained in:
@ -200,6 +200,9 @@ public class Router {
|
||||
// overwrite an existing running router's jar files. Other than ours.
|
||||
installUpdates();
|
||||
|
||||
// Apps may use this as an easy way to determine if they are in the router JVM
|
||||
System.setProperty("router.version", RouterVersion.VERSION);
|
||||
|
||||
// NOW we start all the activity
|
||||
_context.initAll();
|
||||
|
||||
|
@ -24,14 +24,14 @@ import net.i2p.util.Log;
|
||||
* @author jrandom
|
||||
*/
|
||||
public class ClientListenerRunner implements Runnable {
|
||||
private Log _log;
|
||||
private RouterContext _context;
|
||||
private ClientManager _manager;
|
||||
private ServerSocket _socket;
|
||||
private int _port;
|
||||
protected Log _log;
|
||||
protected RouterContext _context;
|
||||
protected ClientManager _manager;
|
||||
protected ServerSocket _socket;
|
||||
protected int _port;
|
||||
private boolean _bindAllInterfaces;
|
||||
private boolean _running;
|
||||
private boolean _listening;
|
||||
protected boolean _running;
|
||||
protected boolean _listening;
|
||||
|
||||
public static final String BIND_ALL_INTERFACES = "i2cp.tcp.bindAllInterfaces";
|
||||
|
||||
@ -91,7 +91,9 @@ public class ClientListenerRunner implements Runnable {
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Refused connection from " + socket.getInetAddress());
|
||||
socket.close();
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_context.router().isAlive())
|
||||
@ -132,7 +134,7 @@ public class ClientListenerRunner implements Runnable {
|
||||
/** give the i2cp client 5 seconds to show that they're really i2cp clients */
|
||||
private final static int CONNECT_TIMEOUT = 5*1000;
|
||||
|
||||
private boolean validate(Socket socket) {
|
||||
protected boolean validate(Socket socket) {
|
||||
try {
|
||||
socket.setSoTimeout(CONNECT_TIMEOUT);
|
||||
int read = socket.getInputStream().read();
|
||||
@ -150,7 +152,7 @@ public class ClientListenerRunner implements Runnable {
|
||||
* Handle the connection by passing it off to a {@link ClientConnectionRunner ClientConnectionRunner}
|
||||
*
|
||||
*/
|
||||
protected void runConnection(Socket socket) throws IOException {
|
||||
protected void runConnection(Socket socket) {
|
||||
ClientConnectionRunner runner = new ClientConnectionRunner(_context, _manager, socket);
|
||||
_manager.registerConnection(runner);
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ import net.i2p.util.Log;
|
||||
public class ClientManager {
|
||||
private Log _log;
|
||||
private ClientListenerRunner _listener;
|
||||
private ClientListenerRunner _internalListener;
|
||||
private final HashMap<Destination, ClientConnectionRunner> _runners; // Destination --> ClientConnectionRunner
|
||||
private final Set<ClientConnectionRunner> _pendingRunners; // ClientConnectionRunner for clients w/out a Dest yet
|
||||
private RouterContext _ctx;
|
||||
@ -58,11 +59,21 @@ public class ClientManager {
|
||||
new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
|
||||
_runners = new HashMap();
|
||||
_pendingRunners = new HashSet();
|
||||
startListeners(port);
|
||||
}
|
||||
|
||||
/** Todo: Start a 3rd listener for IPV6? */
|
||||
private void startListeners(int port) {
|
||||
_listener = new ClientListenerRunner(_ctx, this, port);
|
||||
Thread t = new I2PThread(_listener);
|
||||
t.setName("ClientListener:" + port);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
_internalListener = new InternalClientListenerRunner(_ctx, this, port);
|
||||
t = new I2PThread(_internalListener);
|
||||
t.setName("ClientListener:" + port + "-i");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
@ -80,16 +91,13 @@ public class ClientManager {
|
||||
_log.error("Error setting the port: " + portStr + " is not valid", nfe);
|
||||
}
|
||||
}
|
||||
_listener = new ClientListenerRunner(_ctx, this, port);
|
||||
Thread t = new I2PThread(_listener);
|
||||
t.setName("ClientListener:" + port);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
startListeners(port);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
_log.info("Shutting down the ClientManager");
|
||||
_listener.stopListening();
|
||||
_internalListener.stopListening();
|
||||
Set<ClientConnectionRunner> runners = new HashSet();
|
||||
synchronized (_runners) {
|
||||
for (Iterator<ClientConnectionRunner> iter = _runners.values().iterator(); iter.hasNext();) {
|
||||
|
@ -0,0 +1,88 @@
|
||||
package net.i2p.router.client;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.InternalServerSocket;
|
||||
|
||||
/**
|
||||
* Listen for in-JVM connections on the internal "socket"
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
public class InternalClientListenerRunner extends ClientListenerRunner {
|
||||
|
||||
public InternalClientListenerRunner(RouterContext context, ClientManager manager, int port) {
|
||||
super(context, manager, port);
|
||||
_log = _context.logManager().getLog(InternalClientListenerRunner.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start up the socket listener, listens for connections, and
|
||||
* fires those connections off via {@link #runConnection runConnection}.
|
||||
* This only returns if the socket cannot be opened or there is a catastrophic
|
||||
* failure.
|
||||
*
|
||||
*/
|
||||
public void runServer() {
|
||||
try {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Listening on internal port " + _port);
|
||||
_socket = new InternalServerSocket(_port);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("InternalServerSocket created, before accept: " + _socket);
|
||||
|
||||
_listening = true;
|
||||
_running = true;
|
||||
while (_running) {
|
||||
try {
|
||||
Socket socket = _socket.accept();
|
||||
if (validate(socket)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Internal connection received");
|
||||
runConnection(socket);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Refused connection from " + socket.getInetAddress());
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_context.router().isAlive())
|
||||
_log.error("Server error accepting", ioe);
|
||||
} catch (Throwable t) {
|
||||
if (_context.router().isAlive())
|
||||
_log.error("Fatal error running client listener - killing the thread!", t);
|
||||
_listening = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_context.router().isAlive())
|
||||
_log.error("Error listening on internal port " + _port, ioe);
|
||||
}
|
||||
|
||||
_listening = false;
|
||||
if (_socket != null) {
|
||||
try { _socket.close(); } catch (IOException ioe) {}
|
||||
_socket = null;
|
||||
}
|
||||
|
||||
|
||||
if (_context.router().isAlive())
|
||||
_log.error("CANCELING I2CP LISTEN", new Exception("I2CP Listen cancelled!!!"));
|
||||
_running = false;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user