propagate from branch 'i2p.i2p' (head 3d405c867f6903bf1d69b04c1daebf3146882525)
to branch 'i2p.i2p.zzz.test4' (head bfd85b10fdd1542526a4b9c53e5d4a733087f317)
This commit is contained in:
@ -16,6 +16,7 @@ import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
@ -228,7 +229,15 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
//out.flush();
|
||||
PipedInputStream pi = new PipedInputStream();
|
||||
PipedOutputStream po = new PipedOutputStream(pi);
|
||||
new I2PAppThread(new Pusher(pi, out), "HTTP decompressor").start();
|
||||
// Run in the client thread pool, as there should be an unused thread
|
||||
// there after the accept().
|
||||
// Overridden in I2PTunnelHTTPServer, where it does not use the client pool.
|
||||
try {
|
||||
I2PTunnelClientBase._executor.execute(new Pusher(pi, out));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
// shouldn't happen
|
||||
throw ree;
|
||||
}
|
||||
out = po;
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,6 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelClient extends I2PTunnelClientBase {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelClient.class);
|
||||
|
||||
/** list of Destination objects that we point at */
|
||||
protected List<Destination> dests;
|
||||
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1
|
||||
|
@ -17,6 +17,13 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@ -34,9 +41,9 @@ import net.i2p.util.SimpleTimer;
|
||||
|
||||
public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runnable {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelClientBase.class);
|
||||
protected I2PAppContext _context;
|
||||
protected Logging l;
|
||||
protected final Log _log;
|
||||
protected final I2PAppContext _context;
|
||||
protected final Logging l;
|
||||
|
||||
static final long DEFAULT_CONNECT_TIMEOUT = 60 * 1000;
|
||||
|
||||
@ -64,35 +71,24 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
private String handlerName;
|
||||
private String privKeyFile;
|
||||
|
||||
// private Object conLock = new Object();
|
||||
|
||||
/** List of Socket for those accept()ed but not yet started up */
|
||||
protected final List _waitingSockets = new ArrayList(4); // FIXME should be final and use a factory. FIXME
|
||||
/** How many connections will we allow to be in the process of being built at once? */
|
||||
private int _numConnectionBuilders;
|
||||
/** How long will we allow sockets to sit in the _waitingSockets map before killing them? */
|
||||
private int _maxWaitTime;
|
||||
|
||||
/**
|
||||
* How many concurrent connections this I2PTunnel instance will allow to be
|
||||
* in the process of connecting (or if less than 1, there is no limit)?
|
||||
*/
|
||||
public static final String PROP_NUM_CONNECTION_BUILDERS = "i2ptunnel.numConnectionBuilders";
|
||||
/**
|
||||
* How long will we let a socket wait after being accept()ed without getting
|
||||
* pumped through a connection builder (in milliseconds). If this time is
|
||||
* reached, the socket is unceremoniously closed and discarded. If the max
|
||||
* wait time is less than 1, there is no limit.
|
||||
*
|
||||
*/
|
||||
public static final String PROP_MAX_WAIT_TIME = "i2ptunnel.maxWaitTime";
|
||||
|
||||
private static final int DEFAULT_NUM_CONNECTION_BUILDERS = 5;
|
||||
private static final int DEFAULT_MAX_WAIT_TIME = 30*1000;
|
||||
|
||||
// true if we are chained from a server.
|
||||
private boolean chained = false;
|
||||
|
||||
/** how long to wait before dropping an idle thread */
|
||||
private static final long HANDLER_KEEPALIVE_MS = 2*60*1000;
|
||||
|
||||
/**
|
||||
* We keep a static pool of socket handlers for all clients,
|
||||
* as there is no need for isolation on the client side.
|
||||
* Extending classes may use it for other purposes.
|
||||
* Not for use by servers, as there is no limit on threads.
|
||||
*/
|
||||
static final Executor _executor;
|
||||
private static int _executorThreadCount;
|
||||
static {
|
||||
_executor = new CustomThreadPoolExecutor();
|
||||
}
|
||||
|
||||
public I2PTunnelClientBase(int localPort, Logging l, I2PSocketManager sktMgr,
|
||||
I2PTunnel tunnel, EventDispatcher notifyThis, long clientId )
|
||||
throws IllegalArgumentException {
|
||||
@ -109,9 +105,9 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_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());
|
||||
|
||||
Thread t = new I2PAppThread(this);
|
||||
t.setName("Client " + _clientId);
|
||||
Thread t = new I2PAppThread(this, "Client " + tunnel.listenHost + ':' + localPort);
|
||||
listenerReady = false;
|
||||
t.start();
|
||||
open = true;
|
||||
@ -125,8 +121,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
configurePool(tunnel);
|
||||
|
||||
if (open && listenerReady) {
|
||||
l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
|
||||
notifyEvent("openBaseClientResult", "ok");
|
||||
@ -135,6 +129,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
notifyEvent("openBaseClientResult", "error");
|
||||
}
|
||||
}
|
||||
|
||||
public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l,
|
||||
EventDispatcher notifyThis, String handlerName,
|
||||
I2PTunnel tunnel) throws IllegalArgumentException {
|
||||
@ -163,6 +158,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_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());
|
||||
|
||||
// normalize path so we can find it
|
||||
if (pkf != null) {
|
||||
@ -210,8 +206,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
configurePool(tunnel);
|
||||
|
||||
if (open && listenerReady) {
|
||||
if (openNow)
|
||||
l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
|
||||
@ -224,37 +218,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build and configure the pool handling accept()ed but not yet
|
||||
* established connections
|
||||
*
|
||||
*/
|
||||
private void configurePool(I2PTunnel tunnel) {
|
||||
//_waitingSockets = new ArrayList(4);
|
||||
|
||||
Properties opts = tunnel.getClientOptions();
|
||||
String maxWait = opts.getProperty(PROP_MAX_WAIT_TIME, DEFAULT_MAX_WAIT_TIME+"");
|
||||
try {
|
||||
_maxWaitTime = Integer.parseInt(maxWait);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_maxWaitTime = DEFAULT_MAX_WAIT_TIME;
|
||||
}
|
||||
|
||||
String numBuild = opts.getProperty(PROP_NUM_CONNECTION_BUILDERS, DEFAULT_NUM_CONNECTION_BUILDERS+"");
|
||||
try {
|
||||
_numConnectionBuilders = Integer.parseInt(numBuild);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_numConnectionBuilders = DEFAULT_NUM_CONNECTION_BUILDERS;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numConnectionBuilders; i++) {
|
||||
String name = "ClientBuilder" + _clientId + '.' + i;
|
||||
I2PAppThread b = new I2PAppThread(new TunnelConnectionBuilder(), name);
|
||||
b.setDaemon(true);
|
||||
b.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the this.sockMgr field if it is null, or if we want a new one
|
||||
*
|
||||
@ -321,6 +284,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
* badly that we cant create a socketManager
|
||||
*/
|
||||
protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) {
|
||||
// shadows instance _log
|
||||
Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
|
||||
if (socketManager != null) {
|
||||
I2PSession s = socketManager.getSession();
|
||||
if ( (s == null) || (s.isClosed()) ) {
|
||||
@ -378,6 +343,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
* badly that we cant create a socketManager
|
||||
*/
|
||||
protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf, Logging log) {
|
||||
// shadows instance _log
|
||||
Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
|
||||
Properties props = new Properties();
|
||||
props.putAll(tunnel.getClientOptions());
|
||||
int portNum = 7654;
|
||||
@ -537,7 +504,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
synchronized (_waitingSockets) { _waitingSockets.notifyAll(); }
|
||||
return;
|
||||
}
|
||||
ss = new ServerSocket(localPort, 0, addr);
|
||||
@ -566,12 +532,9 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (open) {
|
||||
Socket s = ss.accept();
|
||||
long before = System.currentTimeMillis();
|
||||
manageConnection(s);
|
||||
long total = System.currentTimeMillis() - before;
|
||||
_context.statManager().addRateData("i2ptunnel.client.manageTime", total, total);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
if (open) {
|
||||
@ -586,9 +549,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
synchronized (_waitingSockets) {
|
||||
_waitingSockets.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -598,24 +558,38 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
*/
|
||||
protected void manageConnection(Socket s) {
|
||||
if (s == null) return;
|
||||
if (_numConnectionBuilders <= 0) {
|
||||
new I2PAppThread(new BlockingRunner(s), "Clinet run").start();
|
||||
return;
|
||||
try {
|
||||
_executor.execute(new BlockingRunner(s));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
// should never happen, we have an unbounded pool and never stop the executor
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
if (_maxWaitTime > 0)
|
||||
SimpleScheduler.getInstance().addEvent(new CloseEvent(s), _maxWaitTime);
|
||||
}
|
||||
|
||||
synchronized (_waitingSockets) {
|
||||
_waitingSockets.add(s);
|
||||
_waitingSockets.notifyAll();
|
||||
/**
|
||||
* Not really needed for now but in case we want to add some hooks like afterExecute().
|
||||
*/
|
||||
private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
public CustomThreadPoolExecutor() {
|
||||
super(0, Integer.MAX_VALUE, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
|
||||
new SynchronousQueue(), new CustomThreadFactory());
|
||||
}
|
||||
}
|
||||
|
||||
/** just to set the name and set Daemon */
|
||||
private static class CustomThreadFactory implements ThreadFactory {
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread rv = Executors.defaultThreadFactory().newThread(r);
|
||||
rv.setName("I2PTunnel Client Runner " + (++_executorThreadCount));
|
||||
rv.setDaemon(true);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking runner, used during the connection establishment whenever we
|
||||
* are not using the queued builders.
|
||||
*
|
||||
* Blocking runner, used during the connection establishment
|
||||
*/
|
||||
private class BlockingRunner implements Runnable {
|
||||
private Socket _s;
|
||||
@ -625,32 +599,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and close the socket from the waiting list, if it is still there.
|
||||
*
|
||||
*/
|
||||
private class CloseEvent implements SimpleTimer.TimedEvent {
|
||||
private Socket _s;
|
||||
public CloseEvent(Socket s) { _s = s; }
|
||||
public void timeReached() {
|
||||
int remaining = 0;
|
||||
boolean stillWaiting = false;
|
||||
synchronized (_waitingSockets) {
|
||||
stillWaiting = _waitingSockets.remove(_s);
|
||||
remaining = _waitingSockets.size();
|
||||
}
|
||||
if (stillWaiting) {
|
||||
try { _s.close(); } catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_context.statManager().addRateData("i2ptunnel.client.closeBacklog", remaining, 0);
|
||||
_log.info("Closed a waiting socket because of backlog");
|
||||
}
|
||||
} else {
|
||||
_context.statManager().addRateData("i2ptunnel.client.closeNoBacklog", remaining, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean close(boolean forced) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("close() called: forced = " + forced + " open = " + open + " sockMgr = " + sockMgr);
|
||||
@ -688,7 +636,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
//l.log("Client closed.");
|
||||
}
|
||||
|
||||
synchronized (_waitingSockets) { _waitingSockets.notifyAll(); }
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -696,40 +643,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Could not close socket", ex);
|
||||
//_log.error("Could not close socket", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool runner pulling sockets off the waiting list and pushing them
|
||||
* through clientConnectionRun. This dies when the I2PTunnel instance
|
||||
* is closed.
|
||||
*
|
||||
*/
|
||||
private class TunnelConnectionBuilder implements Runnable {
|
||||
public void run() {
|
||||
Socket s = null;
|
||||
while (open) {
|
||||
try {
|
||||
synchronized (_waitingSockets) {
|
||||
if (_waitingSockets.isEmpty())
|
||||
_waitingSockets.wait();
|
||||
else
|
||||
s = (Socket)_waitingSockets.remove(0);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
if (s != null) {
|
||||
long before = System.currentTimeMillis();
|
||||
clientConnectionRun(s);
|
||||
long total = System.currentTimeMillis() - before;
|
||||
_context.statManager().addRateData("i2ptunnel.client.buildRunTime", total, 0);
|
||||
}
|
||||
s = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage a connection in a separate thread. This only works if
|
||||
* you do not override manageConnection()
|
||||
|
@ -58,7 +58,6 @@ import net.i2p.util.Log;
|
||||
* @author zzz a stripped-down I2PTunnelHTTPClient
|
||||
*/
|
||||
public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelConnectClient.class);
|
||||
|
||||
private final static byte[] ERR_DESTINATION_UNKNOWN =
|
||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
||||
@ -340,8 +339,8 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
|
||||
_requestId = id;
|
||||
}
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Timeout occured requesting " + _target);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Timeout occured requesting " + _target);
|
||||
handleConnectClientException(new RuntimeException("Timeout"), _out,
|
||||
_target, _usingProxy, _wwwProxy, _requestId);
|
||||
closeSocket(_socket);
|
||||
|
@ -11,7 +11,6 @@ import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelHTTPBidirServer extends I2PTunnelHTTPServer {
|
||||
private final static Log log = new Log(I2PTunnelHTTPBidirServer.class);
|
||||
|
||||
public I2PTunnelHTTPBidirServer(InetAddress host, int port, int proxyport, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, spoofHost, l, notifyThis, tunnel);
|
||||
|
@ -61,7 +61,6 @@ import net.i2p.util.Translate;
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelHTTPClient.class);
|
||||
|
||||
private HashMap addressHelpers = new HashMap();
|
||||
|
||||
@ -894,15 +893,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
_requestId = id;
|
||||
}
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Timeout occured requesting " + _target);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Timeout occured requesting " + _target);
|
||||
handleHTTPClientException(new RuntimeException("Timeout"), _out,
|
||||
_target, _usingProxy, _wwwProxy, _requestId);
|
||||
closeSocket(_socket);
|
||||
}
|
||||
}
|
||||
|
||||
private static String DEFAULT_JUMP_SERVERS =
|
||||
public static final String DEFAULT_JUMP_SERVERS =
|
||||
"http://i2host.i2p/cgi-bin/i2hostjump?," +
|
||||
"http://stats.i2p/cgi-bin/jump.cgi?a=," +
|
||||
"http://i2jump.i2p/";
|
||||
@ -940,8 +939,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
// Skip jump servers we don't know
|
||||
String jumphost = jurl.substring(7); // "http://"
|
||||
jumphost = jumphost.substring(0, jumphost.indexOf('/'));
|
||||
Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(jumphost);
|
||||
if (dest == null) continue;
|
||||
if (!jumphost.endsWith(".i2p"))
|
||||
continue;
|
||||
if (!jumphost.endsWith(".b32.i2p")) {
|
||||
Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(jumphost);
|
||||
if (dest == null) continue;
|
||||
}
|
||||
|
||||
out.write("<br><a href=\"".getBytes());
|
||||
out.write(jurl.getBytes());
|
||||
|
@ -25,7 +25,7 @@ import net.i2p.util.Log;
|
||||
* @since 0.8.2
|
||||
*/
|
||||
public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelHTTPClientBase.class);
|
||||
|
||||
protected final List<String> _proxyList;
|
||||
|
||||
protected final static byte[] ERR_NO_OUTPROXY =
|
||||
|
@ -31,7 +31,7 @@ import net.i2p.data.Base32;
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
private final static Log _log = new Log(I2PTunnelHTTPServer.class);
|
||||
|
||||
/** what Host: should we seem to be to the webserver? */
|
||||
private String _spoofHost;
|
||||
private static final String HASH_HEADER = "X-I2P-DestHash";
|
||||
@ -40,6 +40,20 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
private static final String[] CLIENT_SKIPHEADERS = {HASH_HEADER, DEST64_HEADER, DEST32_HEADER};
|
||||
private static final String SERVER_HEADER = "Server";
|
||||
private static final String[] SERVER_SKIPHEADERS = {SERVER_HEADER};
|
||||
private static final long HEADER_TIMEOUT = 60*1000;
|
||||
|
||||
private final static byte[] ERR_UNAVAILABLE =
|
||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"Proxy-Connection: close\r\n"+
|
||||
"\r\n"+
|
||||
"<html><head><title>503 Service Unavailable<title></head>\n"+
|
||||
"<body><h2>503 Service Unavailable</h2>\n" +
|
||||
"<p>This I2P eepsite is unavailable. It may be down or undergoing maintenance.</p>\n" +
|
||||
"</body></html>")
|
||||
.getBytes();
|
||||
|
||||
public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, l, notifyThis, tunnel);
|
||||
@ -73,8 +87,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
//local is fast, so synchronously. Does not need that many
|
||||
//threads.
|
||||
try {
|
||||
// give them 5 seconds to send in the HTTP request
|
||||
socket.setReadTimeout(5*1000);
|
||||
// The headers _should_ be in the first packet, but
|
||||
// may not be, depending on the client-side options
|
||||
socket.setReadTimeout(HEADER_TIMEOUT);
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
@ -130,13 +145,24 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
} else {
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
|
||||
}
|
||||
|
||||
long afterHandle = getTunnel().getContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
|
||||
" [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
// Send a 503, so the user doesn't get an HTTP Proxy error message
|
||||
// and blame his router or the network.
|
||||
socket.getOutputStream().write(ERR_UNAVAILABLE);
|
||||
} catch (IOException ioe) {}
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error while closing the received i2p con", ex);
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error connecting to HTTP server " + remoteHost + ':' + remotePort, ex);
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
@ -150,12 +176,6 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("OOM in HTTP server", oom);
|
||||
}
|
||||
|
||||
long afterHandle = getTunnel().getContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
}
|
||||
|
||||
private static class CompressedRequestor implements Runnable {
|
||||
@ -169,6 +189,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
_headers = headers;
|
||||
_ctx = ctx;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Compressed requestor running");
|
||||
@ -183,7 +204,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
_log.info("request headers: " + _headers);
|
||||
serverout.write(_headers.getBytes());
|
||||
browserin = _browser.getInputStream();
|
||||
I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server"), Thread.currentThread().getName() + "hcs");
|
||||
I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server", _log), Thread.currentThread().getName() + "hcs");
|
||||
sender.start();
|
||||
|
||||
browserout = _browser.getOutputStream();
|
||||
@ -233,14 +254,19 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
}
|
||||
|
||||
private static class Sender implements Runnable {
|
||||
private OutputStream _out;
|
||||
private InputStream _in;
|
||||
private String _name;
|
||||
public Sender(OutputStream out, InputStream in, String name) {
|
||||
private final OutputStream _out;
|
||||
private final InputStream _in;
|
||||
private final String _name;
|
||||
// shadows _log in super()
|
||||
private final Log _log;
|
||||
|
||||
public Sender(OutputStream out, InputStream in, String name, Log log) {
|
||||
_out = out;
|
||||
_in = in;
|
||||
_name = name;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(_name + ": Begin sending");
|
||||
@ -277,16 +303,16 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
protected boolean shouldCompress() { return true; }
|
||||
@Override
|
||||
protected void finishHeaders() throws IOException {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Including x-i2p-gzip as the content encoding in the response");
|
||||
//if (_log.shouldLog(Log.INFO))
|
||||
// _log.info("Including x-i2p-gzip as the content encoding in the response");
|
||||
out.write("Content-encoding: x-i2p-gzip\r\n".getBytes());
|
||||
super.finishHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beginProcessing() throws IOException {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Beginning compression processing");
|
||||
//if (_log.shouldLog(Log.INFO))
|
||||
// _log.info("Beginning compression processing");
|
||||
//out.flush();
|
||||
_gzipOut = new InternalGZIPOutputStream(out);
|
||||
out = _gzipOut;
|
||||
|
@ -20,8 +20,6 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelIRCClient.class);
|
||||
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
@ -130,6 +128,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
private Socket local;
|
||||
private I2PSocket remote;
|
||||
private StringBuffer expectedPong;
|
||||
// shadows _log in super()
|
||||
private final Log _log = new Log(I2PTunnelIRCClient.class);
|
||||
|
||||
public IrcInboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
local=_local;
|
||||
@ -207,6 +207,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
private Socket local;
|
||||
private I2PSocket remote;
|
||||
private StringBuffer expectedPong;
|
||||
// shadows _log in super()
|
||||
private final Log _log = new Log(I2PTunnelIRCClient.class);
|
||||
|
||||
public IrcOutboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
local=_local;
|
||||
@ -308,7 +310,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
try { command = field[idx++]; }
|
||||
catch (IndexOutOfBoundsException ioobe) // wtf, server sent borked command?
|
||||
{
|
||||
_log.warn("Dropping defective message: index out of bounds while extracting command.");
|
||||
//_log.warn("Dropping defective message: index out of bounds while extracting command.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -431,13 +433,13 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
rv = "PING " + field[1];
|
||||
expectedPong.append("PONG ").append(field[2]).append(" :").append(field[1]); // PONG serverLocation nonce
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
|
||||
//if (_log.shouldLog(Log.ERROR))
|
||||
// _log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
|
||||
rv = null;
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s + "]");
|
||||
//if (_log.shouldLog(Log.WARN))
|
||||
// _log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s + "]");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -61,9 +61,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
public static final String PROP_WEBIRC_SPOOF_IP_DEFAULT="127.0.0.1";
|
||||
public static final String PROP_HOSTNAME="ircserver.fakeHostname";
|
||||
public static final String PROP_HOSTNAME_DEFAULT="%f.b32.i2p";
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelIRCServer.class);
|
||||
|
||||
private static final long HEADER_TIMEOUT = 60*1000;
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||
@ -108,8 +106,9 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
try {
|
||||
String modifiedRegistration;
|
||||
if(!this.method.equals("webirc")) {
|
||||
// give them 15 seconds to send in the request
|
||||
socket.setReadTimeout(15*1000);
|
||||
// The headers _should_ be in the first packet, but
|
||||
// may not be, depending on the client-side options
|
||||
socket.setReadTimeout(HEADER_TIMEOUT);
|
||||
InputStream in = socket.getInputStream();
|
||||
modifiedRegistration = filterRegistration(in, cloakDest(socket.getPeerDestination()));
|
||||
socket.setReadTimeout(readTimeout);
|
||||
@ -126,12 +125,12 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
|
||||
} catch (SocketException ex) {
|
||||
// TODO send the equivalent of a 503?
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error while closing the received i2p con", ex);
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error connecting to IRC server " + remoteHost + ':' + remotePort, ex);
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
@ -181,8 +180,8 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
if (++lineCount > 10)
|
||||
throw new IOException("Too many lines before USER or SERVER, giving up");
|
||||
s = s.trim();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Got line: " + s);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Got line: " + s);
|
||||
|
||||
String field[]=s.split(" ",5);
|
||||
String command;
|
||||
@ -214,8 +213,8 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
if ("SERVER".equalsIgnoreCase(command))
|
||||
break;
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("All done, sending: " + buf.toString());
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("All done, sending: " + buf.toString());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,12 @@ import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@ -30,8 +36,7 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
|
||||
private final static Log _log = new Log(I2PTunnelServer.class);
|
||||
|
||||
protected final Log _log;
|
||||
protected I2PSocketManager sockMgr;
|
||||
protected I2PServerSocket i2pss;
|
||||
|
||||
@ -48,12 +53,17 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
/** default timeout to 3 minutes - override if desired */
|
||||
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||
|
||||
private static final boolean DEFAULT_USE_POOL = false;
|
||||
/** do we use threads? default true (ignored for standard servers, always false) */
|
||||
private static final String PROP_USE_POOL = "i2ptunnel.usePool";
|
||||
private static final boolean DEFAULT_USE_POOL = true;
|
||||
protected static volatile long __serverId = 0;
|
||||
/** max number of threads - this many slowlorisses will DOS this server, but too high could OOM the JVM */
|
||||
private static final String PROP_HANDLER_COUNT = "i2ptunnel.blockingHandlerCount";
|
||||
private static final int DEFAULT_HANDLER_COUNT = 10;
|
||||
|
||||
|
||||
private static final int DEFAULT_HANDLER_COUNT = 65;
|
||||
/** min number of threads */
|
||||
private static final int MIN_HANDLERS = 0;
|
||||
/** how long to wait before dropping an idle thread */
|
||||
private static final long HANDLER_KEEPALIVE_MS = 30*1000;
|
||||
|
||||
protected I2PTunnelTask task = null;
|
||||
protected boolean bidir = false;
|
||||
@ -67,8 +77,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
*/
|
||||
public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("Server at " + host + ':' + port, notifyThis, tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(getClass());
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData));
|
||||
SetUsePool(tunnel);
|
||||
init(host, port, bais, privData, l);
|
||||
}
|
||||
|
||||
@ -79,7 +89,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
public I2PTunnelServer(InetAddress host, int port, File privkey, String privkeyname, Logging l,
|
||||
EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("Server at " + host + ':' + port, notifyThis, tunnel);
|
||||
SetUsePool(tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(getClass());
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(privkey);
|
||||
@ -99,19 +109,10 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
*/
|
||||
public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("Server at " + host + ':' + port, notifyThis, tunnel);
|
||||
SetUsePool(tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(getClass());
|
||||
init(host, port, privData, privkeyname, l);
|
||||
}
|
||||
|
||||
|
||||
private void SetUsePool(I2PTunnel Tunnel) {
|
||||
String usePool = Tunnel.getClientOptions().getProperty("i2ptunnel.usePool");
|
||||
if (usePool != null)
|
||||
_usePool = "true".equalsIgnoreCase(usePool);
|
||||
else
|
||||
_usePool = DEFAULT_USE_POOL;
|
||||
}
|
||||
|
||||
private static final int RETRY_DELAY = 20*1000;
|
||||
private static final int MAX_RETRIES = 4;
|
||||
|
||||
@ -143,6 +144,16 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
// extending classes default to threaded, but for a standard server, we can't get slowlorissed
|
||||
_usePool = !getClass().equals(I2PTunnelServer.class);
|
||||
if (_usePool) {
|
||||
String usePool = getTunnel().getClientOptions().getProperty(PROP_USE_POOL);
|
||||
if (usePool != null)
|
||||
_usePool = "true".equalsIgnoreCase(usePool);
|
||||
else
|
||||
_usePool = DEFAULT_USE_POOL;
|
||||
}
|
||||
|
||||
// Todo: Can't stop a tunnel from the UI while it's in this loop (no session yet)
|
||||
int retries = 0;
|
||||
while (sockMgr == null) {
|
||||
@ -199,8 +210,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
*
|
||||
*/
|
||||
public void startRunning() {
|
||||
Thread t = new I2PAppThread(this);
|
||||
t.setName("Server " + (++__serverId));
|
||||
Thread t = new I2PAppThread(this, "Server " + remoteHost + ':' + remotePort, true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
@ -236,7 +246,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
l.log("Stopping tunnels for server at " + getTunnel().listenHost + ':' + this.remotePort);
|
||||
l.log("Stopping tunnels for server at " + this.remoteHost + ':' + this.remotePort);
|
||||
try {
|
||||
if (i2pss != null) i2pss.close();
|
||||
getTunnel().removeSession(sockMgr.getSession());
|
||||
@ -259,67 +269,106 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
rv = Integer.parseInt(cnt);
|
||||
if (rv <= 0)
|
||||
rv = DEFAULT_HANDLER_COUNT;
|
||||
} catch (NumberFormatException nfe) {
|
||||
rv = DEFAULT_HANDLER_COUNT;
|
||||
}
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* If usePool is set, this starts the executor pool.
|
||||
* Then, do the accept() loop, and either
|
||||
* hands each I2P socket to the executor or runs it in-line.
|
||||
*/
|
||||
public void run() {
|
||||
if (shouldUsePool()) {
|
||||
I2PServerSocket i2pS_S = sockMgr.getServerSocket();
|
||||
int handlers = getHandlerCount();
|
||||
for (int i = 0; i < handlers; i++) {
|
||||
I2PAppThread handler = new I2PAppThread(new Handler(i2pS_S), "Handle Server " + i);
|
||||
handler.start();
|
||||
}
|
||||
} else {
|
||||
I2PServerSocket i2pS_S = sockMgr.getServerSocket();
|
||||
while (true) {
|
||||
try {
|
||||
final I2PSocket i2ps = i2pS_S.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
new I2PAppThread(new Runnable() { public void run() { blockingHandle(i2ps); } }).start();
|
||||
} catch (I2PException ipe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
|
||||
return;
|
||||
} catch (ConnectException ce) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting", ce);
|
||||
// not killing the server..
|
||||
} catch(SocketTimeoutException ste) {
|
||||
// ignored, we never set the timeout
|
||||
I2PServerSocket i2pS_S = sockMgr.getServerSocket();
|
||||
ThreadPoolExecutor executor = null;
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (_usePool)
|
||||
_log.warn("Starting executor with " + getHandlerCount() + " threads max");
|
||||
else
|
||||
_log.warn("Threads disabled, running blockingHandles inline");
|
||||
}
|
||||
if (_usePool) {
|
||||
executor = new CustomThreadPoolExecutor(getHandlerCount(), "ServerHandler pool " + remoteHost + ':' + remotePort);
|
||||
}
|
||||
while (open) {
|
||||
try {
|
||||
final I2PSocket i2ps = i2pS_S.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
if (_usePool) {
|
||||
try {
|
||||
executor.execute(new Handler(i2ps));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
try {
|
||||
i2ps.close();
|
||||
} catch (IOException ioe) {}
|
||||
if (open && _log.shouldLog(Log.ERROR))
|
||||
_log.error("ServerHandler queue full for " + remoteHost + ':' + remotePort +
|
||||
"; increase " + PROP_HANDLER_COUNT + '?', ree);
|
||||
}
|
||||
} else {
|
||||
// use only for standard servers that can't get slowlorissed! Not for http or irc
|
||||
blockingHandle(i2ps);
|
||||
}
|
||||
} catch (I2PException ipe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
|
||||
return;
|
||||
} catch (ConnectException ce) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting", ce);
|
||||
// not killing the server..
|
||||
try {
|
||||
Thread.currentThread().sleep(500);
|
||||
} catch (InterruptedException ie) {}
|
||||
} catch(SocketTimeoutException ste) {
|
||||
// ignored, we never set the timeout
|
||||
}
|
||||
}
|
||||
if (executor != null)
|
||||
executor.shutdownNow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Not really needed for now but in case we want to add some hooks like afterExecute().
|
||||
*/
|
||||
private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
public CustomThreadPoolExecutor(int max, String name) {
|
||||
super(MIN_HANDLERS, max, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
|
||||
new SynchronousQueue(), new CustomThreadFactory(name));
|
||||
}
|
||||
}
|
||||
|
||||
/** just to set the name and set Daemon */
|
||||
private static class CustomThreadFactory implements ThreadFactory {
|
||||
private String _name;
|
||||
|
||||
public CustomThreadFactory(String name) {
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread rv = Executors.defaultThreadFactory().newThread(r);
|
||||
rv.setName(_name);
|
||||
rv.setDaemon(true);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldUsePool() { return _usePool; }
|
||||
|
||||
/**
|
||||
* minor thread pool to pull off the accept() concurrently. there are still lots
|
||||
* (and lots) of wasted threads within the I2PTunnelRunner, but its a start
|
||||
*
|
||||
* Run the blockingHandler.
|
||||
*/
|
||||
private class Handler implements Runnable {
|
||||
private I2PServerSocket _serverSocket;
|
||||
public Handler(I2PServerSocket serverSocket) {
|
||||
_serverSocket = serverSocket;
|
||||
private I2PSocket _i2ps;
|
||||
|
||||
public Handler(I2PSocket socket) {
|
||||
_i2ps = socket;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (open) {
|
||||
try {
|
||||
blockingHandle(_serverSocket.accept());
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
return;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
blockingHandle(_i2ps);
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,20 +384,21 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
afterSocket = I2PAppContext.getGlobalContext().clock().now();
|
||||
new I2PTunnelRunner(s, socket, slock, null, null);
|
||||
|
||||
long afterHandle = I2PAppContext.getGlobalContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
|
||||
" [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error while closing the received i2p con", ex);
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error connecting to server " + remoteHost + ':' + remotePort, ex);
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
}
|
||||
|
||||
long afterHandle = I2PAppContext.getGlobalContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
if (timeToHandle > 1000)
|
||||
_log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,6 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class I2PSOCKSIRCTunnel extends I2PSOCKSTunnel {
|
||||
|
||||
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(I2PSOCKSIRCTunnel.class);
|
||||
private static int __clientId = 0;
|
||||
|
||||
/** @param pkf private key file name or null for transient key */
|
||||
|
@ -26,7 +26,6 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
||||
|
||||
private static final Log _log = new Log(I2PSOCKSTunnel.class);
|
||||
private HashMap<String, List<String>> proxies = null; // port# + "" or "default" -> hostname list
|
||||
protected Destination outProxyDest = null;
|
||||
|
||||
|
@ -45,7 +45,6 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements Source, Sink {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelUDPClientBase.class);
|
||||
protected I2PAppContext _context;
|
||||
protected Logging l;
|
||||
|
||||
|
@ -46,7 +46,7 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sink {
|
||||
|
||||
private final static Log _log = new Log(I2PTunnelUDPServerBase.class);
|
||||
private final Log _log;
|
||||
|
||||
private final Object lock = new Object();
|
||||
protected Object slock = new Object();
|
||||
@ -73,6 +73,7 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
|
||||
public I2PTunnelUDPServerBase(boolean verify, File privkey, String privkeyname, Logging l,
|
||||
EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("UDPServer <- " + privkeyname, notifyThis, tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(I2PTunnelUDPServerBase.class);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(privkey);
|
||||
|
@ -18,6 +18,7 @@ import net.i2p.data.Destination;
|
||||
import net.i2p.data.PrivateKeyFile;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
@ -171,14 +172,23 @@ public class EditBean extends IndexBean {
|
||||
return getProperty(tunnel, "i2cp.leaseSetKey", "");
|
||||
}
|
||||
|
||||
public boolean getAccess(int tunnel) {
|
||||
return getBooleanProperty(tunnel, "i2cp.enableAccessList");
|
||||
public String getAccessMode(int tunnel) {
|
||||
if (getBooleanProperty(tunnel, PROP_ENABLE_ACCESS_LIST))
|
||||
return "1";
|
||||
if (getBooleanProperty(tunnel, PROP_ENABLE_BLACKLIST))
|
||||
return "2";
|
||||
return "0";
|
||||
}
|
||||
|
||||
public String getAccessList(int tunnel) {
|
||||
return getProperty(tunnel, "i2cp.accessList", "").replace(",", "\n");
|
||||
}
|
||||
|
||||
public String getJumpList(int tunnel) {
|
||||
return getProperty(tunnel, I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
|
||||
I2PTunnelHTTPClient.DEFAULT_JUMP_SERVERS).replace(",", "\n");
|
||||
}
|
||||
|
||||
public boolean getClose(int tunnel) {
|
||||
return getBooleanProperty(tunnel, "i2cp.closeOnIdle");
|
||||
}
|
||||
@ -234,6 +244,35 @@ public class EditBean extends IndexBean {
|
||||
return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW, "");
|
||||
}
|
||||
|
||||
/** all of these are @since 0.8.3 */
|
||||
public String getLimitMinute(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_CONNS_MIN, "0");
|
||||
}
|
||||
|
||||
public String getLimitHour(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_CONNS_HOUR, "0");
|
||||
}
|
||||
|
||||
public String getLimitDay(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_CONNS_DAY, "0");
|
||||
}
|
||||
|
||||
public String getTotalMinute(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_MIN, "0");
|
||||
}
|
||||
|
||||
public String getTotalHour(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_HOUR, "0");
|
||||
}
|
||||
|
||||
public String getTotalDay(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_DAY, "0");
|
||||
}
|
||||
|
||||
public String getMaxStreams(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_STREAMS, "0");
|
||||
}
|
||||
|
||||
private int getProperty(int tunnel, String prop, int def) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
@ -270,7 +309,14 @@ public class EditBean extends IndexBean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public boolean isRouterContext() {
|
||||
return _context.isRouterContext();
|
||||
}
|
||||
|
||||
public String getI2CPHost(int tunnel) {
|
||||
if (_context.isRouterContext())
|
||||
return _("internal");
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getI2CPHost();
|
||||
@ -279,6 +325,8 @@ public class EditBean extends IndexBean {
|
||||
}
|
||||
|
||||
public String getI2CPPort(int tunnel) {
|
||||
if (_context.isRouterContext())
|
||||
return _("internal");
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getI2CPPort();
|
||||
|
@ -24,6 +24,7 @@ import net.i2p.data.Certificate;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.PrivateKeyFile;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
@ -537,11 +538,11 @@ public class IndexBean {
|
||||
public void setDescription(String description) {
|
||||
_description = (description != null ? description.trim() : null);
|
||||
}
|
||||
/** I2CP host the router is on */
|
||||
/** I2CP host the router is on, ignored when in router context */
|
||||
public void setClientHost(String host) {
|
||||
_i2cpHost = (host != null ? host.trim() : null);
|
||||
}
|
||||
/** I2CP port the router is on */
|
||||
/** I2CP port the router is on, ignored when in router context */
|
||||
public void setClientport(String port) {
|
||||
_i2cpPort = (port != null ? port.trim() : null);
|
||||
}
|
||||
@ -643,9 +644,17 @@ public class IndexBean {
|
||||
public void setEncrypt(String moo) {
|
||||
_booleanOptions.add("i2cp.encryptLeaseSet");
|
||||
}
|
||||
public void setAccess(String moo) {
|
||||
_booleanOptions.add("i2cp.enableAccessList");
|
||||
|
||||
protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
|
||||
protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
|
||||
|
||||
public void setAccessMode(String val) {
|
||||
if ("1".equals(val))
|
||||
_booleanOptions.add(PROP_ENABLE_ACCESS_LIST);
|
||||
else if ("2".equals(val))
|
||||
_booleanOptions.add(PROP_ENABLE_BLACKLIST);
|
||||
}
|
||||
|
||||
public void setDelayOpen(String moo) {
|
||||
_booleanOptions.add("i2cp.delayOpen");
|
||||
}
|
||||
@ -671,10 +680,17 @@ public class IndexBean {
|
||||
if (val != null)
|
||||
_otherOptions.put("i2cp.leaseSetKey", val.trim());
|
||||
}
|
||||
|
||||
public void setAccessList(String val) {
|
||||
if (val != null)
|
||||
_otherOptions.put("i2cp.accessList", val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
|
||||
}
|
||||
|
||||
public void setJumpList(String val) {
|
||||
if (val != null)
|
||||
_otherOptions.put(I2PTunnelHTTPClient.PROP_JUMP_SERVERS, val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
|
||||
}
|
||||
|
||||
public void setCloseTime(String val) {
|
||||
if (val != null) {
|
||||
try {
|
||||
@ -712,6 +728,50 @@ public class IndexBean {
|
||||
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW, s.trim());
|
||||
}
|
||||
|
||||
/** all of these are @since 0.8.3 */
|
||||
protected static final String PROP_MAX_CONNS_MIN = "i2p.streaming.maxConnsPerMinute";
|
||||
protected static final String PROP_MAX_CONNS_HOUR = "i2p.streaming.maxConnsPerHour";
|
||||
protected static final String PROP_MAX_CONNS_DAY = "i2p.streaming.maxConnsPerDay";
|
||||
protected static final String PROP_MAX_TOTAL_CONNS_MIN = "i2p.streaming.maxTotalConnsPerMinute";
|
||||
protected static final String PROP_MAX_TOTAL_CONNS_HOUR = "i2p.streaming.maxTotalConnsPerHour";
|
||||
protected static final String PROP_MAX_TOTAL_CONNS_DAY = "i2p.streaming.maxTotalConnsPerDay";
|
||||
protected static final String PROP_MAX_STREAMS = "i2p.streaming.maxConcurrentStreams";
|
||||
|
||||
public void setLimitMinute(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_CONNS_MIN, s.trim());
|
||||
}
|
||||
|
||||
public void setLimitHour(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_CONNS_HOUR, s.trim());
|
||||
}
|
||||
|
||||
public void setLimitDay(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_CONNS_DAY, s.trim());
|
||||
}
|
||||
|
||||
public void setTotalMinute(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_TOTAL_CONNS_MIN, s.trim());
|
||||
}
|
||||
|
||||
public void setTotalHour(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_TOTAL_CONNS_HOUR, s.trim());
|
||||
}
|
||||
|
||||
public void setTotalDay(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_TOTAL_CONNS_DAY, s.trim());
|
||||
}
|
||||
|
||||
public void setMaxStreams(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_STREAMS, s.trim());
|
||||
}
|
||||
|
||||
/** params needed for hashcash and dest modification */
|
||||
public void setEffort(String val) {
|
||||
if (val != null) {
|
||||
@ -904,16 +964,20 @@ public class IndexBean {
|
||||
I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH
|
||||
};
|
||||
private static final String _booleanServerOpts[] = {
|
||||
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", "i2cp.enableAccessList"
|
||||
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST
|
||||
};
|
||||
private static final String _otherClientOpts[] = {
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
|
||||
"proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword"
|
||||
"proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword",
|
||||
I2PTunnelHTTPClient.PROP_JUMP_SERVERS
|
||||
};
|
||||
private static final String _otherServerOpts[] = {
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList"
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
|
||||
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
|
||||
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
|
||||
PROP_MAX_STREAMS
|
||||
};
|
||||
protected static final Set _noShowSet = new HashSet();
|
||||
protected static final Set _noShowSet = new HashSet(64);
|
||||
static {
|
||||
_noShowSet.addAll(Arrays.asList(_noShowOpts));
|
||||
_noShowSet.addAll(Arrays.asList(_booleanClientOpts));
|
||||
@ -929,12 +993,14 @@ public class IndexBean {
|
||||
config.setProperty("name", _name);
|
||||
if (_description != null)
|
||||
config.setProperty("description", _description);
|
||||
if (_i2cpHost != null)
|
||||
config.setProperty("i2cpHost", _i2cpHost);
|
||||
if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
|
||||
config.setProperty("i2cpPort", _i2cpPort);
|
||||
} else {
|
||||
config.setProperty("i2cpPort", "7654");
|
||||
if (!_context.isRouterContext()) {
|
||||
if (_i2cpHost != null)
|
||||
config.setProperty("i2cpHost", _i2cpHost);
|
||||
if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
|
||||
config.setProperty("i2cpPort", _i2cpPort);
|
||||
} else {
|
||||
config.setProperty("i2cpPort", "7654");
|
||||
}
|
||||
}
|
||||
if (_privKeyFile != null)
|
||||
config.setProperty("privKeyFile", _privKeyFile);
|
||||
@ -1020,7 +1086,7 @@ public class IndexBean {
|
||||
}
|
||||
}
|
||||
|
||||
private String _(String key) {
|
||||
protected String _(String key) {
|
||||
return Messages._(key, _context);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user