2005-03-04 jrandom
* Filter HTTP response headers in the eepproxy, forcing Connection: close so that broken (/malicious) webservers can't allow persistent connections. All HTTP compliant browsers should now always close the socket. * Enabled the GZIPInputStream's cache (they were'nt cached before) * Make sure our first send is always a SYN (duh) * Workaround for some buggy compilers
This commit is contained in:
@ -0,0 +1,232 @@
|
||||
package net.i2p.i2ptunnel;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2005 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.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Properties;
|
||||
import java.util.Iterator;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Simple stream for delivering an HTTP response to
|
||||
* the client, trivially filtered to make sure "Connection: close"
|
||||
* is always in the response.
|
||||
*
|
||||
*/
|
||||
class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
private static final Log _log = new Log(HTTPResponseOutputStream.class);
|
||||
private ByteCache _cache;
|
||||
protected ByteArray _headerBuffer;
|
||||
private boolean _headerWritten;
|
||||
private byte _buf1[];
|
||||
private static final int CACHE_SIZE = 4096;
|
||||
|
||||
public HTTPResponseOutputStream(OutputStream raw) {
|
||||
super(raw);
|
||||
_cache = ByteCache.getInstance(8, CACHE_SIZE);
|
||||
_headerBuffer = _cache.acquire();
|
||||
_headerWritten = false;
|
||||
_buf1 = new byte[1];
|
||||
}
|
||||
|
||||
public void write(int c) throws IOException {
|
||||
_buf1[0] = (byte)c;
|
||||
write(_buf1, 0, 1);
|
||||
}
|
||||
public void write(byte buf[]) throws IOException {
|
||||
write(buf, 0, buf.length);
|
||||
}
|
||||
public void write(byte buf[], int off, int len) throws IOException {
|
||||
if (_headerWritten) {
|
||||
out.write(buf, off, len);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
ensureCapacity();
|
||||
_headerBuffer.getData()[_headerBuffer.getValid()] = buf[off+i];
|
||||
_headerBuffer.setValid(_headerBuffer.getValid()+1);
|
||||
|
||||
if (headerReceived()) {
|
||||
writeHeader();
|
||||
_headerWritten = true;
|
||||
if (i + 1 < len) // write out the remaining
|
||||
out.write(buf, off+i+1, len-i-1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* filter any headers (adding or removing as necessary), and tweak
|
||||
* the first response line as necessary.
|
||||
*
|
||||
* @return response line ("200 OK", etc)
|
||||
*/
|
||||
protected String filterHeaders(String responseLine, Properties props) {
|
||||
props.setProperty("Connection", "close");
|
||||
props.setProperty("Proxy-Connection", "close");
|
||||
return responseLine;
|
||||
}
|
||||
|
||||
|
||||
/** grow (and free) the buffer as necessary */
|
||||
private void ensureCapacity() {
|
||||
if (_headerBuffer.getValid() + 1 >= _headerBuffer.getData().length) {
|
||||
int newSize = (int)(_headerBuffer.getData().length * 1.5);
|
||||
ByteArray newBuf = new ByteArray(new byte[newSize]);
|
||||
System.arraycopy(_headerBuffer.getData(), 0, newBuf, 0, _headerBuffer.getValid());
|
||||
if (_headerBuffer.getData().length == CACHE_SIZE)
|
||||
_cache.release(_headerBuffer);
|
||||
_headerBuffer = newBuf;
|
||||
}
|
||||
}
|
||||
|
||||
/** are the headers finished? */
|
||||
private boolean headerReceived() {
|
||||
if (_headerBuffer.getValid() < 3) return false;
|
||||
byte first = _headerBuffer.getData()[_headerBuffer.getValid()-3];
|
||||
byte second = _headerBuffer.getData()[_headerBuffer.getValid()-2];
|
||||
byte third = _headerBuffer.getData()[_headerBuffer.getValid()-1];
|
||||
return (isNL(second) && isNL(third)) || // \n\n
|
||||
(isNL(first) && isNL(third)); // \n\r\n
|
||||
}
|
||||
|
||||
/** we ignore any potential \r, since we trim it on write anyway */
|
||||
private static final byte NL = '\n';
|
||||
private boolean isNL(byte b) { return (b == NL); }
|
||||
|
||||
/** ok, received, now munge & write it */
|
||||
private void writeHeader() throws IOException {
|
||||
Properties props = new Properties();
|
||||
String responseLine = null;
|
||||
|
||||
int lastEnd = -1;
|
||||
for (int i = 0; i < _headerBuffer.getValid(); i++) {
|
||||
if (isNL(_headerBuffer.getData()[i])) {
|
||||
if (lastEnd == -1) {
|
||||
responseLine = new String(_headerBuffer.getData(), 0, i+1); // includes NL
|
||||
} else {
|
||||
for (int j = lastEnd+1; j < i; j++) {
|
||||
if (_headerBuffer.getData()[j] == ':') {
|
||||
String key = new String(_headerBuffer.getData(), lastEnd+1, j-(lastEnd+1));
|
||||
String val = new String(_headerBuffer.getData(), j+2, i-(j+2));
|
||||
props.setProperty(key, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastEnd = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (responseLine == null)
|
||||
throw new IOException("No HTTP response line, with props=" + props);
|
||||
|
||||
responseLine = filterHeaders(responseLine, props);
|
||||
responseLine = (responseLine.trim() + "\n");
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
StringBuffer msg = new StringBuffer(responseLine.length() + props.size() * 64);
|
||||
msg.append("HTTP response: first line [").append(responseLine.trim());
|
||||
msg.append("] options: \n");
|
||||
|
||||
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = props.getProperty(key);
|
||||
msg.append('[').append(key.trim()).append("]=[").append(val.trim()).append("]\n");
|
||||
}
|
||||
|
||||
_log.debug(msg.toString());
|
||||
}
|
||||
|
||||
out.write(responseLine.getBytes());
|
||||
|
||||
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = props.getProperty(key);
|
||||
String line = key.trim() + ": " + val.trim() + "\n";
|
||||
out.write(line.getBytes());
|
||||
}
|
||||
out.write("\n".getBytes()); // end of the headers
|
||||
|
||||
// done, shove off
|
||||
if (_headerBuffer.getData().length == CACHE_SIZE)
|
||||
_cache.release(_headerBuffer);
|
||||
else
|
||||
_headerBuffer = null;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String simple = "HTTP/1.1 200 OK\n" +
|
||||
"foo: bar\n" +
|
||||
"baz: bat\n" +
|
||||
"\n" +
|
||||
"hi ho, this is the body";
|
||||
String filtered = "HTTP/1.1 200 OK\n" +
|
||||
"Connection: keep-alive\n" +
|
||||
"foo: bar\n" +
|
||||
"baz: bat\n" +
|
||||
"\n" +
|
||||
"hi ho, this is the body";
|
||||
String winfilter= "HTTP/1.1 200 OK\r\n" +
|
||||
"Connection: keep-alive\r\n" +
|
||||
"foo: bar\r\n" +
|
||||
"baz: bat\r\n" +
|
||||
"\r\n" +
|
||||
"hi ho, this is the body";
|
||||
String minimal = "HTTP/1.1 200 OK\n" +
|
||||
"\n" +
|
||||
"hi ho, this is the body";
|
||||
String winmin = "HTTP/1.1 200 OK\r\n" +
|
||||
"\r\n" +
|
||||
"hi ho, this is the body";
|
||||
String invalid1 = "HTTP/1.1 200 OK\n";
|
||||
String invalid2 = "HTTP/1.1 200 OK";
|
||||
String invalid3 = "HTTP 200 OK\r\n";
|
||||
String invalid4 = "HTTP 200 OK\r";
|
||||
String large = "HTTP/1.1 200 OK\n" +
|
||||
"Last-modified: Tue, 25 Nov 2003 12:05:38 GMT\n" +
|
||||
"Expires: Tue, 25 Nov 2003 12:05:38 GMT\n" +
|
||||
"Content-length: 32\n" +
|
||||
"\n" +
|
||||
"hi ho, this is the body";
|
||||
/* */
|
||||
test("Simple", simple);
|
||||
test("Filtered", filtered);
|
||||
test("Filtered windows", winfilter);
|
||||
test("Minimal", minimal);
|
||||
test("Windows", winmin);
|
||||
test("Large", large);
|
||||
test("Invalid (short headers)", invalid1);
|
||||
test("Invalid (no headers)", invalid2);
|
||||
test("Invalid (windows with short headers)", invalid3);
|
||||
test("Invalid (windows no headers)", invalid4);
|
||||
/* */
|
||||
}
|
||||
|
||||
private static void test(String name, String orig) {
|
||||
System.out.println("====Testing: " + name + "\n" + orig + "\n------------");
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
|
||||
HTTPResponseOutputStream resp = new HTTPResponseOutputStream(baos);
|
||||
resp.write(orig.getBytes());
|
||||
resp.flush();
|
||||
String received = new String(baos.toByteArray());
|
||||
System.out.println(received);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -416,7 +416,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
I2PSocket i2ps = createI2PSocket(dest, getDefaultOptions(opts));
|
||||
byte[] data = newRequest.toString().getBytes("ISO-8859-1");
|
||||
Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
|
||||
I2PTunnelRunner runner = new I2PTunnelRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
|
||||
I2PTunnelRunner runner = new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
|
||||
} catch (SocketException ex) {
|
||||
_log.info(getPrefix(requestId) + "Error trying to connect", ex);
|
||||
l.log(ex.getMessage());
|
||||
|
@ -0,0 +1,41 @@
|
||||
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
|
||||
* (c) 2003 - 2004 mihi
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Override the response with a stream filtering the HTTP headers
|
||||
* received. Specifically, this makes sure we get Connection: close,
|
||||
* so the browser knows they really shouldn't try to use persistent
|
||||
* connections. The HTTP server *should* already be setting this,
|
||||
* since the HTTP headers sent by the browser specify Connection: close,
|
||||
* and the server should echo it. However, both broken and malicious
|
||||
* servers could ignore that, potentially confusing the user.
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPClientRunner extends I2PTunnelRunner {
|
||||
public I2PTunnelHTTPClientRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData, List sockList, Runnable onTimeout) {
|
||||
super(s, i2ps, slock, initialI2PData, sockList, onTimeout);
|
||||
}
|
||||
|
||||
protected OutputStream getSocketOut() throws IOException {
|
||||
OutputStream raw = super.getSocketOut();
|
||||
return new HTTPResponseOutputStream(raw);
|
||||
}
|
||||
}
|
@ -111,10 +111,13 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
|
||||
return startedOn;
|
||||
}
|
||||
|
||||
protected InputStream getSocketIn() throws IOException { return s.getInputStream(); }
|
||||
protected OutputStream getSocketOut() throws IOException { return s.getOutputStream(); }
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
InputStream in = s.getInputStream();
|
||||
OutputStream out = s.getOutputStream(); // = new BufferedOutputStream(s.getOutputStream(), NETWORK_BUFFER_SIZE);
|
||||
InputStream in = getSocketIn();
|
||||
OutputStream out = getSocketOut(); // = new BufferedOutputStream(s.getOutputStream(), NETWORK_BUFFER_SIZE);
|
||||
i2ps.setSocketErrorListener(this);
|
||||
InputStream i2pin = i2ps.getInputStream();
|
||||
OutputStream i2pout = i2ps.getOutputStream(); //new BufferedOutputStream(i2ps.getOutputStream(), MAX_PACKET_SIZE);
|
||||
|
@ -584,6 +584,7 @@ public class Connection {
|
||||
}
|
||||
}
|
||||
|
||||
/** how many packets have we sent and the other side has ACKed? */
|
||||
public long getAckedPackets() { return _ackedPackets; }
|
||||
public long getCreatedOn() { return _createdOn; }
|
||||
public long getCloseSentOn() { return _closeSentOn; }
|
||||
@ -599,6 +600,7 @@ public class Connection {
|
||||
|
||||
public void incrementUnackedPacketsReceived() { _unackedPacketsReceived++; }
|
||||
public int getUnackedPacketsReceived() { return _unackedPacketsReceived; }
|
||||
/** how many packets have we sent but not yet received an ACK for? */
|
||||
public int getUnackedPacketsSent() {
|
||||
synchronized (_outboundPackets) {
|
||||
return _outboundPackets.size();
|
||||
|
@ -132,6 +132,8 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver {
|
||||
private PacketLocal buildPacket(Connection con, byte buf[], int off, int size, boolean forceIncrement) {
|
||||
if (size > Packet.MAX_PAYLOAD_SIZE) throw new IllegalArgumentException("size is too large (" + size + ")");
|
||||
boolean ackOnly = isAckOnly(con, size);
|
||||
boolean isFirst = (con.getAckedPackets() <= 0) && (con.getUnackedPacketsSent() <= 0);
|
||||
|
||||
PacketLocal packet = new PacketLocal(_context, con.getRemotePeer(), con);
|
||||
//ByteArray data = packet.acquirePayload();
|
||||
ByteArray data = new ByteArray(new byte[size]);
|
||||
@ -140,7 +142,7 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver {
|
||||
data.setValid(size);
|
||||
data.setOffset(0);
|
||||
packet.setPayload(data);
|
||||
if (ackOnly && !forceIncrement)
|
||||
if ( (ackOnly && !forceIncrement) && (!isFirst) )
|
||||
packet.setSequenceNum(0);
|
||||
else
|
||||
packet.setSequenceNum(con.getNextOutboundPacketNum());
|
||||
@ -158,7 +160,8 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver {
|
||||
|
||||
packet.setFlag(Packet.FLAG_SIGNATURE_REQUESTED, con.getOptions().getRequireFullySigned());
|
||||
|
||||
if ( (!ackOnly) && (packet.getSequenceNum() <= 0) ) {
|
||||
//if ( (!ackOnly) && (packet.getSequenceNum() <= 0) ) {
|
||||
if (isFirst) {
|
||||
packet.setFlag(Packet.FLAG_SYNCHRONIZE);
|
||||
packet.setOptionalFrom(con.getSession().getMyDestination());
|
||||
packet.setOptionalMaxSize(con.getOptions().getMaxMessageSize());
|
||||
|
@ -160,6 +160,7 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
synchronized (this) {
|
||||
if (_ackOn > 0) break;
|
||||
if (_cancelledOn > 0) break;
|
||||
if (!_connection.getIsConnected()) break;
|
||||
if (timeRemaining > 60*1000)
|
||||
timeRemaining = 60*1000;
|
||||
else if (timeRemaining <= 0)
|
||||
|
@ -865,7 +865,7 @@ public class DataHelper {
|
||||
ReusableGZIPInputStream in = ReusableGZIPInputStream.acquire();
|
||||
in.initialize(new ByteArrayInputStream(orig, offset, length));
|
||||
|
||||
ByteCache cache = ByteCache.getInstance(16, MAX_UNCOMPRESSED);
|
||||
ByteCache cache = ByteCache.getInstance(8, MAX_UNCOMPRESSED);
|
||||
ByteArray outBuf = cache.acquire();
|
||||
int written = 0;
|
||||
while (true) {
|
||||
@ -877,6 +877,7 @@ public class DataHelper {
|
||||
byte rv[] = new byte[written];
|
||||
System.arraycopy(outBuf.getData(), 0, rv, 0, written);
|
||||
cache.release(outBuf);
|
||||
ReusableGZIPInputStream.release(in);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -134,8 +134,8 @@ public class Timestamper implements Runnable {
|
||||
try {
|
||||
lastFailed = !queryTime(serverList);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if (!lastFailed)
|
||||
_log.log(Log.CRIT, "Unable to reach any of the NTP servers - network disconnected?");
|
||||
if ( (!lastFailed) && (_log.shouldLog(Log.ERROR)) )
|
||||
_log.error("Unable to reach any of the NTP servers - network disconnected?");
|
||||
lastFailed = true;
|
||||
}
|
||||
}
|
||||
|
@ -238,8 +238,8 @@ public class OrderedProperties extends Properties {
|
||||
|
||||
public int compareTo(Object o) {
|
||||
if (o == null) return -1;
|
||||
if (o instanceof StringMapEntry) return ((String) getKey()).compareTo(((StringMapEntry) o).getKey());
|
||||
if (o instanceof String) return ((String) getKey()).compareTo(o);
|
||||
if (o instanceof StringMapEntry) return ((String) getKey()).compareTo((String)((StringMapEntry) o).getKey());
|
||||
if (o instanceof String) return ((String) getKey()).compareTo((String)o);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ import net.i2p.data.DataHelper;
|
||||
*
|
||||
*/
|
||||
public class ReusableGZIPInputStream extends ResettableGZIPInputStream {
|
||||
private static ArrayList _available = new ArrayList(16);
|
||||
private static ArrayList _available = new ArrayList(8);
|
||||
/**
|
||||
* Pull a cached instance
|
||||
*/
|
||||
@ -36,7 +36,7 @@ public class ReusableGZIPInputStream extends ResettableGZIPInputStream {
|
||||
*/
|
||||
public static void release(ReusableGZIPInputStream released) {
|
||||
synchronized (_available) {
|
||||
if (_available.size() < 16)
|
||||
if (_available.size() < 8)
|
||||
_available.add(released);
|
||||
}
|
||||
}
|
||||
|
11
history.txt
11
history.txt
@ -1,4 +1,13 @@
|
||||
$Id: history.txt,v 1.162 2005/03/02 22:36:52 jrandom Exp $
|
||||
$Id: history.txt,v 1.163 2005/03/04 01:09:51 jrandom Exp $
|
||||
|
||||
2005-03-04 jrandom
|
||||
* Filter HTTP response headers in the eepproxy, forcing Connection: close
|
||||
so that broken (/malicious) webservers can't allow persistent
|
||||
connections. All HTTP compliant browsers should now always close the
|
||||
socket.
|
||||
* Enabled the GZIPInputStream's cache (they were'nt cached before)
|
||||
* Make sure our first send is always a SYN (duh)
|
||||
* Workaround for some buggy compilers
|
||||
|
||||
2005-03-03 jrandom
|
||||
* Loop while starting up the I2PTunnel instances, in case the I2CP
|
||||
|
@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
public final static String ID = "$Revision: 1.157 $ $Date: 2005/03/02 22:36:53 $";
|
||||
public final static String ID = "$Revision: 1.158 $ $Date: 2005/03/04 01:09:20 $";
|
||||
public final static String VERSION = "0.5.0.1";
|
||||
public final static long BUILD = 9;
|
||||
public final static long BUILD = 10;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION);
|
||||
System.out.println("Router ID: " + RouterVersion.ID);
|
||||
|
@ -27,7 +27,7 @@ public class InboundGatewayReceiver implements TunnelGateway.Receiver {
|
||||
if (_target == null) {
|
||||
ReceiveJob j = null;
|
||||
if (!alreadySearched)
|
||||
j = new ReceiveJob(encrypted);
|
||||
j = new ReceiveJob(_context, encrypted);
|
||||
_context.netDb().lookupRouterInfo(_config.getSendTo(), j, j, 5*1000);
|
||||
return;
|
||||
}
|
||||
@ -47,8 +47,8 @@ public class InboundGatewayReceiver implements TunnelGateway.Receiver {
|
||||
|
||||
private class ReceiveJob extends JobImpl {
|
||||
private byte[] _encrypted;
|
||||
public ReceiveJob(byte data[]) {
|
||||
super(_context);
|
||||
public ReceiveJob(RouterContext ctx, byte data[]) {
|
||||
super(ctx);
|
||||
_encrypted = data;
|
||||
}
|
||||
public String getName() { return "lookup first hop"; }
|
||||
|
@ -42,7 +42,7 @@ class OutboundReceiver implements TunnelGateway.Receiver {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("lookup of " + _config.getPeer(1).toBase64().substring(0,4)
|
||||
+ " required for " + msg);
|
||||
_context.netDb().lookupRouterInfo(_config.getPeer(1), new SendJob(msg), new FailedJob(), 10*1000);
|
||||
_context.netDb().lookupRouterInfo(_config.getPeer(1), new SendJob(_context, msg), new FailedJob(_context), 10*1000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,8 +60,8 @@ class OutboundReceiver implements TunnelGateway.Receiver {
|
||||
|
||||
private class SendJob extends JobImpl {
|
||||
private TunnelDataMessage _msg;
|
||||
public SendJob(TunnelDataMessage msg) {
|
||||
super(_context);
|
||||
public SendJob(RouterContext ctx, TunnelDataMessage msg) {
|
||||
super(ctx);
|
||||
_msg = msg;
|
||||
}
|
||||
public String getName() { return "forward a tunnel message"; }
|
||||
@ -78,8 +78,8 @@ class OutboundReceiver implements TunnelGateway.Receiver {
|
||||
}
|
||||
|
||||
private class FailedJob extends JobImpl {
|
||||
public FailedJob() {
|
||||
super(_context);
|
||||
public FailedJob(RouterContext ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
public String getName() { return "failed looking for our outbound gateway"; }
|
||||
public void runJob() {
|
||||
|
@ -77,7 +77,7 @@ public class TunnelParticipant {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Lookup the nextHop (" + _config.getSendTo().toBase64().substring(0,4)
|
||||
+ " for " + msg);
|
||||
_context.netDb().lookupRouterInfo(_config.getSendTo(), new SendJob(msg), new TimeoutJob(msg), 10*1000);
|
||||
_context.netDb().lookupRouterInfo(_config.getSendTo(), new SendJob(_context, msg), new TimeoutJob(_context, msg), 10*1000);
|
||||
}
|
||||
} else {
|
||||
_inboundEndpointProcessor.getConfig().incrementProcessedMessages();
|
||||
@ -112,8 +112,8 @@ public class TunnelParticipant {
|
||||
|
||||
private class SendJob extends JobImpl {
|
||||
private TunnelDataMessage _msg;
|
||||
public SendJob(TunnelDataMessage msg) {
|
||||
super(_context);
|
||||
public SendJob(RouterContext ctx, TunnelDataMessage msg) {
|
||||
super(ctx);
|
||||
_msg = msg;
|
||||
}
|
||||
public String getName() { return "forward a tunnel message"; }
|
||||
@ -132,8 +132,8 @@ public class TunnelParticipant {
|
||||
|
||||
private class TimeoutJob extends JobImpl {
|
||||
private TunnelDataMessage _msg;
|
||||
public TimeoutJob(TunnelDataMessage msg) {
|
||||
super(_context);
|
||||
public TimeoutJob(RouterContext ctx, TunnelDataMessage msg) {
|
||||
super(ctx);
|
||||
_msg = msg;
|
||||
}
|
||||
public String getName() { return "timeout looking for next hop info"; }
|
||||
|
Reference in New Issue
Block a user