forked from I2P_Developers/i2p.i2p
Compare commits
90 Commits
i2p_0_5
...
i2p_0_5_0_
Author | SHA1 | Date | |
---|---|---|---|
![]() |
348e845793 | ||
![]() |
80827c3aad | ||
![]() |
3b4cf0a024 | ||
![]() |
941252fd80 | ||
![]() |
bc626ece2d | ||
![]() |
400feb3ba7 | ||
![]() |
756a4e3995 | ||
![]() |
578301240e | ||
![]() |
9b8f91c7f9 | ||
![]() |
c7c389d4fb | ||
![]() |
68f7adfa0b | ||
![]() |
c4ac5170c7 | ||
![]() |
32e0c8ac71 | ||
![]() |
c9c1eae32f | ||
![]() |
33366cc291 | ||
![]() |
083ac1f125 | ||
![]() |
80c6290b89 | ||
![]() |
6492ad165a | ||
![]() |
f0d1b1a40e | ||
![]() |
17f044e6cd | ||
![]() |
63f3a9cd7b | ||
![]() |
b8ddbf13b4 | ||
![]() |
be9bdbfe0f | ||
![]() |
bc74bf1402 | ||
![]() |
5c2a57f95a | ||
![]() |
9cd8cc692e | ||
![]() |
ebac4df2d3 | ||
![]() |
0626f714c6 | ||
![]() |
21842291e9 | ||
![]() |
d461c295f6 | ||
![]() |
85b3450525 | ||
![]() |
75d7c81b7c | ||
![]() |
1433e20f73 | ||
![]() |
e614a2f726 | ||
![]() |
32be7f1fd8 | ||
![]() |
66e1d95a2a | ||
![]() |
ff03be217e | ||
![]() |
a52f8b89dc | ||
![]() |
21c7c043b3 | ||
![]() |
45e6608ad3 | ||
![]() |
28978e3680 | ||
![]() |
904f755c8c | ||
![]() |
a2c309ddd3 | ||
![]() |
677eeac8f7 | ||
![]() |
b232cc0f24 | ||
![]() |
18bbae1d1e | ||
![]() |
08ee62b52c | ||
![]() |
5b83aed719 | ||
![]() |
b5875ca07b | ||
![]() |
3f9bf28382 | ||
![]() |
a2bd71c75b | ||
![]() |
89509490c5 | ||
![]() |
a997a46040 | ||
![]() |
538dd07e7b | ||
![]() |
046778404e | ||
![]() |
766f83d653 | ||
![]() |
b20aee6753 | ||
![]() |
f9aa3aef18 | ||
![]() |
d74aa6e53d | ||
![]() |
ea6fbc7835 | ||
![]() |
536e604b8e | ||
![]() |
49d6f5018f | ||
![]() |
4a830e422a | ||
![]() |
df6c52fe75 | ||
![]() |
01979c08b3 | ||
![]() |
7928ef83cc | ||
![]() |
10afe0a060 | ||
![]() |
ef230cfa3d | ||
![]() |
2d15a42137 | ||
![]() |
57d6a2f645 | ||
![]() |
469a0852d7 | ||
![]() |
7983bb1490 | ||
![]() |
2e7eac02ed | ||
![]() |
238389fc7f | ||
![]() |
4cec9da0a6 | ||
![]() |
00f27d4400 | ||
![]() |
f61618e4a4 | ||
![]() |
265d5e306e | ||
![]() |
10ed058c2e | ||
![]() |
8a21f0efec | ||
![]() |
b8291ac5a4 | ||
![]() |
c17433cb93 | ||
![]() |
35fe7f8203 | ||
![]() |
21f13dba43 | ||
![]() |
0db239a3fe | ||
![]() |
4745d61f9b | ||
![]() |
b9a4c3ba52 | ||
![]() |
cbf6a70a1a | ||
![]() |
7d4e093b58 | ||
![]() |
d27feabcb3 |
@@ -21,7 +21,8 @@
|
||||
<target name="distclean" depends="clean" />
|
||||
|
||||
<target name="compile" depends="init">
|
||||
<javac srcdir="${src}" destdir="${build}" classpath="${servlet}"/>
|
||||
<javac debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
srcdir="${src}" destdir="${build}" classpath="${servlet}"/>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
|
@@ -31,6 +31,9 @@
|
||||
</war>
|
||||
</target>
|
||||
<target name="precompilejsp">
|
||||
<delete dir="../jsp/WEB-INF/" />
|
||||
<delete file="../jsp/web-fragment.xml" />
|
||||
<delete file="../jsp/web-out.xml" />
|
||||
<mkdir dir="../jsp/WEB-INF/" />
|
||||
<mkdir dir="../jsp/WEB-INF/classes" />
|
||||
<!-- there are various jspc ant tasks, but they all seem a bit flakey -->
|
||||
@@ -53,7 +56,8 @@
|
||||
<arg value="-webapp" />
|
||||
<arg value="../jsp/" />
|
||||
</java>
|
||||
<javac destdir="../jsp/WEB-INF/classes/" srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
|
||||
<javac debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
destdir="../jsp/WEB-INF/classes/" srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
|
||||
<classpath>
|
||||
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
|
@@ -0,0 +1,242 @@
|
||||
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.ArrayList;
|
||||
import java.util.HashMap;
|
||||
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 = 8*1024;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.getData(), 0, _headerBuffer.getValid());
|
||||
newBuf.setValid(_headerBuffer.getValid());
|
||||
newBuf.setOffset(0);
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweak that first HTTP response line (HTTP 200 OK, etc)
|
||||
*
|
||||
*/
|
||||
protected String filterResponseLine(String line) {
|
||||
return line;
|
||||
}
|
||||
|
||||
/** 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 {
|
||||
String responseLine = null;
|
||||
|
||||
boolean connectionSent = false;
|
||||
boolean proxyConnectionSent = false;
|
||||
|
||||
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
|
||||
responseLine = filterResponseLine(responseLine);
|
||||
responseLine = (responseLine.trim() + "\n");
|
||||
out.write(responseLine.getBytes());
|
||||
} else {
|
||||
for (int j = lastEnd+1; j < i; j++) {
|
||||
if (_headerBuffer.getData()[j] == ':') {
|
||||
int keyLen = j-(lastEnd+1);
|
||||
int valLen = i-(j+2);
|
||||
if ( (keyLen <= 0) || (valLen <= 0) )
|
||||
throw new IOException("Invalid header @ " + j);
|
||||
String key = new String(_headerBuffer.getData(), lastEnd+1, keyLen);
|
||||
String val = new String(_headerBuffer.getData(), j+2, valLen);
|
||||
|
||||
if ("Connection".equalsIgnoreCase(key)) {
|
||||
out.write("Connection: close\n".getBytes());
|
||||
connectionSent = true;
|
||||
} else if ("Proxy-Connection".equalsIgnoreCase(key)) {
|
||||
out.write("Proxy-Connection: close\n".getBytes());
|
||||
proxyConnectionSent = true;
|
||||
} else {
|
||||
out.write((key.trim() + ": " + val.trim() + "\n").getBytes());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastEnd = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connectionSent)
|
||||
out.write("Connection: close\n".getBytes());
|
||||
if (!proxyConnectionSent)
|
||||
out.write("Proxy-Connection: close\n".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 invalid5 = "HTTP/1.1 200 OK\r\n" +
|
||||
"I am broken, and I smell\r\n" +
|
||||
"\r\n";
|
||||
String invalid6 = "HTTP/1.1 200 OK\r\n" +
|
||||
":I am broken, and I smell\r\n" +
|
||||
"\r\n";
|
||||
String invalid7 = "HTTP/1.1 200 OK\n" +
|
||||
"I am broken, and I smell:\n" +
|
||||
":asdf\n" +
|
||||
":\n" +
|
||||
"\n";
|
||||
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, true);
|
||||
test("Filtered", filtered, true);
|
||||
test("Filtered windows", winfilter, true);
|
||||
test("Minimal", minimal, true);
|
||||
test("Windows", winmin, true);
|
||||
test("Large", large, true);
|
||||
test("Invalid (short headers)", invalid1, true);
|
||||
test("Invalid (no headers)", invalid2, true);
|
||||
test("Invalid (windows with short headers)", invalid3, true);
|
||||
test("Invalid (windows no headers)", invalid4, true);
|
||||
test("Invalid (bad headers)", invalid5, true);
|
||||
test("Invalid (bad headers2)", invalid6, false);
|
||||
test("Invalid (bad headers3)", invalid7, false);
|
||||
/* */
|
||||
}
|
||||
|
||||
private static void test(String name, String orig, boolean shouldPass) {
|
||||
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) {
|
||||
if (shouldPass)
|
||||
e.printStackTrace();
|
||||
else
|
||||
System.out.println("Properly fails with " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,15 +12,12 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
@@ -104,11 +101,17 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
this.l = l;
|
||||
this.handlerName = handlerName + _clientId;
|
||||
|
||||
synchronized (sockLock) {
|
||||
if (ownDest) {
|
||||
sockMgr = buildSocketManager();
|
||||
} else {
|
||||
sockMgr = getSocketManager();
|
||||
while (sockMgr == null) {
|
||||
synchronized (sockLock) {
|
||||
if (ownDest) {
|
||||
sockMgr = buildSocketManager();
|
||||
} else {
|
||||
sockMgr = getSocketManager();
|
||||
}
|
||||
}
|
||||
if (sockMgr == null) {
|
||||
_log.log(Log.CRIT, "Unable to create socket manager");
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
if (sockMgr == null) {
|
||||
@@ -206,8 +209,24 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
props.putAll(System.getProperties());
|
||||
else
|
||||
props.putAll(tunnel.getClientOptions());
|
||||
I2PSocketManager sockManager = I2PSocketManagerFactory.createManager(tunnel.host, Integer.parseInt(tunnel.port), props);
|
||||
if (sockManager == null) return null;
|
||||
int portNum = 7654;
|
||||
if (tunnel.port != null) {
|
||||
try {
|
||||
portNum = Integer.parseInt(tunnel.port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.log(Log.CRIT, "Invalid port specified [" + tunnel.port + "], reverting to " + portNum);
|
||||
}
|
||||
}
|
||||
|
||||
I2PSocketManager sockManager = null;
|
||||
while (sockManager == null) {
|
||||
sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props);
|
||||
|
||||
if (sockManager == null) {
|
||||
_log.log(Log.CRIT, "Unable to create socket manager");
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
sockManager.setName("Client");
|
||||
return sockManager;
|
||||
}
|
||||
|
@@ -22,9 +22,7 @@ import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -196,9 +194,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "Line=[" + line + "]");
|
||||
|
||||
if (line.startsWith("Connection: ") ||
|
||||
line.startsWith("Keep-Alive: ") ||
|
||||
line.startsWith("Proxy-Connection: "))
|
||||
String lowercaseLine = line.toLowerCase();
|
||||
if (lowercaseLine.startsWith("connection: ") ||
|
||||
lowercaseLine.startsWith("keep-alive: ") ||
|
||||
lowercaseLine.startsWith("proxy-connection: "))
|
||||
continue;
|
||||
|
||||
if (method == null) { // first line (GET /base64/realaddr)
|
||||
@@ -337,29 +336,29 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
} else {
|
||||
if (line.startsWith("Host: ") && !usingWWWProxy) {
|
||||
if (lowercaseLine.startsWith("host: ") && !usingWWWProxy) {
|
||||
line = "Host: " + host;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix(requestId) + "Setting host = " + host);
|
||||
} else if (line.startsWith("User-Agent: ")) {
|
||||
} else if (lowercaseLine.startsWith("user-agent: ")) {
|
||||
// always stripped, added back at the end
|
||||
line = null;
|
||||
continue;
|
||||
} else if (line.startsWith("Accept")) {
|
||||
} else if (lowercaseLine.startsWith("accept")) {
|
||||
// strip the accept-blah headers, as they vary dramatically from
|
||||
// browser to browser
|
||||
line = null;
|
||||
continue;
|
||||
} else if (line.startsWith("Referer: ")) {
|
||||
} else if (lowercaseLine.startsWith("referer: ")) {
|
||||
// Shouldn't we be more specific, like accepting in-site referers ?
|
||||
//line = "Referer: i2p";
|
||||
line = null;
|
||||
continue; // completely strip the line
|
||||
} else if (line.startsWith("Via: ")) {
|
||||
} else if (lowercaseLine.startsWith("via: ")) {
|
||||
//line = "Via: i2p";
|
||||
line = null;
|
||||
continue; // completely strip the line
|
||||
} else if (line.startsWith("From: ")) {
|
||||
} else if (lowercaseLine.startsWith("from: ")) {
|
||||
//line = "From: i2p";
|
||||
line = null;
|
||||
continue; // completely strip the line
|
||||
@@ -418,7 +417,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);
|
||||
}
|
||||
}
|
@@ -4,7 +4,6 @@
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
@@ -17,7 +16,6 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
@@ -31,7 +30,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
|
||||
* Sun's impl of BufferedOutputStream), but that is the streaming
|
||||
* api's job...
|
||||
*/
|
||||
static int MAX_PACKET_SIZE = 1024 * 32;
|
||||
static int MAX_PACKET_SIZE = 1024 * 4;
|
||||
|
||||
static final int NETWORK_BUFFER_SIZE = MAX_PACKET_SIZE;
|
||||
|
||||
@@ -112,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);
|
||||
@@ -216,7 +218,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
|
||||
this.out = out;
|
||||
_toI2P = toI2P;
|
||||
direction = (toI2P ? "toI2P" : "fromI2P");
|
||||
_cache = ByteCache.getInstance(256, NETWORK_BUFFER_SIZE);
|
||||
_cache = ByteCache.getInstance(32, NETWORK_BUFFER_SIZE);
|
||||
setName("StreamForwarder " + _runnerId + "." + (++__forwarderId));
|
||||
start();
|
||||
}
|
||||
@@ -281,6 +283,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
|
||||
//else
|
||||
// _log.warn("You may ignore this", ex);
|
||||
} finally {
|
||||
_cache.release(ba);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info(direction + ": done forwarding between "
|
||||
+ from + " and " + to);
|
||||
@@ -302,7 +305,6 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
|
||||
finishLock.notifyAll();
|
||||
// the main thread will close sockets etc. now
|
||||
}
|
||||
_cache.release(ba);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -75,10 +75,25 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
I2PClient client = I2PClientFactory.createClient();
|
||||
Properties props = new Properties();
|
||||
props.putAll(getTunnel().getClientOptions());
|
||||
synchronized (slock) {
|
||||
sockMgr = I2PSocketManagerFactory.createManager(privData, getTunnel().host, Integer.parseInt(getTunnel().port),
|
||||
props);
|
||||
int portNum = 7654;
|
||||
if (getTunnel().port != null) {
|
||||
try {
|
||||
portNum = Integer.parseInt(getTunnel().port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.log(Log.CRIT, "Invalid port specified [" + getTunnel().port + "], reverting to " + portNum);
|
||||
}
|
||||
}
|
||||
|
||||
while (sockMgr == null) {
|
||||
synchronized (slock) {
|
||||
sockMgr = I2PSocketManagerFactory.createManager(privData, getTunnel().host, portNum,
|
||||
props);
|
||||
|
||||
}
|
||||
if (sockMgr == null) {
|
||||
_log.log(Log.CRIT, "Unable to create socket manager");
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
sockMgr.setName("Server");
|
||||
getTunnel().addSession(sockMgr.getSession());
|
||||
|
@@ -258,8 +258,16 @@ public class TunnelController implements Logging {
|
||||
if ("localhost".equals(_tunnel.host))
|
||||
_tunnel.host = "127.0.0.1";
|
||||
String port = getI2CPPort();
|
||||
if ( (port != null) && (port.length() > 0) )
|
||||
_tunnel.port = port;
|
||||
if ( (port != null) && (port.length() > 0) ) {
|
||||
try {
|
||||
int portNum = Integer.parseInt(port);
|
||||
_tunnel.port = String.valueOf(portNum);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_tunnel.port = "7654";
|
||||
}
|
||||
} else {
|
||||
_tunnel.port = "7654";
|
||||
}
|
||||
}
|
||||
|
||||
public void stopTunnel() {
|
||||
@@ -324,6 +332,18 @@ public class TunnelController implements Logging {
|
||||
public String getTargetDestination() { return _config.getProperty("targetDestination"); }
|
||||
public String getProxyList() { return _config.getProperty("proxyList"); }
|
||||
public boolean getStartOnLoad() { return "true".equalsIgnoreCase(_config.getProperty("startOnLoad", "true")); }
|
||||
public String getMyDestination() {
|
||||
if (_tunnel != null) {
|
||||
List sessions = _tunnel.getSessions();
|
||||
for (int i = 0; i < sessions.size(); i++) {
|
||||
I2PSession session = (I2PSession)sessions.get(i);
|
||||
Destination dest = session.getMyDestination();
|
||||
if (dest != null)
|
||||
return dest.toBase64();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean getIsRunning() { return _running; }
|
||||
public boolean getIsStarting() { return _starting; }
|
||||
|
@@ -1,12 +1,8 @@
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@@ -1,407 +0,0 @@
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Uuuugly code to generate the edit/add forms for the various
|
||||
* I2PTunnel types (httpclient/client/server)
|
||||
*
|
||||
*/
|
||||
class WebEditPageFormGenerator {
|
||||
private static final String SELECT_TYPE_FORM =
|
||||
"<form action=\"edit.jsp\"> Type of tunnel: <select name=\"type\">" +
|
||||
"<option value=\"httpclient\">HTTP proxy</option>" +
|
||||
"<option value=\"client\">Client tunnel</option>" +
|
||||
"<option value=\"server\">Server tunnel</option>" +
|
||||
"<option value=\"httpserver\">HTTP server tunnel</option>" +
|
||||
"</select> <input type=\"submit\" value=\"GO\" />" +
|
||||
"</form>\n";
|
||||
|
||||
/**
|
||||
* Retrieve the form requested
|
||||
*
|
||||
*/
|
||||
public static String getForm(WebEditPageHelper helper) {
|
||||
TunnelController controller = helper.getTunnelController();
|
||||
|
||||
if ( (helper.getType() == null) && (controller == null) )
|
||||
return SELECT_TYPE_FORM;
|
||||
|
||||
String id = helper.getNum();
|
||||
String type = helper.getType();
|
||||
if (controller != null)
|
||||
type = controller.getType();
|
||||
|
||||
if ("httpclient".equals(type))
|
||||
return getEditHttpClientForm(controller, id);
|
||||
else if ("client".equals(type))
|
||||
return getEditClientForm(controller, id);
|
||||
else if ("server".equals(type))
|
||||
return getEditServerForm(controller, id);
|
||||
else if ("httpserver".equals(type))
|
||||
return getEditHttpServerForm(controller, id);
|
||||
else
|
||||
return "WTF, unknown type [" + type + "]";
|
||||
}
|
||||
|
||||
private static String getEditHttpClientForm(TunnelController controller, String id) {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
addGeneral(buf, controller, id);
|
||||
buf.append("<b>Type:</b> <i>HTTP proxy</i><input type=\"hidden\" name=\"type\" value=\"httpclient\" /><br />\n");
|
||||
|
||||
addListeningOn(buf, controller, 4444);
|
||||
|
||||
buf.append("<b>Outproxies:</b> <input type=\"text\" name=\"proxyList\" size=\"20\" ");
|
||||
if ( (controller != null) && (controller.getProxyList() != null) )
|
||||
buf.append("value=\"").append(controller.getProxyList()).append("\" ");
|
||||
else
|
||||
buf.append("value=\"squid.i2p\" ");
|
||||
buf.append("/><br />\n");
|
||||
|
||||
buf.append("<hr />Note: the following options are shared across all client tunnels and");
|
||||
buf.append(" HTTP proxies<br />\n");
|
||||
|
||||
addOptions(buf, controller);
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\">\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
|
||||
buf.append(" <i>confirm removal:</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append("</form>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static String getEditClientForm(TunnelController controller, String id) {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
addGeneral(buf, controller, id);
|
||||
buf.append("<b>Type:</b> <i>Client tunnel</i><input type=\"hidden\" name=\"type\" value=\"client\" /><br />\n");
|
||||
|
||||
addListeningOn(buf, controller, 2025 + new Random().nextInt(1000)); // 2025 since nextInt can be negative
|
||||
|
||||
buf.append("<b>Target:</b> <input type=\"text\" size=\"40\" name=\"targetDestination\" ");
|
||||
if ( (controller != null) && (controller.getTargetDestination() != null) )
|
||||
buf.append("value=\"").append(controller.getTargetDestination()).append("\" ");
|
||||
buf.append(" /> (either the hosts.txt name or the full base64 destination)<br />\n");
|
||||
|
||||
buf.append("<hr />Note: the following options are shared across all client tunnels and");
|
||||
buf.append(" HTTP proxies<br />\n");
|
||||
|
||||
addOptions(buf, controller);
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\"><br />\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
|
||||
buf.append(" <i>confirm removal:</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append("</form>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static String getEditServerForm(TunnelController controller, String id) {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
addGeneral(buf, controller, id);
|
||||
buf.append("<b>Type:</b> <i>Server tunnel</i><input type=\"hidden\" name=\"type\" value=\"server\" /><br />\n");
|
||||
|
||||
buf.append("<b>Target host:</b> <input type=\"text\" size=\"40\" name=\"targetHost\" ");
|
||||
if ( (controller != null) && (controller.getTargetHost() != null) )
|
||||
buf.append("value=\"").append(controller.getTargetHost()).append("\" ");
|
||||
else
|
||||
buf.append("value=\"127.0.0.1\" ");
|
||||
buf.append(" /><br />\n");
|
||||
|
||||
buf.append("<b>Target port:</b> <input type=\"text\" size=\"4\" name=\"targetPort\" ");
|
||||
if ( (controller != null) && (controller.getTargetPort() != null) )
|
||||
buf.append("value=\"").append(controller.getTargetPort()).append("\" ");
|
||||
else
|
||||
buf.append("value=\"80\" ");
|
||||
buf.append(" /><br />\n");
|
||||
|
||||
buf.append("<b>Private key file:</b> <input type=\"text\" name=\"privKeyFile\" value=\"");
|
||||
if ( (controller != null) && (controller.getPrivKeyFile() != null) ) {
|
||||
buf.append(controller.getPrivKeyFile()).append("\" /><br />");
|
||||
} else {
|
||||
buf.append("myServer.privKey\" /><br />");
|
||||
buf.append("<input type=\"hidden\" name=\"privKeyGenerate\" value=\"true\" />");
|
||||
}
|
||||
|
||||
addOptions(buf, controller);
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\">\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
|
||||
buf.append(" <i>confirm removal:</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append("</form>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static String getEditHttpServerForm(TunnelController controller, String id) {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
addGeneral(buf, controller, id);
|
||||
buf.append("<b>Type:</b> <i>HTTP server tunnel</i><input type=\"hidden\" name=\"type\" value=\"httpserver\" /><br />\n");
|
||||
|
||||
buf.append("<b>Target host:</b> <input type=\"text\" size=\"40\" name=\"targetHost\" ");
|
||||
if ( (controller != null) && (controller.getTargetHost() != null) )
|
||||
buf.append("value=\"").append(controller.getTargetHost()).append("\" ");
|
||||
else
|
||||
buf.append("value=\"127.0.0.1\" ");
|
||||
buf.append(" /><br />\n");
|
||||
|
||||
buf.append("<b>Target port:</b> <input type=\"text\" size=\"4\" name=\"targetPort\" ");
|
||||
if ( (controller != null) && (controller.getTargetPort() != null) )
|
||||
buf.append("value=\"").append(controller.getTargetPort()).append("\" ");
|
||||
else
|
||||
buf.append("value=\"80\" ");
|
||||
buf.append(" /><br />\n");
|
||||
|
||||
buf.append("<b>Website hostname:</b> <input type=\"text\" size=\"16\" name=\"spoofedHost\" ");
|
||||
if ( (controller != null) && (controller.getSpoofedHost() != null) )
|
||||
buf.append("value=\"").append(controller.getSpoofedHost()).append("\" ");
|
||||
else
|
||||
buf.append("value=\"mysite.i2p\" ");
|
||||
buf.append(" /><br />\n");
|
||||
|
||||
buf.append("<b>Private key file:</b> <input type=\"text\" name=\"privKeyFile\" value=\"");
|
||||
if ( (controller != null) && (controller.getPrivKeyFile() != null) ) {
|
||||
buf.append(controller.getPrivKeyFile()).append("\" /><br />");
|
||||
} else {
|
||||
buf.append("myServer.privKey\" /><br />");
|
||||
buf.append("<input type=\"hidden\" name=\"privKeyGenerate\" value=\"true\" />");
|
||||
}
|
||||
|
||||
addOptions(buf, controller);
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\">\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
|
||||
buf.append(" <i>confirm removal:</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append("</form>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start off the form and add some common fields (name, num, description)
|
||||
*
|
||||
* @param buf where to shove the form
|
||||
* @param controller tunnel in question, or null if we're creating a new tunnel
|
||||
* @param id index into the current list of tunnelControllerGroup.getControllers() list
|
||||
* (or null if we are generating an 'add' form)
|
||||
*/
|
||||
private static void addGeneral(StringBuffer buf, TunnelController controller, String id) {
|
||||
buf.append("<form action=\"edit.jsp\">");
|
||||
if (id != null)
|
||||
buf.append("<input type=\"hidden\" name=\"num\" value=\"").append(id).append("\" />");
|
||||
long nonce = new Random().nextLong();
|
||||
System.setProperty(WebEditPageHelper.class.getName() + ".nonce", nonce+"");
|
||||
buf.append("<input type=\"hidden\" name=\"nonce\" value=\"").append(nonce).append("\" />");
|
||||
|
||||
buf.append("<b>Name:</b> <input type=\"text\" name=\"name\" size=\"20\" ");
|
||||
if ( (controller != null) && (controller.getName() != null) )
|
||||
buf.append("value=\"").append(controller.getName()).append("\" ");
|
||||
buf.append("/><br />\n");
|
||||
|
||||
buf.append("<b>Description:</b> <input type=\"text\" name=\"description\" size=\"60\" ");
|
||||
if ( (controller != null) && (controller.getDescription() != null) )
|
||||
buf.append("value=\"").append(controller.getDescription()).append("\" ");
|
||||
buf.append("/><br />\n");
|
||||
|
||||
buf.append("<b>Start automatically?</b> \n");
|
||||
buf.append("<input type=\"checkbox\" name=\"startOnLoad\" value=\"true\" ");
|
||||
if ( (controller != null) && (controller.getStartOnLoad()) )
|
||||
buf.append(" checked=\"true\" />\n<br />\n");
|
||||
else
|
||||
buf.append(" />\n<br />\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the fields asking for what port and interface the tunnel should
|
||||
* listen on.
|
||||
*
|
||||
* @param buf where to shove the form
|
||||
* @param controller tunnel in question, or null if we're creating a new tunnel
|
||||
* @param defaultPort if we are creating a new tunnel, default the form to the given port
|
||||
*/
|
||||
private static void addListeningOn(StringBuffer buf, TunnelController controller, int defaultPort) {
|
||||
buf.append("<b>Listening on port:</b> <input type=\"text\" name=\"port\" size=\"20\" ");
|
||||
if ( (controller != null) && (controller.getListenPort() != null) )
|
||||
buf.append("value=\"").append(controller.getListenPort()).append("\" ");
|
||||
else
|
||||
buf.append("value=\"").append(defaultPort).append("\" ");
|
||||
buf.append("/><br />\n");
|
||||
|
||||
String selectedOn = null;
|
||||
if ( (controller != null) && (controller.getListenOnInterface() != null) )
|
||||
selectedOn = controller.getListenOnInterface();
|
||||
|
||||
buf.append("<b>Reachable by:</b> ");
|
||||
buf.append("<select name=\"reachableBy\">");
|
||||
buf.append("<option value=\"127.0.0.1\" ");
|
||||
if ( (selectedOn != null) && ("127.0.0.1".equals(selectedOn)) )
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append(">Locally (127.0.0.1)</option>\n");
|
||||
buf.append("<option value=\"0.0.0.0\" ");
|
||||
if ( (selectedOn != null) && ("0.0.0.0".equals(selectedOn)) )
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append(">Everyone (0.0.0.0)</option>\n");
|
||||
buf.append("</select> ");
|
||||
buf.append("Other: <input type=\"text\" name=\"reachableByOther\" value=\"");
|
||||
if ( (selectedOn != null) && (!"127.0.0.1".equals(selectedOn)) && (!"0.0.0.0".equals(selectedOn)) )
|
||||
buf.append(selectedOn);
|
||||
buf.append("\"><br />\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fields for customizing the I2PSession options, including helpers for
|
||||
* tunnel depth and count, as well as I2CP host and port.
|
||||
*
|
||||
* @param buf where to shove the form
|
||||
* @param controller tunnel in question, or null if we're creating a new tunnel
|
||||
*/
|
||||
private static void addOptions(StringBuffer buf, TunnelController controller) {
|
||||
int tunnelDepth = 2;
|
||||
int numTunnels = 2;
|
||||
int connectDelay = 0;
|
||||
int maxWindowSize = -1;
|
||||
Properties opts = getOptions(controller);
|
||||
if (opts != null) {
|
||||
String depth = opts.getProperty("inbound.length");
|
||||
if (depth != null) {
|
||||
try {
|
||||
tunnelDepth = Integer.parseInt(depth);
|
||||
} catch (NumberFormatException nfe) {
|
||||
tunnelDepth = 2;
|
||||
}
|
||||
}
|
||||
String num = opts.getProperty("inbound.quantity");
|
||||
if (num != null) {
|
||||
try {
|
||||
numTunnels = Integer.parseInt(num);
|
||||
} catch (NumberFormatException nfe) {
|
||||
numTunnels = 2;
|
||||
}
|
||||
}
|
||||
String delay = opts.getProperty("i2p.streaming.connectDelay");
|
||||
if (delay != null) {
|
||||
try {
|
||||
connectDelay = Integer.parseInt(delay);
|
||||
} catch (NumberFormatException nfe) {
|
||||
connectDelay = 0;
|
||||
}
|
||||
}
|
||||
String max = opts.getProperty("i2p.streaming.maxWindowSize");
|
||||
if (max != null) {
|
||||
try {
|
||||
maxWindowSize = Integer.parseInt(max);
|
||||
} catch (NumberFormatException nfe) {
|
||||
maxWindowSize = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf.append("<b>Tunnel depth:</b> ");
|
||||
buf.append("<select name=\"tunnelDepth\">");
|
||||
buf.append("<option value=\"0\" ");
|
||||
if (tunnelDepth == 0) buf.append(" selected=\"true\" ");
|
||||
buf.append(">0 hop tunnel (low anonymity, low latency)</option>");
|
||||
buf.append("<option value=\"1\" ");
|
||||
if (tunnelDepth == 1) buf.append(" selected=\"true\" ");
|
||||
buf.append(">1 hop tunnel (medium anonymity, medium latency)</option>");
|
||||
buf.append("<option value=\"2\" ");
|
||||
if (tunnelDepth == 2) buf.append(" selected=\"true\" ");
|
||||
buf.append(">2 hop tunnel (high anonymity, high latency)</option>");
|
||||
if (tunnelDepth > 2) {
|
||||
buf.append("<option value=\"").append(tunnelDepth).append("\" selected=\"true\" >");
|
||||
buf.append(tunnelDepth);
|
||||
buf.append(" hop tunnel (custom)</option>");
|
||||
}
|
||||
buf.append("</select><br />\n");
|
||||
|
||||
buf.append("<b>Tunnel count:</b> ");
|
||||
buf.append("<select name=\"tunnelCount\">");
|
||||
buf.append("<option value=\"1\" ");
|
||||
if (numTunnels == 1) buf.append(" selected=\"true\" ");
|
||||
buf.append(">1 inbound tunnel (low bandwidth usage, less reliability)</option>");
|
||||
buf.append("<option value=\"2\" ");
|
||||
if (numTunnels == 2) buf.append(" selected=\"true\" ");
|
||||
buf.append(">2 inbound tunnels (standard bandwidth usage, standard reliability)</option>");
|
||||
buf.append("<option value=\"3\" ");
|
||||
if (numTunnels == 3) buf.append(" selected=\"true\" ");
|
||||
buf.append(">3 inbound tunnels (higher bandwidth usage, higher reliability)</option>");
|
||||
|
||||
if (numTunnels > 3) {
|
||||
buf.append("<option value=\"").append(numTunnels).append("\" selected=\"true\" >");
|
||||
buf.append(numTunnels);
|
||||
buf.append(" inbound tunnels (custom)</option>");
|
||||
}
|
||||
buf.append("</select><br />\n");
|
||||
|
||||
buf.append("<b>Delay connection briefly? </b> ");
|
||||
buf.append("<input type=\"checkbox\" name=\"connectDelay\" value=\"");
|
||||
buf.append((connectDelay > 0 ? connectDelay : 1000)).append("\" ");
|
||||
if (connectDelay > 0)
|
||||
buf.append("checked=\"true\" ");
|
||||
buf.append("/> (useful for brief request/response connections)<br />\n");
|
||||
|
||||
buf.append("<b>Communication profile:</b>");
|
||||
buf.append("<select name=\"profile\">");
|
||||
if (maxWindowSize <= 0)
|
||||
buf.append("<option value=\"interactive\">Interactive</option><option value=\"bulk\" selected=\"true\">Bulk</option>");
|
||||
else
|
||||
buf.append("<option value=\"interactive\" selected=\"true\">Interactive</option><option value=\"bulk\">Bulk</option>");
|
||||
buf.append("</select><br />\n");
|
||||
|
||||
buf.append("<b>I2CP host:</b> ");
|
||||
buf.append("<input type=\"text\" name=\"clientHost\" size=\"20\" value=\"");
|
||||
if ( (controller != null) && (controller.getI2CPHost() != null) )
|
||||
buf.append(controller.getI2CPHost());
|
||||
else
|
||||
buf.append("127.0.0.1");
|
||||
buf.append("\" /><br />\n");
|
||||
buf.append("<b>I2CP port:</b> ");
|
||||
buf.append("<input type=\"text\" name=\"clientPort\" size=\"20\" value=\"");
|
||||
if ( (controller != null) && (controller.getI2CPPort() != null) )
|
||||
buf.append(controller.getI2CPPort());
|
||||
else
|
||||
buf.append("7654");
|
||||
buf.append("\" /><br />\n");
|
||||
|
||||
buf.append("<b>Other custom options:</b> \n");
|
||||
buf.append("<input type=\"text\" name=\"customOptions\" size=\"60\" value=\"");
|
||||
if (opts != null) {
|
||||
int i = 0;
|
||||
for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = opts.getProperty(key);
|
||||
if ("inbound.length".equals(key)) continue;
|
||||
if ("outbound.length".equals(key)) continue;
|
||||
if ("inbound.quantity".equals(key)) continue;
|
||||
if ("outbound.quantity".equals(key)) continue;
|
||||
if ("inbound.nickname".equals(key)) continue;
|
||||
if ("outbound.nickname".equals(key)) continue;
|
||||
if ("i2p.streaming.connectDelay".equals(key)) continue;
|
||||
if ("i2p.streaming.maxWindowSize".equals(key)) continue;
|
||||
if (i != 0) buf.append(' ');
|
||||
buf.append(key).append('=').append(val);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
buf.append("\" /><br />\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the client options from the tunnel
|
||||
*
|
||||
* @return map of name=val to be used as I2P session options
|
||||
*/
|
||||
private static Properties getOptions(TunnelController controller) {
|
||||
if (controller == null) return null;
|
||||
String opts = controller.getClientOptions();
|
||||
StringTokenizer tok = new StringTokenizer(opts);
|
||||
Properties props = new Properties();
|
||||
while (tok.hasMoreTokens()) {
|
||||
String pair = tok.nextToken();
|
||||
int eq = pair.indexOf('=');
|
||||
if ( (eq <= 0) || (eq >= pair.length()) )
|
||||
continue;
|
||||
String key = pair.substring(0, eq);
|
||||
String val = pair.substring(eq+1);
|
||||
props.setProperty(key, val);
|
||||
}
|
||||
return props;
|
||||
}
|
||||
}
|
@@ -1,213 +0,0 @@
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.util.List;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Ugly hack to let the web interface access the list of known tunnels and
|
||||
* control their operation. Any data submitted by setting properties are
|
||||
* acted upon by calling getActionResults() (which returns any messages
|
||||
* generated). In addition, the getSummaryList() generates the html for
|
||||
* summarizing all of the tunnels known, including both their status and the
|
||||
* links to edit, stop, or start them.
|
||||
*
|
||||
*/
|
||||
public class WebStatusPageHelper {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private String _action;
|
||||
private int _controllerNum;
|
||||
private long _nonce;
|
||||
|
||||
public WebStatusPageHelper() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_action = null;
|
||||
_controllerNum = -1;
|
||||
_log = _context.logManager().getLog(WebStatusPageHelper.class);
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
_action = action;
|
||||
}
|
||||
public void setNum(String num) {
|
||||
if (num != null) {
|
||||
try {
|
||||
_controllerNum = Integer.parseInt(num);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_controllerNum = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void setNonce(long nonce) { _nonce = nonce; }
|
||||
public void setNonce(String nonce) {
|
||||
if (nonce != null) {
|
||||
try {
|
||||
_nonce = Long.parseLong(nonce);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
}
|
||||
|
||||
public String getActionResults() {
|
||||
try {
|
||||
return processAction();
|
||||
} catch (Throwable t) {
|
||||
_log.log(Log.CRIT, "Internal error processing web status", t);
|
||||
return "Internal error processing request - " + t.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public String getSummaryList() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "<b>I2PTunnel instances not yet started - please be patient</b>\n";
|
||||
|
||||
long nonce = _context.random().nextLong();
|
||||
StringBuffer buf = new StringBuffer(4*1024);
|
||||
buf.append("<ul>");
|
||||
List tunnels = group.getControllers();
|
||||
for (int i = 0; i < tunnels.size(); i++) {
|
||||
buf.append("<li>\n");
|
||||
getSummary(buf, i, (TunnelController)tunnels.get(i), nonce);
|
||||
buf.append("</li>\n");
|
||||
}
|
||||
buf.append("</ul>");
|
||||
|
||||
buf.append("<hr /><form action=\"index.jsp\" method=\"GET\">\n");
|
||||
buf.append("<input type=\"hidden\" name=\"nonce\" value=\"").append(nonce).append("\" />\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Stop all\" />\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Start all\" />\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Restart all\" />\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Reload config\" />\n");
|
||||
buf.append("</form>\n");
|
||||
|
||||
System.setProperty(getClass().getName() + ".nonce", nonce+"");
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void getSummary(StringBuffer buf, int num, TunnelController controller, long nonce) {
|
||||
buf.append("<b>").append(controller.getName()).append("</b>: ");
|
||||
if (controller.getIsRunning()) {
|
||||
buf.append("<i>running</i> ");
|
||||
buf.append("<a href=\"index.jsp?num=").append(num);
|
||||
buf.append("&nonce=").append(nonce);
|
||||
buf.append("&action=stop\">stop</a> ");
|
||||
} else if (controller.getIsStarting()) {
|
||||
buf.append("<i>startup in progress (please be patient)</i>");
|
||||
} else {
|
||||
buf.append("<i>not running</i> ");
|
||||
buf.append("<a href=\"index.jsp?num=").append(num);
|
||||
buf.append("&nonce=").append(nonce);
|
||||
buf.append("&action=start\">start</a> ");
|
||||
}
|
||||
buf.append("<a href=\"edit.jsp?num=").append(num).append("\">edit</a> ");
|
||||
buf.append("<br />\n");
|
||||
controller.getSummary(buf);
|
||||
}
|
||||
|
||||
private String processAction() {
|
||||
if ( (_action == null) || (_action.trim().length() <= 0) )
|
||||
return getMessages();
|
||||
String expected = System.getProperty(getClass().getName() + ".nonce");
|
||||
if ( (expected == null) || (!expected.equals(Long.toString(_nonce))) )
|
||||
return "<b>Invalid nonce, are you being spoofed?</b>";
|
||||
if ("Stop all".equals(_action))
|
||||
return stopAll();
|
||||
else if ("Start all".equals(_action))
|
||||
return startAll();
|
||||
else if ("Restart all".equals(_action))
|
||||
return restartAll();
|
||||
else if ("Reload config".equals(_action))
|
||||
return reloadConfig();
|
||||
else if ("stop".equals(_action))
|
||||
return stop();
|
||||
else if ("start".equals(_action))
|
||||
return start();
|
||||
else
|
||||
return "Action <i>" + _action + "</i> unknown";
|
||||
}
|
||||
private String stopAll() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "<b>I2PTunnel instances not yet started - please be patient</b>\n";
|
||||
|
||||
List msgs = group.stopAllControllers();
|
||||
return getMessages(msgs);
|
||||
}
|
||||
private String startAll() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "<b>I2PTunnel instances not yet started - please be patient</b>\n";
|
||||
|
||||
List msgs = group.startAllControllers();
|
||||
return getMessages(msgs);
|
||||
}
|
||||
private String restartAll() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "<b>I2PTunnel instances not yet started - please be patient</b>\n";
|
||||
|
||||
List msgs = group.restartAllControllers();
|
||||
return getMessages(msgs);
|
||||
}
|
||||
private String reloadConfig() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "<b>I2PTunnel instances not yet started - please be patient</b>\n";
|
||||
|
||||
group.reloadControllers();
|
||||
return "Config reloaded";
|
||||
}
|
||||
private String start() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "<b>I2PTunnel instances not yet started - please be patient</b>\n";
|
||||
|
||||
if (_controllerNum < 0) return "Invalid tunnel";
|
||||
|
||||
List controllers = group.getControllers();
|
||||
if (_controllerNum >= controllers.size()) return "Invalid tunnel";
|
||||
TunnelController controller = (TunnelController)controllers.get(_controllerNum);
|
||||
controller.startTunnelBackground();
|
||||
return getMessages(controller.clearMessages());
|
||||
}
|
||||
|
||||
private String stop() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "<b>I2PTunnel instances not yet started - please be patient</b>\n";
|
||||
|
||||
if (_controllerNum < 0) return "Invalid tunnel";
|
||||
|
||||
List controllers = group.getControllers();
|
||||
if (_controllerNum >= controllers.size()) return "Invalid tunnel";
|
||||
TunnelController controller = (TunnelController)controllers.get(_controllerNum);
|
||||
controller.stopTunnel();
|
||||
return getMessages(controller.clearMessages());
|
||||
}
|
||||
|
||||
private String getMessages() {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
if (group == null)
|
||||
return "";
|
||||
|
||||
return getMessages(group.clearAllMessages());
|
||||
}
|
||||
|
||||
private String getMessages(List msgs) {
|
||||
if (msgs == null) return "";
|
||||
int num = msgs.size();
|
||||
switch (num) {
|
||||
case 0: return "";
|
||||
case 1: return (String)msgs.get(0);
|
||||
default:
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
buf.append("<ul>");
|
||||
for (int i = 0; i < num; i++)
|
||||
buf.append("<li>").append((String)msgs.get(i)).append("</li>\n");
|
||||
buf.append("</ul>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,7 +14,6 @@ import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.i2ptunnel.I2PTunnel;
|
||||
import net.i2p.util.Log;
|
||||
|
217
apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
Normal file
217
apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
Normal file
@@ -0,0 +1,217 @@
|
||||
package net.i2p.i2ptunnel.web;
|
||||
/*
|
||||
* 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.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Ugly little accessor for the edit page
|
||||
*/
|
||||
public class EditBean extends IndexBean {
|
||||
public EditBean() { super(); }
|
||||
|
||||
public static boolean staticIsClient(int tunnel) {
|
||||
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
|
||||
List controllers = group.getControllers();
|
||||
if (controllers.size() > tunnel) {
|
||||
TunnelController cur = (TunnelController)controllers.get(tunnel);
|
||||
if (cur == null) return false;
|
||||
return ( ("client".equals(cur.getType())) || ("httpclient".equals(cur.getType())) );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getTargetHost(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getTargetHost();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
public String getTargetPort(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getTargetPort();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
public String getSpoofedHost(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getSpoofedHost();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
public String getPrivateKeyFile(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getPrivKeyFile();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean startAutomatically(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getStartOnLoad();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldDelay(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts != null) {
|
||||
String delay = opts.getProperty("i2p.streaming.connectDelay");
|
||||
if ( (delay == null) || ("0".equals(delay)) )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInteractive(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts != null) {
|
||||
String wsiz = opts.getProperty("i2p.streaming.maxWindowSize");
|
||||
if ( (wsiz == null) || (!"1".equals(wsiz)) )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTunnelDepth(int tunnel, int defaultLength) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts != null) {
|
||||
String len = opts.getProperty("inbound.length");
|
||||
if (len == null) return defaultLength;
|
||||
try {
|
||||
return Integer.parseInt(len);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return defaultLength;
|
||||
}
|
||||
} else {
|
||||
return defaultLength;
|
||||
}
|
||||
} else {
|
||||
return defaultLength;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTunnelCount(int tunnel, int defaultCount) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts != null) {
|
||||
String len = opts.getProperty("inbound.quantity");
|
||||
if (len == null) return defaultCount;
|
||||
try {
|
||||
return Integer.parseInt(len);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return defaultCount;
|
||||
}
|
||||
} else {
|
||||
return defaultCount;
|
||||
}
|
||||
} else {
|
||||
return defaultCount;
|
||||
}
|
||||
}
|
||||
|
||||
public String getI2CPHost(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getI2CPHost();
|
||||
else
|
||||
return "localhost";
|
||||
}
|
||||
|
||||
public String getI2CPPort(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getI2CPPort();
|
||||
else
|
||||
return "7654";
|
||||
}
|
||||
|
||||
public String getCustomOptions(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts == null) return "";
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
int i = 0;
|
||||
for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = opts.getProperty(key);
|
||||
if ("inbound.length".equals(key)) continue;
|
||||
if ("outbound.length".equals(key)) continue;
|
||||
if ("inbound.quantity".equals(key)) continue;
|
||||
if ("outbound.quantity".equals(key)) continue;
|
||||
if ("inbound.nickname".equals(key)) continue;
|
||||
if ("outbound.nickname".equals(key)) continue;
|
||||
if ("i2p.streaming.connectDelay".equals(key)) continue;
|
||||
if ("i2p.streaming.maxWindowSize".equals(key)) continue;
|
||||
if (i != 0) buf.append(' ');
|
||||
buf.append(key).append('=').append(val);
|
||||
i++;
|
||||
}
|
||||
return buf.toString();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the client options from the tunnel
|
||||
*
|
||||
* @return map of name=val to be used as I2P session options
|
||||
*/
|
||||
private static Properties getOptions(TunnelController controller) {
|
||||
if (controller == null) return null;
|
||||
String opts = controller.getClientOptions();
|
||||
StringTokenizer tok = new StringTokenizer(opts);
|
||||
Properties props = new Properties();
|
||||
while (tok.hasMoreTokens()) {
|
||||
String pair = tok.nextToken();
|
||||
int eq = pair.indexOf('=');
|
||||
if ( (eq <= 0) || (eq >= pair.length()) )
|
||||
continue;
|
||||
String key = pair.substring(0, eq);
|
||||
String val = pair.substring(eq+1);
|
||||
props.setProperty(key, val);
|
||||
}
|
||||
return props;
|
||||
}
|
||||
}
|
@@ -1,28 +1,38 @@
|
||||
package net.i2p.i2ptunnel;
|
||||
package net.i2p.i2ptunnel.web;
|
||||
/*
|
||||
* 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.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* UUUUuuuuuugly glue code to handle bean interaction from the web, process
|
||||
* that data, and spit out the results (or the form requested). The basic
|
||||
* usage is to set any of the fields with data then query the bean via
|
||||
* getActionResults() which triggers the request processing (taking all the
|
||||
* provided data, doing what needs to be done) and returns the results of those
|
||||
* activites. Then a subsequent call to getEditForm() generates the HTML form
|
||||
* to either edit the currently selected tunnel (if specified) or add a new one.
|
||||
* This functionality is delegated to the WebEditPageFormGenerator.
|
||||
* Simple accessor for exposing tunnel info, but also an ugly form handler
|
||||
*
|
||||
*/
|
||||
public class WebEditPageHelper {
|
||||
private Log _log;
|
||||
public class IndexBean {
|
||||
protected I2PAppContext _context;
|
||||
protected Log _log;
|
||||
protected TunnelControllerGroup _group;
|
||||
private String _action;
|
||||
private int _tunnel;
|
||||
private long _prevNonce;
|
||||
private long _curNonce;
|
||||
private long _nextNonce;
|
||||
private String _passphrase;
|
||||
|
||||
private String _type;
|
||||
private String _id;
|
||||
private String _name;
|
||||
private String _description;
|
||||
private String _i2cpHost;
|
||||
@@ -44,30 +54,327 @@ public class WebEditPageHelper {
|
||||
private boolean _startOnLoad;
|
||||
private boolean _privKeyGenerate;
|
||||
private boolean _removeConfirmed;
|
||||
private long _nonce;
|
||||
|
||||
public WebEditPageHelper() {
|
||||
public static final int RUNNING = 1;
|
||||
public static final int STARTING = 2;
|
||||
public static final int NOT_RUNNING = 3;
|
||||
|
||||
public static final String PROP_TUNNEL_PASSPHRASE = "i2ptunnel.passphrase";
|
||||
static final String PROP_NONCE = IndexBean.class.getName() + ".nonce";
|
||||
static final String CLIENT_NICKNAME = "shared clients";
|
||||
|
||||
public IndexBean() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(IndexBean.class);
|
||||
_group = TunnelControllerGroup.getInstance();
|
||||
_action = null;
|
||||
_type = null;
|
||||
_id = null;
|
||||
_removeConfirmed = false;
|
||||
_log = I2PAppContext.getGlobalContext().logManager().getLog(WebEditPageHelper.class);
|
||||
_tunnel = -1;
|
||||
_curNonce = -1;
|
||||
_prevNonce = -1;
|
||||
try {
|
||||
String nonce = System.getProperty(PROP_NONCE);
|
||||
if (nonce != null)
|
||||
_prevNonce = Long.parseLong(nonce);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
_nextNonce = _context.random().nextLong();
|
||||
System.setProperty(PROP_NONCE, Long.toString(_nextNonce));
|
||||
}
|
||||
|
||||
public long getNextNonce() { return _nextNonce; }
|
||||
public void setNonce(String nonce) {
|
||||
if (nonce != null) {
|
||||
try {
|
||||
_nonce = Long.parseLong(nonce);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
if ( (nonce == null) || (nonce.trim().length() <= 0) ) return;
|
||||
try {
|
||||
_curNonce = Long.parseLong(nonce);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_curNonce = -1;
|
||||
}
|
||||
}
|
||||
public void setPassphrase(String phrase) {
|
||||
_passphrase = phrase;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
if ( (action == null) || (action.trim().length() <= 0) ) return;
|
||||
_action = action;
|
||||
}
|
||||
public void setTunnel(String tunnel) {
|
||||
if ( (tunnel == null) || (tunnel.trim().length() <= 0) ) return;
|
||||
try {
|
||||
_tunnel = Integer.parseInt(tunnel);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_tunnel = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for form submit - either "Save" or Remove"
|
||||
*/
|
||||
public void setAction(String action) {
|
||||
_action = (action != null ? action.trim() : null);
|
||||
private boolean validPassphrase(String proposed) {
|
||||
if (proposed == null) return false;
|
||||
String pass = _context.getProperty(PROP_TUNNEL_PASSPHRASE);
|
||||
if ( (pass != null) && (pass.trim().length() > 0) )
|
||||
return pass.trim().equals(proposed.trim());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private String processAction() {
|
||||
if ( (_action == null) || (_action.trim().length() <= 0) )
|
||||
return "";
|
||||
if ( (_prevNonce != _curNonce) && (!validPassphrase(_passphrase)) )
|
||||
return "Invalid nonce, are you being spoofed?";
|
||||
if ("Stop all tunnels".equals(_action))
|
||||
return stopAll();
|
||||
else if ("Start all tunnels".equals(_action))
|
||||
return startAll();
|
||||
else if ("Restart all".equals(_action))
|
||||
return restartAll();
|
||||
else if ("Reload config".equals(_action))
|
||||
return reloadConfig();
|
||||
else if ("stop".equals(_action))
|
||||
return stop();
|
||||
else if ("start".equals(_action))
|
||||
return start();
|
||||
else if ("Save changes".equals(_action))
|
||||
return saveChanges();
|
||||
else if ("Delete this proxy".equals(_action))
|
||||
return deleteTunnel();
|
||||
else
|
||||
return "Action " + _action + " unknown";
|
||||
}
|
||||
private String stopAll() {
|
||||
if (_group == null) return "";
|
||||
List msgs = _group.stopAllControllers();
|
||||
return getMessages(msgs);
|
||||
}
|
||||
private String startAll() {
|
||||
if (_group == null) return "";
|
||||
List msgs = _group.startAllControllers();
|
||||
return getMessages(msgs);
|
||||
}
|
||||
private String restartAll() {
|
||||
if (_group == null) return "";
|
||||
List msgs = _group.restartAllControllers();
|
||||
return getMessages(msgs);
|
||||
}
|
||||
private String reloadConfig() {
|
||||
if (_group == null) return "";
|
||||
|
||||
_group.reloadControllers();
|
||||
return "Config reloaded";
|
||||
}
|
||||
private String start() {
|
||||
if (_tunnel < 0) return "Invalid tunnel";
|
||||
|
||||
List controllers = _group.getControllers();
|
||||
if (_tunnel >= controllers.size()) return "Invalid tunnel";
|
||||
TunnelController controller = (TunnelController)controllers.get(_tunnel);
|
||||
controller.startTunnelBackground();
|
||||
return "";
|
||||
}
|
||||
|
||||
private String stop() {
|
||||
if (_tunnel < 0) return "Invalid tunnel";
|
||||
|
||||
List controllers = _group.getControllers();
|
||||
if (_tunnel >= controllers.size()) return "Invalid tunnel";
|
||||
TunnelController controller = (TunnelController)controllers.get(_tunnel);
|
||||
controller.stopTunnel();
|
||||
return "";
|
||||
}
|
||||
|
||||
private String saveChanges() {
|
||||
TunnelController cur = getController(_tunnel);
|
||||
|
||||
Properties config = getConfig();
|
||||
if (config == null)
|
||||
return "Invalid params";
|
||||
|
||||
if (cur == null) {
|
||||
// creating new
|
||||
cur = new TunnelController(config, "", true);
|
||||
_group.addController(cur);
|
||||
if (cur.getStartOnLoad())
|
||||
cur.startTunnelBackground();
|
||||
} else {
|
||||
cur.setConfig(config, "");
|
||||
}
|
||||
|
||||
if ("httpclient".equals(cur.getType()) || "client".equals(cur.getType())) {
|
||||
// all clients use the same I2CP session, and as such, use the same
|
||||
// I2CP options
|
||||
List controllers = _group.getControllers();
|
||||
for (int i = 0; i < controllers.size(); i++) {
|
||||
TunnelController c = (TunnelController)controllers.get(i);
|
||||
if (c == cur) continue;
|
||||
if ("httpclient".equals(c.getType()) || "client".equals(c.getType())) {
|
||||
Properties cOpt = c.getConfig("");
|
||||
if (_tunnelCount != null) {
|
||||
cOpt.setProperty("option.inbound.quantity", _tunnelCount);
|
||||
cOpt.setProperty("option.outbound.quantity", _tunnelCount);
|
||||
}
|
||||
if (_tunnelDepth != null) {
|
||||
cOpt.setProperty("option.inbound.length", _tunnelDepth);
|
||||
cOpt.setProperty("option.outbound.length", _tunnelDepth);
|
||||
}
|
||||
cOpt.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
|
||||
cOpt.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
|
||||
|
||||
c.setConfig(cOpt, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List msgs = doSave();
|
||||
msgs.add(0, "Changes saved");
|
||||
return getMessages(msgs);
|
||||
}
|
||||
private List doSave() {
|
||||
_group.saveConfig();
|
||||
return _group.clearAllMessages();
|
||||
}
|
||||
private String deleteTunnel() {
|
||||
if (!_removeConfirmed)
|
||||
return "Please confirm removal";
|
||||
|
||||
TunnelController cur = getController(_tunnel);
|
||||
if (cur == null)
|
||||
return "Invalid tunnel number";
|
||||
|
||||
List msgs = _group.removeController(cur);
|
||||
msgs.addAll(doSave());
|
||||
return getMessages(msgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes any action requested (start/stop/etc) and dump out the
|
||||
* messages.
|
||||
*
|
||||
*/
|
||||
public String getMessages() {
|
||||
if (_group == null)
|
||||
return "";
|
||||
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
if (_action != null) {
|
||||
try {
|
||||
buf.append(processAction()).append("\n");
|
||||
} catch (Exception e) {
|
||||
_log.log(Log.CRIT, "Error processing " + _action, e);
|
||||
}
|
||||
}
|
||||
getMessages(_group.clearAllMessages(), buf);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
////
|
||||
// The remaining methods are simple bean props for the jsp to query
|
||||
////
|
||||
|
||||
public int getTunnelCount() {
|
||||
if (_group == null) return 0;
|
||||
return _group.getControllers().size();
|
||||
}
|
||||
|
||||
public boolean isClient(int tunnelNum) {
|
||||
TunnelController cur = getController(tunnelNum);
|
||||
if (cur == null) return false;
|
||||
return ( ("client".equals(cur.getType())) || ("httpclient".equals(cur.getType())) );
|
||||
}
|
||||
|
||||
public String getTunnelName(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getName();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getClientPort(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getListenPort();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getTunnelType(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return getTypeName(tun.getType());
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getTypeName(String internalType) {
|
||||
if ("client".equals(internalType)) return "Client proxy";
|
||||
else if ("httpclient".equals(internalType)) return "HTTP proxy";
|
||||
else if ("server".equals(internalType)) return "Server";
|
||||
else if ("httpserver".equals(internalType)) return "HTTP server";
|
||||
else return internalType;
|
||||
}
|
||||
|
||||
public String getInternalType(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getType();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getClientInterface(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getListenOnInterface();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public int getTunnelStatus(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun == null) return NOT_RUNNING;
|
||||
if (tun.getIsRunning()) return RUNNING;
|
||||
else if (tun.getIsStarting()) return STARTING;
|
||||
else return NOT_RUNNING;
|
||||
}
|
||||
|
||||
public String getTunnelDescription(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getDescription();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getClientDestination(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun == null) return "";
|
||||
if ("client".equals(tun.getType())) return tun.getTargetDestination();
|
||||
else return tun.getProxyList();
|
||||
}
|
||||
|
||||
public String getServerTarget(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getTargetHost() + ':' + tun.getTargetPort();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getDestinationBase64(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
String rv = tun.getMyDestination();
|
||||
if (rv != null)
|
||||
return rv;
|
||||
else
|
||||
return "";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// bean props for form submission
|
||||
///
|
||||
|
||||
/**
|
||||
* What type of tunnel (httpclient, client, or server). This is
|
||||
* required when adding a new tunnel.
|
||||
@@ -76,17 +383,7 @@ public class WebEditPageHelper {
|
||||
public void setType(String type) {
|
||||
_type = (type != null ? type.trim() : null);
|
||||
}
|
||||
/**
|
||||
* Which particular tunnel should be edited (index into the current
|
||||
* TunnelControllerGroup's getControllers() list). This is required
|
||||
* when editing a tunnel, but not when adding a new one.
|
||||
*
|
||||
*/
|
||||
public void setNum(String id) {
|
||||
_id = (id != null ? id.trim() : null);
|
||||
}
|
||||
String getType() { return _type; }
|
||||
String getNum() { return _id; }
|
||||
|
||||
/** Short name of the tunnel */
|
||||
public void setName(String name) {
|
||||
@@ -158,14 +455,6 @@ public class WebEditPageHelper {
|
||||
public void setPrivKeyFile(String file) {
|
||||
_privKeyFile = (file != null ? file.trim() : null);
|
||||
}
|
||||
/**
|
||||
* If called with any value, we want to generate a new destination
|
||||
* for this server tunnel. This won't cause any existing private keys
|
||||
* to be overwritten, however.
|
||||
*/
|
||||
public void setPrivKeyGenerate(String moo) {
|
||||
_privKeyGenerate = true;
|
||||
}
|
||||
/**
|
||||
* If called with any value (and the form submitted with action=Remove),
|
||||
* we really do want to stop and remove the tunnel.
|
||||
@@ -186,140 +475,7 @@ public class WebEditPageHelper {
|
||||
public void setProfile(String profile) {
|
||||
_profile = profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the form and display any resulting messages
|
||||
*
|
||||
*/
|
||||
public String getActionResults() {
|
||||
try {
|
||||
return processAction();
|
||||
} catch (Throwable t) {
|
||||
_log.log(Log.CRIT, "Internal error processing request", t);
|
||||
return "Internal error - " + t.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an HTML form to edit / create a tunnel according to the
|
||||
* specified fields
|
||||
*/
|
||||
public String getEditForm() {
|
||||
try {
|
||||
return WebEditPageFormGenerator.getForm(this);
|
||||
} catch (Throwable t) {
|
||||
_log.log(Log.CRIT, "Internal error retrieving edit form", t);
|
||||
return "Internal error - " + t.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the tunnel pointed to by the current id
|
||||
*
|
||||
*/
|
||||
TunnelController getTunnelController() {
|
||||
if (_id == null) return null;
|
||||
int id = -1;
|
||||
try {
|
||||
id = Integer.parseInt(_id);
|
||||
List controllers = TunnelControllerGroup.getInstance().getControllers();
|
||||
if ( (id < 0) || (id >= controllers.size()) )
|
||||
return null;
|
||||
else
|
||||
return (TunnelController)controllers.get(id);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Invalid tunnel id [" + _id + "]", nfe);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String processAction() {
|
||||
if ( (_action == null) || (_action.trim().length() <= 0) )
|
||||
return "";
|
||||
String expected = System.getProperty(getClass().getName() + ".nonce");
|
||||
if ( (expected == null) || (!expected.equals(Long.toString(_nonce))) )
|
||||
return "<b>Invalid nonce, are you being spoofed?</b>";
|
||||
if ("Save".equals(_action))
|
||||
return save();
|
||||
else if ("Remove".equals(_action))
|
||||
return remove();
|
||||
else
|
||||
return "Action <i>" + _action + "</i> unknown";
|
||||
}
|
||||
|
||||
private String remove() {
|
||||
if (!_removeConfirmed)
|
||||
return "Please confirm removal";
|
||||
|
||||
TunnelController cur = getTunnelController();
|
||||
if (cur == null)
|
||||
return "Invalid tunnel number";
|
||||
|
||||
List msgs = TunnelControllerGroup.getInstance().removeController(cur);
|
||||
msgs.addAll(doSave());
|
||||
return getMessages(msgs);
|
||||
}
|
||||
|
||||
private String save() {
|
||||
if (_type == null)
|
||||
return "<b>Invalid form submission (no type?)</b>";
|
||||
Properties config = getConfig();
|
||||
if (config == null)
|
||||
return "<b>Invalid params</b>";
|
||||
|
||||
TunnelController cur = getTunnelController();
|
||||
if (cur == null) {
|
||||
// creating new
|
||||
cur = new TunnelController(config, "", _privKeyGenerate);
|
||||
TunnelControllerGroup.getInstance().addController(cur);
|
||||
if (cur.getStartOnLoad())
|
||||
cur.startTunnelBackground();
|
||||
} else {
|
||||
cur.setConfig(config, "");
|
||||
}
|
||||
|
||||
if ("httpclient".equals(cur.getType()) || "client".equals(cur.getType())) {
|
||||
// all clients use the same I2CP session, and as such, use the same
|
||||
// I2CP options
|
||||
List controllers = TunnelControllerGroup.getInstance().getControllers();
|
||||
for (int i = 0; i < controllers.size(); i++) {
|
||||
TunnelController c = (TunnelController)controllers.get(i);
|
||||
if (c == cur) continue;
|
||||
if ("httpclient".equals(c.getType()) || "client".equals(c.getType())) {
|
||||
Properties cOpt = c.getConfig("");
|
||||
if (_tunnelCount != null) {
|
||||
cOpt.setProperty("option.inbound.quantity", _tunnelCount);
|
||||
cOpt.setProperty("option.outbound.quantity", _tunnelCount);
|
||||
}
|
||||
if (_tunnelDepth != null) {
|
||||
cOpt.setProperty("option.inbound.length", _tunnelDepth);
|
||||
cOpt.setProperty("option.outbound.length", _tunnelDepth);
|
||||
}
|
||||
if (_connectDelay)
|
||||
cOpt.setProperty("option.i2p.streaming.connectDelay", "1000");
|
||||
else
|
||||
cOpt.setProperty("option.i2p.streaming.connectDelay", "0");
|
||||
if ("interactive".equals(_profile))
|
||||
cOpt.setProperty("option.i2p.streaming.maxWindowSize", "1");
|
||||
else
|
||||
cOpt.remove("option.i2p.streaming.maxWindowSize");
|
||||
if (_name != null) {
|
||||
cOpt.setProperty("option.inbound.nickname", _name);
|
||||
cOpt.setProperty("option.outbound.nickname", _name);
|
||||
}
|
||||
c.setConfig(cOpt, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getMessages(doSave());
|
||||
}
|
||||
private List doSave() {
|
||||
TunnelControllerGroup.getInstance().saveConfig();
|
||||
return TunnelControllerGroup.getInstance().clearAllMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on all provided data, create a set of configuration parameters
|
||||
* suitable for use in a TunnelController. This will replace (not add to)
|
||||
@@ -339,6 +495,9 @@ public class WebEditPageHelper {
|
||||
config.setProperty("interface", _reachableBy);
|
||||
if (_proxyList != null)
|
||||
config.setProperty("proxyList", _proxyList);
|
||||
|
||||
config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
|
||||
config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
|
||||
} else if ("client".equals(_type)) {
|
||||
if (_port != null)
|
||||
config.setProperty("listenPort", _port);
|
||||
@@ -348,6 +507,9 @@ public class WebEditPageHelper {
|
||||
config.setProperty("interface", _reachableBy);
|
||||
if (_targetDestination != null)
|
||||
config.setProperty("targetDestination", _targetDestination);
|
||||
|
||||
config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
|
||||
config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
|
||||
} else if ("server".equals(_type)) {
|
||||
if (_targetHost != null)
|
||||
config.setProperty("targetHost", _targetHost);
|
||||
@@ -378,8 +540,10 @@ public class WebEditPageHelper {
|
||||
config.setProperty("description", _description);
|
||||
if (_i2cpHost != null)
|
||||
config.setProperty("i2cpHost", _i2cpHost);
|
||||
if (_i2cpPort != null)
|
||||
if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) )
|
||||
config.setProperty("i2cpPort", _i2cpPort);
|
||||
else
|
||||
config.setProperty("i2cpPort", "7654");
|
||||
|
||||
if (_customOptions != null) {
|
||||
StringTokenizer tok = new StringTokenizer(_customOptions);
|
||||
@@ -417,32 +581,43 @@ public class WebEditPageHelper {
|
||||
else
|
||||
config.setProperty("option.i2p.streaming.connectDelay", "0");
|
||||
if (_name != null) {
|
||||
config.setProperty("option.inbound.nickname", _name);
|
||||
config.setProperty("option.outbound.nickname", _name);
|
||||
}
|
||||
if ( (!"client".equals(_type)) && (!"httpclient".equals(_type)) ) {
|
||||
config.setProperty("option.inbound.nickname", _name);
|
||||
config.setProperty("option.outbound.nickname", _name);
|
||||
} else {
|
||||
config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
|
||||
config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
|
||||
}
|
||||
}
|
||||
if ("interactive".equals(_profile))
|
||||
config.setProperty("option.i2p.streaming.maxWindowSize", "1");
|
||||
else
|
||||
config.remove("option.i2p.streaming.maxWindowSize");
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty print the messages provided
|
||||
*
|
||||
*/
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
protected TunnelController getController(int tunnel) {
|
||||
if (tunnel < 0) return null;
|
||||
if (_group == null) return null;
|
||||
List controllers = _group.getControllers();
|
||||
if (controllers.size() > tunnel)
|
||||
return (TunnelController)controllers.get(tunnel);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getMessages(List msgs) {
|
||||
if (msgs == null) return "";
|
||||
int num = msgs.size();
|
||||
switch (num) {
|
||||
case 0: return "";
|
||||
case 1: return (String)msgs.get(0);
|
||||
default:
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
buf.append("<ul>");
|
||||
for (int i = 0; i < num; i++)
|
||||
buf.append("<li>").append((String)msgs.get(i)).append("</li>\n");
|
||||
buf.append("</ul>\n");
|
||||
return buf.toString();
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
getMessages(msgs, buf);
|
||||
return buf.toString();
|
||||
}
|
||||
private void getMessages(List msgs, StringBuffer buf) {
|
||||
if (msgs == null) return;
|
||||
for (int i = 0; i < msgs.size(); i++) {
|
||||
buf.append((String)msgs.get(i)).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,16 +1,26 @@
|
||||
<%@page contentType="text/html" %>
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2PTunnel edit</title>
|
||||
</head><body>
|
||||
|
||||
<a href="index.jsp">Back</a>
|
||||
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.WebEditPageHelper" id="helper" scope="request" />
|
||||
<jsp:setProperty name="helper" property="*" />
|
||||
<b><jsp:getProperty name="helper" property="actionResults" /></b>
|
||||
|
||||
<jsp:getProperty name="helper" property="editForm" />
|
||||
</body>
|
||||
</html>
|
||||
<% String tun = request.getParameter("tunnel");
|
||||
if (tun != null) {
|
||||
try {
|
||||
int curTunnel = Integer.parseInt(tun);
|
||||
if (EditBean.staticIsClient(curTunnel)) {
|
||||
%><jsp:include page="editClient.jsp" /><%
|
||||
} else {
|
||||
%><jsp:include page="editServer.jsp" /><%
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
%>Invalid tunnel parameter<%
|
||||
}
|
||||
} else {
|
||||
String type = request.getParameter("type");
|
||||
int curTunnel = -1;
|
||||
if ("client".equals(type) || "httpclient".equals(type)) {
|
||||
%><jsp:include page="editClient.jsp" /><%
|
||||
} else if ("server".equals(type) || "httpserver".equals(type)) {
|
||||
%><jsp:include page="editServer.jsp" /><%
|
||||
} else {
|
||||
%>Invalid tunnel type<%
|
||||
}
|
||||
}
|
||||
%>
|
280
apps/i2ptunnel/jsp/editClient.jsp
Normal file
280
apps/i2ptunnel/jsp/editClient.jsp
Normal file
@@ -0,0 +1,280 @@
|
||||
<%@page contentType="text/html" %>
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.web.EditBean" id="editBean" scope="request" />
|
||||
<% String tun = request.getParameter("tunnel");
|
||||
int curTunnel = -1;
|
||||
if (tun != null) {
|
||||
try {
|
||||
curTunnel = Integer.parseInt(tun);
|
||||
} catch (NumberFormatException nfe) {
|
||||
curTunnel = -1;
|
||||
}
|
||||
}
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title>I2PTunnel Webmanager</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="index.jsp">
|
||||
<input type="hidden" name="tunnel" value="<%=request.getParameter("tunnel")%>" />
|
||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||
<table width="80%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<% if (curTunnel >= 0) { %>
|
||||
<b>Edit proxy settings</b>
|
||||
<% } else { %>
|
||||
<b>New proxy settings</b>
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Name: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="30" maxlength="50" name="name" value="<%=editBean.getTunnelName(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Type: </b>
|
||||
<td><%
|
||||
if (curTunnel >= 0) {
|
||||
%><%=editBean.getTunnelType(curTunnel)%>
|
||||
<input type="hidden" name="type" value="<%=editBean.getInternalType(curTunnel)%>" />
|
||||
<%
|
||||
} else {
|
||||
%><%=editBean.getTypeName(request.getParameter("type"))%>
|
||||
<input type="hidden" name="type" value="<%=request.getParameter("type")%>" />
|
||||
<%
|
||||
}
|
||||
%></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Description: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="60" maxlength="80" name="description" value="<%=editBean.getTunnelDescription(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Start automatically?:</b>
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.startAutomatically(curTunnel)) { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" checked="true" />
|
||||
<% } else { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" />
|
||||
<% } %>
|
||||
<i>(Check the Box for 'YES')</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> <b>Listening Port:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="6" maxlength="5" name="port" value="<%=editBean.getClientPort(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> Accessable by:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="reachableBy">
|
||||
<% String clientInterface = editBean.getClientInterface(curTunnel); %>
|
||||
<% if (("127.0.0.1".equals(clientInterface)) || (clientInterface == null) || (clientInterface.trim().length() <= 0)) { %>
|
||||
<option value="127.0.0.1" selected="true">Locally (127.0.0.1)</option>
|
||||
<option value="0.0.0.0">Everyone (0.0.0.0)</option>
|
||||
<option value="other">LAN Hosts (Please specify your LAN address)</option>
|
||||
|
||||
</select>
|
||||
|
||||
<b>others:</b>
|
||||
<input type="text" name="reachablyByOther" size="20" />
|
||||
<% } else if ("0.0.0.0".equals(clientInterface)) { %>
|
||||
<option value="127.0.0.1">Locally (127.0.0.1)</option>
|
||||
<option value="0.0.0.0" selected="true">Everyone (0.0.0.0)</option>
|
||||
<option value="other">LAN Hosts (Please specify your LAN address)</option>
|
||||
|
||||
</select>
|
||||
|
||||
<b>others:</b>
|
||||
<input type="text" name="reachablyByOther" size="20" />
|
||||
<% } else { %>
|
||||
<option value="127.0.0.1">Locally (127.0.0.1)</option>
|
||||
<option value="0.0.0.0">Everyone (0.0.0.0)</option>
|
||||
<option value="other" selected="true">LAN Hosts (Please specify your LAN address)</option>
|
||||
|
||||
</select>
|
||||
|
||||
<b>others:</b>
|
||||
<input type="text" name="reachablyByOther" size="20" value="<%=clientInterface%>" />
|
||||
<% } %>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<% if ("httpclient".equals(editBean.getInternalType(curTunnel))) { %>
|
||||
<td><b>Outproxies:</b>
|
||||
<% } else { %>
|
||||
<td><b>Target:</b>
|
||||
<% } %>
|
||||
</td>
|
||||
<td>
|
||||
<% if ("httpclient".equals(editBean.getInternalType(curTunnel))) { %>
|
||||
<input type="text" name="proxyList" value="<%=editBean.getClientDestination(curTunnel)%>" />
|
||||
<% } else { %>
|
||||
<input type="text" name="targetDestination" value="<%=editBean.getClientDestination(curTunnel)%>" />
|
||||
<% } %>
|
||||
<i>(name or destination)</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Delayed connect?</b>
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.shouldDelay(curTunnel)) { %>
|
||||
<input type="checkbox" value="1000" name="connectDelay" checked="true" />
|
||||
<% } else { %>
|
||||
<input type="checkbox" value="1000" name="connectDelay" />
|
||||
<% } %>
|
||||
<i>(for request/response connections)</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Profile:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="profile">
|
||||
<% if (editBean.isInteractive(curTunnel)) { %>
|
||||
<option value="interactive" selected="true">interactive connection </option>
|
||||
<option value="bulk">bulk connection (downloads/websites/BT) </option>
|
||||
<% } else { %>
|
||||
<option value="interactive">interactive connection </option>
|
||||
<option value="bulk" selected="true">bulk connection (downloads/websites/BT) </option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<b><hr size="1">
|
||||
Advanced networking options<br />
|
||||
<span style="color:#dd0000;">(Those are shared between ALL your Client proxies!)</span></b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Tunnel depth:</b>
|
||||
</td>
|
||||
<td><select name="tunnelDepth">
|
||||
<% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2);
|
||||
switch (tunnelDepth) {
|
||||
case 0: %>
|
||||
<option value="0" selected="true">0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 1: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" selected="true">1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" selected="true">2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> hop tunnel</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Tunnel count:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="tunnelCount">
|
||||
<% int tunnelCount = editBean.getTunnelCount(curTunnel, 2);
|
||||
switch (tunnelCount) {
|
||||
case 1: %>
|
||||
<option value="1" selected="true" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" selected="true" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 3: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" selected="true" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> inbound tunnels</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
<tr>
|
||||
<td><b>I2CP host:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientHost" size="20" value="<%=editBean.getI2CPHost(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>I2CP port:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientPort" size="20" value="<%=editBean.getI2CPPort(curTunnel)%>" /><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Custom options:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="customOptions" size="60" value="<%=editBean.getCustomOptions(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<hr size="1">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Save:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Save changes" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Delete?</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Delete this proxy" />
|
||||
<b><span style="color:#dd0000;">confirm delete:</span></b>
|
||||
<input type="checkbox" value="true" name="removeConfirm" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
233
apps/i2ptunnel/jsp/editServer.jsp
Normal file
233
apps/i2ptunnel/jsp/editServer.jsp
Normal file
@@ -0,0 +1,233 @@
|
||||
<%@page contentType="text/html" %>
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.web.EditBean" id="editBean" scope="request" />
|
||||
<% String tun = request.getParameter("tunnel");
|
||||
int curTunnel = -1;
|
||||
if (tun != null) {
|
||||
try {
|
||||
curTunnel = Integer.parseInt(tun);
|
||||
} catch (NumberFormatException nfe) {
|
||||
curTunnel = -1;
|
||||
}
|
||||
}
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title>I2PTunnel Webmanager</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="index.jsp">
|
||||
<input type="hidden" name="tunnel" value="<%=request.getParameter("tunnel")%>" />
|
||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||
<table width="80%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<% if (curTunnel >= 0) { %>
|
||||
<b>Edit server settings</b>
|
||||
<% } else { %>
|
||||
<b>New server settings</b>
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Name: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="30" maxlength="50" name="name" value="<%=editBean.getTunnelName(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Type: </b>
|
||||
<td><%
|
||||
if (curTunnel >= 0) {
|
||||
%><%=editBean.getTunnelType(curTunnel)%>
|
||||
<input type="hidden" name="type" value="<%=editBean.getInternalType(curTunnel)%>" />
|
||||
<%
|
||||
} else {
|
||||
%><%=editBean.getTypeName(request.getParameter("type"))%>
|
||||
<input type="hidden" name="type" value="<%=request.getParameter("type")%>" />
|
||||
<%
|
||||
}
|
||||
%></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Description: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="60" maxlength="80" name="description" value="<%=editBean.getTunnelDescription(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Start automatically?:</b>
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.startAutomatically(curTunnel)) { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" checked="true" />
|
||||
<% } else { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" />
|
||||
<% } %>
|
||||
<i>(Check the Box for 'YES')</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> <b>Target:</b>
|
||||
</td>
|
||||
<td>
|
||||
Host: <input type="text" size="20" name="targetHost" value="<%=editBean.getTargetHost(curTunnel)%>" />
|
||||
Port: <input type="text" size="6" maxlength="5" name="targetPort" value="<%=editBean.getTargetPort(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<% String curType = editBean.getInternalType(curTunnel);
|
||||
if ( (curType == null) || (curType.trim().length() <= 0) )
|
||||
curType = request.getParameter("type");
|
||||
if ("httpserver".equals(curType)) { %>
|
||||
<tr>
|
||||
<td><b>Website name:</b></td>
|
||||
<td><input type="text" size="20" name="spoofedHost" value="<%=editBean.getSpoofedHost(curTunnel)%>" />
|
||||
</td></tr>
|
||||
<% } %>
|
||||
<tr>
|
||||
<td><b>Private key file:</b>
|
||||
</td>
|
||||
<td><input type="text" size="30" name="privKeyFile" value="<%=editBean.getPrivateKeyFile(curTunnel)%>" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Profile:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="profile">
|
||||
<% if (editBean.isInteractive(curTunnel)) { %>
|
||||
<option value="interactive" selected="true">interactive connection </option>
|
||||
<option value="bulk">bulk connection (downloads/websites/BT) </option>
|
||||
<% } else { %>
|
||||
<option value="interactive">interactive connection </option>
|
||||
<option value="bulk" selected="true">bulk connection (downloads/websites/BT) </option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="left"><b>Local destination:</b><br /><i>(if known)</i></td>
|
||||
<td valign="top" align="left"><input type="text" size="60" value="<%=editBean.getDestinationBase64(curTunnel)%>" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<b><hr size="1">
|
||||
Advanced networking options<br />
|
||||
</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Tunnel depth:</b>
|
||||
</td>
|
||||
<td><select name="tunnelDepth">
|
||||
<% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2);
|
||||
switch (tunnelDepth) {
|
||||
case 0: %>
|
||||
<option value="0" selected="true">0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 1: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" selected="true">1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" selected="true">2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> hop tunnel</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Tunnel count:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="tunnelCount">
|
||||
<% int tunnelCount = editBean.getTunnelCount(curTunnel, 2);
|
||||
switch (tunnelCount) {
|
||||
case 1: %>
|
||||
<option value="1" selected="true" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" selected="true" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 3: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" selected="true" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> inbound tunnels</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
<tr>
|
||||
<td><b>I2CP host:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientHost" size="20" value="<%=editBean.getI2CPHost(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>I2CP port:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientPort" size="20" value="<%=editBean.getI2CPPort(curTunnel)%>" /><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Custom options:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="customOptions" size="60" value="<%=editBean.getCustomOptions(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<hr size="1">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Save:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Save changes" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Delete?</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Delete this proxy" />
|
||||
<b><span style="color:#dd0000;">confirm delete:</span></b>
|
||||
<input type="checkbox" value="true" name="removeConfirm" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
@@ -1,26 +1,184 @@
|
||||
<%@page contentType="text/html" %>
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.IndexBean" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.web.IndexBean" id="indexBean" scope="request" />
|
||||
<jsp:setProperty name="indexBean" property="*" />
|
||||
|
||||
<html><head>
|
||||
<title>I2PTunnel status</title>
|
||||
</head><body>
|
||||
<html>
|
||||
<head>
|
||||
<title>I2PTunnel Webmanager</title>
|
||||
</head>
|
||||
<body style="font-family: Verdana, Tahoma, Helvetica, sans-serif;font-size:12px;">
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td nowrap="true"><b>New Messages: </b><br />
|
||||
<a href="index.jsp">refresh</a>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="3" cols="60" readonly="true"><jsp:getProperty name="indexBean" property="messages" /></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.WebStatusPageHelper" id="helper" scope="request" />
|
||||
<jsp:setProperty name="helper" property="*" />
|
||||
<h2>Messages since last page load:</h2>
|
||||
<b><jsp:getProperty name="helper" property="actionResults" /></b>
|
||||
|
||||
<jsp:getProperty name="helper" property="summaryList" />
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="7" align="center" valign="middle" style="font-size:14px;">
|
||||
<b>Your Client Tunnels:</b><br />
|
||||
<hr size="1" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="15%"><b>Name:</b></td>
|
||||
<td><b>Port:</b></td>
|
||||
<td><b>Type:</b></td>
|
||||
<td><b>Interface:</b></td>
|
||||
<td><b>Status:</b></td>
|
||||
</tr>
|
||||
<% for (int curClient = 0; curClient < indexBean.getTunnelCount(); curClient++) {
|
||||
if (!indexBean.isClient(curClient)) continue; %>
|
||||
<tr>
|
||||
<td valign="top" align="left">
|
||||
<b><a href="edit.jsp?tunnel=<%=curClient%>"><%=indexBean.getTunnelName(curClient) %></a></b></td>
|
||||
<td valign="top" align="left" nowrap="true"><%=indexBean.getClientPort(curClient) %></td>
|
||||
<td valign="top" align="left" nowrap="true"><%=indexBean.getTunnelType(curClient) %></td>
|
||||
<td valign="top" align="left" nowrap="true"><%=indexBean.getClientInterface(curClient) %></td>
|
||||
<td valign="top" align="left" nowrap="true"><%
|
||||
switch (indexBean.getTunnelStatus(curClient)) {
|
||||
case IndexBean.STARTING:
|
||||
%><b><span style="color:#339933">Starting...</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">[STOP]</a><%
|
||||
break;
|
||||
case IndexBean.RUNNING:
|
||||
%><b><span style="color:#00dd00">Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">[STOP]</a><%
|
||||
break;
|
||||
case IndexBean.NOT_RUNNING:
|
||||
%><b><span style="color:#dd0000">Not Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curClient%>">[START]</a><%
|
||||
break;
|
||||
}
|
||||
%></td>
|
||||
</tr>
|
||||
<tr><td align="right" valign="top">Destination:</td>
|
||||
<td colspan="4"><input align="left" size="40" valign="top" style="overflow: hidden" readonly="true" value="<%=indexBean.getClientDestination(curClient) %>" /></td></tr>
|
||||
<tr>
|
||||
<td valign="top" align="right">Description:</td>
|
||||
<td valign="top" align="left" colspan="4"><%=indexBean.getTunnelDescription(curClient) %></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="5" align="center" valign="middle" style="font-size:14px;">
|
||||
<b>Your Server Tunnels:</b><br />
|
||||
<hr size="1" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="15%"><b>Name: </b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Points at:</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Status:</b>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<% for (int curServer = 0; curServer < indexBean.getTunnelCount(); curServer++) {
|
||||
if (indexBean.isClient(curServer)) continue; %>
|
||||
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<b><a href="edit.jsp?tunnel=<%=curServer%>"><%=indexBean.getTunnelName(curServer)%></a></b>
|
||||
</td>
|
||||
<td valign="top"><%=indexBean.getServerTarget(curServer)%></td>
|
||||
<td valign="top" nowrap="true"><%
|
||||
switch (indexBean.getTunnelStatus(curServer)) {
|
||||
case IndexBean.RUNNING:
|
||||
%><b><span style="color:#00dd00">Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>">[STOP]</a><%
|
||||
if ("httpserver".equals(indexBean.getInternalType(curServer))) {
|
||||
%> (<a href="http://<%=(new java.util.Random()).nextLong()%>.i2p/?i2paddresshelper=<%=indexBean.getDestinationBase64(curServer)%>">preview</a>)<%
|
||||
}
|
||||
break;
|
||||
case IndexBean.NOT_RUNNING:
|
||||
%><b><span style="color:#dd0000">Not Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curServer%>">[START]</a><%
|
||||
break;
|
||||
case IndexBean.STARTING:
|
||||
%>
|
||||
<b><span style="color:#339933">Starting...</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>">[STOP]</a><%
|
||||
break;
|
||||
}
|
||||
%>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td valign="top" align="right">Description:</td>
|
||||
<td valign="top" align="left" colspan="2"><%=indexBean.getTunnelDescription(curServer)%></td></tr>
|
||||
<% } %>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="2" align="center" valign="middle">
|
||||
<b>Operations Menu - Please chose from below!</b><br /><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<form action="index.jsp" method="GET">
|
||||
<td >
|
||||
<input type="hidden" name="nonce" value="<%=indexBean.getNextNonce()%>" />
|
||||
<input type="submit" name="action" value="Stop all tunnels" />
|
||||
<input type="submit" name="action" value="Start all tunnels" />
|
||||
<input type="submit" name="action" value="Restart all" />
|
||||
<input type="submit" name="action" value="Reload config" />
|
||||
</td>
|
||||
</form>
|
||||
<form action="edit.jsp">
|
||||
<td >
|
||||
<b>Add new:</b>
|
||||
<select name="type">
|
||||
<select name="type">
|
||||
<option value="httpclient">HTTP proxy</option>
|
||||
<option value="client">Client tunnel</option>
|
||||
<option value="server">Server tunnel</option>
|
||||
<option value="httpserver">HTTP server tunnel</option>
|
||||
</select> <input type="submit" value="GO" />
|
||||
<option value="httpserver">HTTP server tunnel</option>
|
||||
</select> <input type="submit" value="Create" />
|
||||
</td>
|
||||
</form>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -62,6 +62,8 @@ public interface I2PSocket {
|
||||
*/
|
||||
public void close() throws IOException;
|
||||
|
||||
public boolean isClosed();
|
||||
|
||||
public void setSocketErrorListener(SocketErrorListener lsnr);
|
||||
/**
|
||||
* Allow notification of underlying errors communicating across I2P without
|
||||
|
@@ -233,6 +233,8 @@ class I2PSocketImpl implements I2PSocket {
|
||||
in.notifyClosed();
|
||||
}
|
||||
|
||||
public boolean isClosed() { return _closedOn > 0; }
|
||||
|
||||
/**
|
||||
* Close the socket from the I2P side (by a close packet)
|
||||
*/
|
||||
|
@@ -4,27 +4,16 @@
|
||||
*/
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSessionListener;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -36,18 +36,27 @@ public class I2PSocketManagerFactory {
|
||||
* @return the newly created socket manager, or null if there were errors
|
||||
*/
|
||||
public static I2PSocketManager createManager() {
|
||||
String i2cpHost = System.getProperty(I2PClient.PROP_TCP_HOST, "localhost");
|
||||
int i2cpPort = 7654;
|
||||
String i2cpPortStr = System.getProperty(I2PClient.PROP_TCP_PORT);
|
||||
if (i2cpPortStr != null) {
|
||||
try {
|
||||
i2cpPort = Integer.parseInt(i2cpPortStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// gobble gobble
|
||||
}
|
||||
}
|
||||
return createManager(getHost(), getPort(), System.getProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a socket manager using a brand new destination connected to the
|
||||
* I2CP router on the local machine on the default port (7654).
|
||||
*
|
||||
* @return the newly created socket manager, or null if there were errors
|
||||
*/
|
||||
public static I2PSocketManager createManager(Properties opts) {
|
||||
return createManager(getHost(), getPort(), opts);
|
||||
}
|
||||
|
||||
return createManager(i2cpHost, i2cpPort, System.getProperties());
|
||||
/**
|
||||
* Create a socket manager using a brand new destination connected to the
|
||||
* I2CP router on the specified host and port
|
||||
*
|
||||
* @return the newly created socket manager, or null if there were errors
|
||||
*/
|
||||
public static I2PSocketManager createManager(String host, int port) {
|
||||
return createManager(host, port, System.getProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,6 +81,26 @@ public class I2PSocketManagerFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a socket manager using the destination loaded from the given private key
|
||||
* stream and connected to the default I2CP host and port.
|
||||
*
|
||||
* @return the newly created socket manager, or null if there were errors
|
||||
*/
|
||||
public static I2PSocketManager createManager(InputStream myPrivateKeyStream) {
|
||||
return createManager(myPrivateKeyStream, getHost(), getPort(), System.getProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a socket manager using the destination loaded from the given private key
|
||||
* stream and connected to the default I2CP host and port.
|
||||
*
|
||||
* @return the newly created socket manager, or null if there were errors
|
||||
*/
|
||||
public static I2PSocketManager createManager(InputStream myPrivateKeyStream, Properties opts) {
|
||||
return createManager(myPrivateKeyStream, getHost(), getPort(), opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a socket manager using the destination loaded from the given private key
|
||||
* stream and connected to the I2CP router on the specified machine on the given
|
||||
@@ -154,4 +183,20 @@ public class I2PSocketManagerFactory {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String getHost() {
|
||||
return System.getProperty(I2PClient.PROP_TCP_HOST, "localhost");
|
||||
}
|
||||
private static int getPort() {
|
||||
int i2cpPort = 7654;
|
||||
String i2cpPortStr = System.getProperty(I2PClient.PROP_TCP_PORT);
|
||||
if (i2cpPortStr != null) {
|
||||
try {
|
||||
i2cpPort = Integer.parseInt(i2cpPortStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// gobble gobble
|
||||
}
|
||||
}
|
||||
return i2cpPort;
|
||||
}
|
||||
}
|
@@ -1,7 +1,5 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Define the configuration for streaming and verifying data on the socket.
|
||||
*
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
|
@@ -8,8 +8,6 @@ import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.data.Destination;
|
||||
|
@@ -122,11 +122,12 @@ public class StreamSinkServer {
|
||||
long written = 0;
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1) {
|
||||
_fos.write(buf, 0, read);
|
||||
//_fos.write(buf, 0, read);
|
||||
written += read;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("read and wrote " + read);
|
||||
}
|
||||
_fos.write(("written: [" + written + "]\n").getBytes());
|
||||
long lifetime = System.currentTimeMillis() - start;
|
||||
_log.error("Got EOF from client socket [written=" + written + " lifetime=" + lifetime + "]");
|
||||
} catch (IOException ioe) {
|
||||
@@ -150,7 +151,7 @@ public class StreamSinkServer {
|
||||
StreamSinkServer server = null;
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
server = new StreamSinkServer("dataDir", "server.key", "localhost", 10001);
|
||||
server = new StreamSinkServer("dataDir", "server.key", "localhost", 7654);
|
||||
break;
|
||||
case 2:
|
||||
server = new StreamSinkServer(args[0], args[1]);
|
||||
|
@@ -1,24 +1,12 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
@@ -74,13 +74,20 @@
|
||||
<arg value="../jsp/" />
|
||||
</java>
|
||||
|
||||
<javac destdir="../jsp/WEB-INF/classes/" srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
|
||||
<javac debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
destdir="../jsp/WEB-INF/classes/"
|
||||
srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
|
||||
<classpath>
|
||||
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||
<pathelement location="../../systray/java/build/obj" />
|
||||
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
||||
<pathelement location="../../../installer/lib/wrapper/win32/wrapper.jar" />
|
||||
<pathelement location="build/routerconsole.jar" />
|
||||
<pathelement location="../../../router/java/build/router.jar" />
|
||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||
</classpath>
|
||||
</javac>
|
||||
<delete>
|
||||
|
@@ -17,11 +17,6 @@ public class ConfigAdvancedHandler extends FormHandler {
|
||||
private boolean _shouldSave;
|
||||
private String _config;
|
||||
|
||||
public void ConfigNetHandler() {
|
||||
_shouldSave = false;
|
||||
_forceRestart = false;
|
||||
}
|
||||
|
||||
protected void processForm() {
|
||||
if (_shouldSave) {
|
||||
saveChanges();
|
||||
|
@@ -1,11 +1,8 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Properties;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handler to deal with form submissions from the logging config form and act
|
||||
@@ -21,10 +18,6 @@ public class ConfigLoggingHandler extends FormHandler {
|
||||
private String _dateFormat;
|
||||
private String _fileSize;
|
||||
|
||||
public void ConfigNetHandler() {
|
||||
_shouldSave = false;
|
||||
}
|
||||
|
||||
protected void processForm() {
|
||||
if (_shouldSave) {
|
||||
saveChanges();
|
||||
|
@@ -1,14 +1,9 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
|
||||
public class ConfigLoggingHelper {
|
||||
|
@@ -13,15 +13,10 @@ import java.net.URLConnection;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.time.Timestamper;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.ClientTunnelSettings;
|
||||
|
||||
/**
|
||||
* Handler to deal with form submissions from the main config form and act
|
||||
* upon the values.
|
||||
@@ -41,13 +36,6 @@ public class ConfigNetHandler extends FormHandler {
|
||||
private String _reseedFrom;
|
||||
private String _sharePct;
|
||||
|
||||
public void ConfigNetHandler() {
|
||||
_guessRequested = false;
|
||||
_reseedRequested = false;
|
||||
_saveRequested = false;
|
||||
_timeSyncEnabled = false;
|
||||
}
|
||||
|
||||
protected void processForm() {
|
||||
if (_guessRequested) {
|
||||
guessHostname();
|
||||
|
@@ -1,16 +1,7 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.time.Timestamper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.ClientTunnelSettings;
|
||||
|
||||
public class ConfigNetHelper {
|
||||
private RouterContext _context;
|
||||
|
@@ -8,7 +8,6 @@ import java.util.Properties;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.ClientTunnelSettings;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.apps.systray.SysTray;
|
||||
import net.i2p.apps.systray.UrlLauncher;
|
||||
@@ -20,9 +19,8 @@ import org.tanukisoftware.wrapper.WrapperManager;
|
||||
*
|
||||
*/
|
||||
public class ConfigServiceHandler extends FormHandler {
|
||||
public void ConfigNetHandler() {}
|
||||
|
||||
private class UpdateWrapperManagerTask implements Runnable {
|
||||
public static class UpdateWrapperManagerTask implements Runnable {
|
||||
private int _exitCode;
|
||||
public UpdateWrapperManagerTask(int exitCode) {
|
||||
_exitCode = exitCode;
|
||||
|
@@ -1,15 +1,8 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.TunnelPoolSettings;
|
||||
@@ -49,9 +42,11 @@ public class ConfigTunnelsHelper {
|
||||
TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(dest.calculateHash());
|
||||
TunnelPoolSettings out = _context.tunnelManager().getOutboundSettings(dest.calculateHash());
|
||||
|
||||
String name = (in != null ? in.getDestinationNickname() : null);
|
||||
if ( (in == null) || (out == null) ) continue;
|
||||
|
||||
String name = in.getDestinationNickname();
|
||||
if (name == null)
|
||||
name = (out != null ? out.getDestinationNickname() : null);
|
||||
name = out.getDestinationNickname();
|
||||
if (name == null)
|
||||
name = dest.calculateHash().toBase64().substring(0,6);
|
||||
|
||||
@@ -110,7 +105,7 @@ public class ConfigTunnelsHelper {
|
||||
buf.append("</tr>\n");
|
||||
|
||||
// tunnel depth variance
|
||||
buf.append("<tr><td>Variance</td>\n");
|
||||
buf.append("<tr><td>Randomization</td>\n");
|
||||
buf.append("<td><select name=\"").append(index).append(".varianceInbound\">\n");
|
||||
buf.append("<option value=\"0\" ");
|
||||
if (in.getLengthVariance() == 0) buf.append(" selected=\"true\" ");
|
||||
|
@@ -0,0 +1,103 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ConfigUpdateHandler extends FormHandler {
|
||||
private String _newsURL;
|
||||
private long _refreshFrequency;
|
||||
private String _updateURL;
|
||||
private String _updatePolicy;
|
||||
private String _proxyHost;
|
||||
private String _proxyPort;
|
||||
private boolean _updateThroughProxy;
|
||||
private String _trustedKeys;
|
||||
|
||||
public static final String PROP_NEWS_URL = "router.newsURL";
|
||||
public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
|
||||
public static final String PROP_REFRESH_FREQUENCY = "router.newsRefreshFrequency";
|
||||
public static final String DEFAULT_REFRESH_FREQUENCY = 12*60*60*1000 + "";
|
||||
public static final String PROP_UPDATE_URL = "router.updateURL";
|
||||
public static final String DEFAULT_UPDATE_URL = "http://dev.i2p.net/i2p/i2pupdate.sud";
|
||||
public static final String PROP_UPDATE_POLICY = "router.updatePolicy";
|
||||
public static final String DEFAULT_UPDATE_POLICY = "notify";
|
||||
public static final String PROP_SHOULD_PROXY = "router.updateThroughProxy";
|
||||
public static final String DEFAULT_SHOULD_PROXY = Boolean.FALSE.toString();
|
||||
public static final String PROP_PROXY_HOST = "router.updateProxyHost";
|
||||
public static final String DEFAULT_PROXY_HOST = "localhost";
|
||||
public static final String PROP_PROXY_PORT = "router.updateProxyPort";
|
||||
public static final String DEFAULT_PROXY_PORT = "4444";
|
||||
|
||||
protected void processForm() {
|
||||
if ( (_newsURL != null) && (_newsURL.length() > 0) ) {
|
||||
String oldURL = _context.router().getConfigSetting(PROP_NEWS_URL);
|
||||
if ( (oldURL == null) || (!_newsURL.equals(oldURL)) ) {
|
||||
_context.router().setConfigSetting(PROP_NEWS_URL, _newsURL);
|
||||
addFormNotice("Updating news URL to " + _newsURL);
|
||||
}
|
||||
}
|
||||
if ( (_updateURL != null) && (_updateURL.length() > 0) ) {
|
||||
String oldURL = _context.router().getConfigSetting(PROP_UPDATE_URL);
|
||||
if ( (oldURL == null) || (!_updateURL.equals(oldURL)) ) {
|
||||
_context.router().setConfigSetting(PROP_UPDATE_URL, _updateURL);
|
||||
addFormNotice("Updating update URL to " + _updateURL);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (_proxyHost != null) && (_proxyHost.length() > 0) ) {
|
||||
String oldHost = _context.router().getConfigSetting(PROP_PROXY_HOST);
|
||||
if ( (oldHost == null) || (!_proxyHost.equals(oldHost)) ) {
|
||||
_context.router().setConfigSetting(PROP_PROXY_HOST, _proxyHost);
|
||||
addFormNotice("Updating proxy host to " + _proxyHost);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (_proxyPort != null) && (_proxyPort.length() > 0) ) {
|
||||
String oldPort = _context.router().getConfigSetting(PROP_PROXY_PORT);
|
||||
if ( (oldPort == null) || (!_proxyHost.equals(oldPort)) ) {
|
||||
_context.router().setConfigSetting(PROP_PROXY_PORT, _proxyPort);
|
||||
addFormNotice("Updating proxy port to " + _proxyPort);
|
||||
}
|
||||
}
|
||||
|
||||
if (_updateThroughProxy) {
|
||||
_context.router().setConfigSetting(PROP_SHOULD_PROXY, Boolean.TRUE.toString());
|
||||
} else {
|
||||
_context.router().setConfigSetting(PROP_SHOULD_PROXY, Boolean.FALSE.toString());
|
||||
}
|
||||
|
||||
String oldFreqStr = _context.router().getConfigSetting(PROP_REFRESH_FREQUENCY);
|
||||
long oldFreq = -1;
|
||||
if (oldFreqStr != null)
|
||||
try { oldFreq = Long.parseLong(oldFreqStr); } catch (NumberFormatException nfe) {}
|
||||
if (_refreshFrequency != oldFreq) {
|
||||
_context.router().setConfigSetting(PROP_REFRESH_FREQUENCY, ""+_refreshFrequency);
|
||||
addFormNotice("Updating refresh frequency to " + DataHelper.formatDuration(_refreshFrequency));
|
||||
}
|
||||
|
||||
if ( (_updatePolicy != null) && (_updatePolicy.length() > 0) ) {
|
||||
String oldPolicy = _context.router().getConfigSetting(PROP_UPDATE_POLICY);
|
||||
if ( (oldPolicy == null) || (!_updatePolicy.equals(oldPolicy)) ) {
|
||||
_context.router().setConfigSetting(PROP_UPDATE_POLICY, _updatePolicy);
|
||||
addFormNotice("Updating update policy to " + _updatePolicy);
|
||||
}
|
||||
}
|
||||
|
||||
// should save the keys...
|
||||
|
||||
_context.router().saveConfig();
|
||||
}
|
||||
|
||||
public void setNewsURL(String url) { _newsURL = url; }
|
||||
public void setRefreshFrequency(String freq) {
|
||||
try { _refreshFrequency = Long.parseLong(freq); } catch (NumberFormatException nfe) {}
|
||||
}
|
||||
public void setUpdateURL(String url) { _updateURL = url; }
|
||||
public void setUpdatePolicy(String policy) { _updatePolicy = policy; }
|
||||
public void setTrustedKeys(String keys) { _trustedKeys = keys; }
|
||||
public void setUpdateThroughProxy(String foo) { _updateThroughProxy = true; }
|
||||
public void setProxyHost(String host) { _proxyHost = host; }
|
||||
public void setProxyPort(String port) { _proxyPort = port; }
|
||||
}
|
@@ -0,0 +1,123 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.List;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.router.RouterContext;
|
||||
|
||||
public class ConfigUpdateHelper {
|
||||
private RouterContext _context;
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
*
|
||||
* @param contextId begging few characters of the routerHash, or null to pick
|
||||
* the first one we come across.
|
||||
*/
|
||||
public void setContextId(String contextId) {
|
||||
try {
|
||||
_context = ContextHelper.getContext(contextId);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigUpdateHelper() {}
|
||||
|
||||
public boolean updateAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getNewsURL() {
|
||||
String url = _context.getProperty(ConfigUpdateHandler.PROP_NEWS_URL);
|
||||
if (url != null)
|
||||
return url;
|
||||
else
|
||||
return ConfigUpdateHandler.DEFAULT_NEWS_URL;
|
||||
}
|
||||
public String getUpdateURL() {
|
||||
String url = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL);
|
||||
if (url != null)
|
||||
return url;
|
||||
else
|
||||
return ConfigUpdateHandler.DEFAULT_UPDATE_URL;
|
||||
}
|
||||
public String getProxyHost() {
|
||||
String host = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST);
|
||||
if (host != null)
|
||||
return host;
|
||||
else
|
||||
return ConfigUpdateHandler.DEFAULT_PROXY_HOST;
|
||||
}
|
||||
public String getProxyPort() {
|
||||
String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT);
|
||||
if (port != null)
|
||||
return port;
|
||||
else
|
||||
return ConfigUpdateHandler.DEFAULT_PROXY_PORT;
|
||||
}
|
||||
|
||||
public String getUpdateThroughProxy() {
|
||||
String proxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
|
||||
if (Boolean.valueOf(proxy).booleanValue())
|
||||
return "<input type=\"checkbox\" value=\"true\" name=\"updateThroughProxy\" checked=\"true\" >";
|
||||
else
|
||||
|
||||
return "<input type=\"checkbox\" value=\"true\" name=\"updateThroughProxy\" >";
|
||||
}
|
||||
|
||||
private static final long PERIODS[] = new long[] { 12*60*60*1000l, 24*60*60*1000l, 48*60*60*1000l, -1l };
|
||||
|
||||
public String getRefreshFrequencySelectBox() {
|
||||
String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY);
|
||||
if (freq == null) freq = ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY;
|
||||
long ms = -1;
|
||||
try {
|
||||
ms = Long.parseLong(freq);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
|
||||
StringBuffer buf = new StringBuffer(256);
|
||||
buf.append("<select name=\"refreshFrequency\">");
|
||||
for (int i = 0; i < PERIODS.length; i++) {
|
||||
buf.append("<option value=\"").append(PERIODS[i]);
|
||||
if (PERIODS[i] == ms)
|
||||
buf.append("\" selected=\"true\"");
|
||||
|
||||
if (PERIODS[i] == -1)
|
||||
buf.append("\">Never</option>\n");
|
||||
else
|
||||
buf.append("\">Every ").append(DataHelper.formatDuration(PERIODS[i])).append("</option>\n");
|
||||
}
|
||||
buf.append("</select>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String getUpdatePolicySelectBox() {
|
||||
String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
|
||||
if (policy == null) policy = ConfigUpdateHandler.DEFAULT_UPDATE_POLICY;
|
||||
|
||||
StringBuffer buf = new StringBuffer(256);
|
||||
buf.append("<select name=\"updatePolicy\">");
|
||||
|
||||
if ("notify".equals(policy))
|
||||
buf.append("<option value=\"notify\" selected=\"true\">Notify only</option>");
|
||||
else
|
||||
buf.append("<option value=\"notify\">Notify only</option>");
|
||||
|
||||
if ("install".equals(policy))
|
||||
buf.append("<option value=\"install\" selected=\"true\">Download and install</option>");
|
||||
else
|
||||
buf.append("<option value=\"install\">Download and install</option>");
|
||||
|
||||
buf.append("</select>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String getTrustedKeys() {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
TrustedUpdate up = new TrustedUpdate(_context);
|
||||
List keys = up.getTrustedKeys();
|
||||
for (int i = 0; i < keys.size(); i++)
|
||||
buf.append((String)keys.get(i)).append('\n');
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
@@ -1,9 +1,5 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.FileUtil;
|
||||
|
||||
|
@@ -3,10 +3,7 @@ package net.i2p.router.web;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.ClientTunnelSettings;
|
||||
|
||||
/**
|
||||
* Simple form handler base class - does not depend on servlets or jsp,
|
||||
|
@@ -1,7 +1,5 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
@@ -41,6 +39,22 @@ public class LogsHelper {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String getCriticalLogs() {
|
||||
List msgs = _context.logManager().getBuffer().getMostRecentCriticalMessages();
|
||||
StringBuffer buf = new StringBuffer(16*1024);
|
||||
buf.append("<ul>");
|
||||
buf.append("<code>\n");
|
||||
for (int i = msgs.size(); i > 0; i--) {
|
||||
String msg = (String)msgs.get(i - 1);
|
||||
buf.append("<li>");
|
||||
buf.append(msg);
|
||||
buf.append("</li>\n");
|
||||
}
|
||||
buf.append("</code></ul>\n");
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String getServiceLogs() {
|
||||
String str = FileUtil.readTextFile("wrapper.log", 500, false);
|
||||
if (str == null)
|
||||
|
274
apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java
Normal file
274
apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java
Normal file
@@ -0,0 +1,274 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.RouterVersion;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Task to periodically look for updates to the news.xml, and to keep
|
||||
* track of whether that has an announcement for a new version.
|
||||
*/
|
||||
public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private boolean _updateAvailable;
|
||||
private long _lastFetch;
|
||||
private static NewsFetcher _instance;
|
||||
//public static final synchronized NewsFetcher getInstance() { return _instance; }
|
||||
public static final synchronized NewsFetcher getInstance(I2PAppContext ctx) {
|
||||
if (_instance != null)
|
||||
return _instance;
|
||||
_instance = new NewsFetcher(ctx);
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private static final String NEWS_FILE = "docs/news.xml";
|
||||
private static final String TEMP_NEWS_FILE = "docs/news.xml.temp";
|
||||
|
||||
private NewsFetcher(I2PAppContext ctx) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(NewsFetcher.class);
|
||||
_instance = this;
|
||||
updateLastFetched();
|
||||
}
|
||||
|
||||
private void updateLastFetched() {
|
||||
File news = new File(NEWS_FILE);
|
||||
if (news.exists())
|
||||
_lastFetch = news.lastModified();
|
||||
else
|
||||
_lastFetch = 0;
|
||||
}
|
||||
|
||||
public boolean updateAvailable() { return _updateAvailable; }
|
||||
|
||||
public void run() {
|
||||
try { Thread.sleep(_context.random().nextLong(5*60*1000)); } catch (InterruptedException ie) {}
|
||||
while (true) {
|
||||
if (!_updateAvailable) checkForUpdates();
|
||||
if (shouldFetchNews())
|
||||
fetchNews();
|
||||
try { Thread.sleep(10*60*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldInstall() {
|
||||
String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
|
||||
return ("install".equals(policy));
|
||||
}
|
||||
|
||||
private boolean shouldFetchNews() {
|
||||
updateLastFetched();
|
||||
String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY);
|
||||
if (freq == null)
|
||||
freq = ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY;
|
||||
try {
|
||||
long ms = Long.parseLong(freq);
|
||||
if (ms <= 0)
|
||||
return false;
|
||||
|
||||
if (_lastFetch + ms < _context.clock().now()) {
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Last fetched " + DataHelper.formatDuration(_context.clock().now() - _lastFetch) + " ago");
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Invalid refresh frequency: " + freq);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private void fetchNews() {
|
||||
String newsURL = _context.getProperty(ConfigUpdateHandler.PROP_NEWS_URL, ConfigUpdateHandler.DEFAULT_NEWS_URL);
|
||||
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
|
||||
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
|
||||
String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT);
|
||||
File tempFile = new File(TEMP_NEWS_FILE);
|
||||
if (tempFile.exists())
|
||||
tempFile.delete();
|
||||
|
||||
int proxyPort = -1;
|
||||
try {
|
||||
proxyPort = Integer.parseInt(port);
|
||||
EepGet get = null;
|
||||
if (shouldProxy)
|
||||
get = new EepGet(_context, proxyHost, proxyPort, 10, TEMP_NEWS_FILE, newsURL);
|
||||
else
|
||||
get = new EepGet(_context, 10, TEMP_NEWS_FILE, newsURL);
|
||||
get.addStatusListener(this);
|
||||
get.fetch();
|
||||
} catch (Throwable t) {
|
||||
_log.error("Error fetching the news", t);
|
||||
}
|
||||
|
||||
_lastFetch = _context.clock().now();
|
||||
}
|
||||
|
||||
private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\"";
|
||||
private static final String VERSION_PREFIX = "version=\"";
|
||||
private void checkForUpdates() {
|
||||
_updateAvailable = false;
|
||||
File news = new File(NEWS_FILE);
|
||||
if ( (!news.exists()) || (news.length() <= 0) ) return;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(news);
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
while (DataHelper.readLine(in, buf)) {
|
||||
int index = buf.indexOf(VERSION_PREFIX);
|
||||
if (index == -1) {
|
||||
// skip
|
||||
} else {
|
||||
int end = buf.indexOf("\"", index + VERSION_PREFIX.length());
|
||||
if (end > index) {
|
||||
String ver = buf.substring(index+VERSION_PREFIX.length(), end);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Found version: [" + ver + "]");
|
||||
if (needsUpdate(ver)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Our version is out of date, update!");
|
||||
break;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Our version is current");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buf.indexOf(VERSION_STRING) != -1) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Our version found, no need to update: " + buf.toString());
|
||||
return;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("No match in " + buf.toString());
|
||||
}
|
||||
buf.setLength(0);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error checking the news for an update", ioe);
|
||||
return;
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
// could not find version="0.5.0.1", so there must be an update ;)
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Our version was NOT found (" + RouterVersion.VERSION + "), update needed");
|
||||
_updateAvailable = true;
|
||||
|
||||
if (shouldInstall()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Policy requests update, so we update");
|
||||
UpdateHandler handler = null;
|
||||
if (_context instanceof RouterContext) {
|
||||
handler = new UpdateHandler((RouterContext)_context);
|
||||
} else {
|
||||
List contexts = RouterContext.listContexts();
|
||||
if (contexts.size() > 0)
|
||||
handler = new UpdateHandler((RouterContext)contexts.get(0));
|
||||
else
|
||||
_log.log(Log.CRIT, "No router context to update with?");
|
||||
}
|
||||
if (handler != null)
|
||||
handler.update();
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Policy requests manual update, so we do nothing");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needsUpdate(String version) {
|
||||
StringTokenizer newTok = new StringTokenizer(sanitize(version), ".");
|
||||
StringTokenizer ourTok = new StringTokenizer(sanitize(RouterVersion.VERSION), ".");
|
||||
|
||||
while (newTok.hasMoreTokens() && ourTok.hasMoreTokens()) {
|
||||
String newVer = newTok.nextToken();
|
||||
String oldVer = ourTok.nextToken();
|
||||
switch (compare(newVer, oldVer)) {
|
||||
case -1: // newVer is smaller
|
||||
return false;
|
||||
case 0: // eq
|
||||
break;
|
||||
case 1: // newVer is larger
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (newTok.hasMoreTokens() && !ourTok.hasMoreTokens())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final String VALID = "0123456789.";
|
||||
private static final String sanitize(String str) {
|
||||
StringBuffer buf = new StringBuffer(str);
|
||||
for (int i = 0; i < buf.length(); i++) {
|
||||
if (VALID.indexOf(buf.charAt(i)) == -1) {
|
||||
buf.deleteCharAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static final int compare(String lhs, String rhs) {
|
||||
try {
|
||||
int left = Integer.parseInt(lhs);
|
||||
int right = Integer.parseInt(rhs);
|
||||
if (left < right)
|
||||
return -1;
|
||||
else if (left == right)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
// ignore
|
||||
}
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
// ignore
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("News fetched from " + url + " with " + (alreadyTransferred+bytesTransferred));
|
||||
|
||||
File temp = new File(TEMP_NEWS_FILE);
|
||||
if (temp.exists()) {
|
||||
boolean copied = FileUtil.copy(TEMP_NEWS_FILE, NEWS_FILE, true);
|
||||
if (copied) {
|
||||
temp.delete();
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Failed to copy the news file!");
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Transfer complete, but no file?");
|
||||
}
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Failed to fetch the news from " + url);
|
||||
File temp = new File(TEMP_NEWS_FILE);
|
||||
temp.delete();
|
||||
}
|
||||
}
|
@@ -4,8 +4,6 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.admin.StatsGenerator;
|
||||
|
||||
|
@@ -8,14 +8,12 @@ import java.io.OutputStream;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handler to deal with reseed requests. This reseed from the URL
|
||||
|
@@ -4,19 +4,18 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.apps.systray.SysTray;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.WebApplicationContext;
|
||||
import org.mortbay.http.DigestAuthenticator;
|
||||
import org.mortbay.http.handler.SecurityHandler;
|
||||
import org.mortbay.http.HashUserRealm;
|
||||
import org.mortbay.http.HttpRequest;
|
||||
import org.mortbay.http.SecurityConstraint;
|
||||
import org.mortbay.http.Authenticator;
|
||||
import org.mortbay.util.MultiException;
|
||||
|
||||
public class RouterConsoleRunner {
|
||||
private Server _server;
|
||||
@@ -73,12 +72,17 @@ public class RouterConsoleRunner {
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext());
|
||||
I2PThread t = new I2PThread(fetcher, "NewsFetcher");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void initialize(WebApplicationContext context) {
|
||||
String password = getPassword();
|
||||
if (password != null) {
|
||||
HashUserRealm realm = new HashUserRealm();
|
||||
HashUserRealm realm = new HashUserRealm("i2prouter");
|
||||
realm.put("admin", password);
|
||||
realm.addUserToRole("admin", "routerAdmin");
|
||||
context.setRealm(realm);
|
||||
|
@@ -3,7 +3,6 @@ package net.i2p.router.web;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Writer;
|
||||
|
||||
import net.i2p.data.Hash;
|
||||
|
@@ -1,10 +1,10 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
@@ -70,8 +70,33 @@ public class SummaryHelper {
|
||||
else
|
||||
return DataHelper.formatDuration(router.getUptime());
|
||||
}
|
||||
|
||||
|
||||
private static final DateFormat _fmt = new java.text.SimpleDateFormat("HH:mm:ss", Locale.UK);
|
||||
public String getTime() {
|
||||
if (_context == null) return "";
|
||||
|
||||
String now = null;
|
||||
synchronized (_fmt) {
|
||||
now = _fmt.format(new Date(_context.clock().now()));
|
||||
}
|
||||
|
||||
long ms = _context.clock().getOffset();
|
||||
|
||||
if (ms < 60 * 1000) {
|
||||
return now + " (" + (ms / 1000) + "s)";
|
||||
} else if (ms < 60 * 60 * 1000) {
|
||||
return now + " (" + (ms / (60 * 1000)) + "m)";
|
||||
} else if (ms < 24 * 60 * 60 * 1000) {
|
||||
return now + " (" + (ms / (60 * 60 * 1000)) + "h)";
|
||||
} else {
|
||||
return now + " (" + (ms / (24 * 60 * 60 * 1000)) + "d)";
|
||||
}
|
||||
}
|
||||
|
||||
public boolean allowReseed() {
|
||||
return (_context.netDb().getKnownRouters() < 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve amount of used memory.
|
||||
*
|
||||
@@ -442,4 +467,8 @@ public class SummaryHelper {
|
||||
|
||||
return _context.throttle().getTunnelLag() + "ms";
|
||||
}
|
||||
|
||||
public boolean updateAvailable() {
|
||||
return NewsFetcher.getInstance(_context).updateAvailable();
|
||||
}
|
||||
}
|
@@ -0,0 +1,168 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handle the request to update the router by firing off an EepGet call and
|
||||
* displaying its status to anyone who asks. After the download completes,
|
||||
* it is verified with the TrustedUpdate, and if it is authentic, the router
|
||||
* is restarted.
|
||||
*
|
||||
*/
|
||||
public class UpdateHandler {
|
||||
private static UpdateRunner _updateRunner;
|
||||
private RouterContext _context;
|
||||
private Log _log;
|
||||
private DecimalFormat _pct = new DecimalFormat("00.0%");
|
||||
|
||||
private static final String SIGNED_UPDATE_FILE = "i2pupdate.sud";
|
||||
|
||||
public UpdateHandler() {}
|
||||
public UpdateHandler(RouterContext ctx) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(UpdateHandler.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
*
|
||||
* @param contextId begging few characters of the routerHash, or null to pick
|
||||
* the first one we come across.
|
||||
*/
|
||||
public void setContextId(String contextId) {
|
||||
try {
|
||||
_context = ContextHelper.getContext(contextId);
|
||||
_log = _context.logManager().getLog(UpdateHandler.class);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setUpdateNonce(String nonce) {
|
||||
if (nonce == null) return;
|
||||
if (nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.nonce")) ||
|
||||
nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
synchronized (UpdateHandler.class) {
|
||||
if (_updateRunner == null)
|
||||
_updateRunner = new UpdateRunner();
|
||||
if (_updateRunner.isRunning()) {
|
||||
return;
|
||||
} else {
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "true");
|
||||
I2PThread update = new I2PThread(_updateRunner, "Update");
|
||||
update.start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return _updateRunner.getStatus();
|
||||
}
|
||||
|
||||
public class UpdateRunner implements Runnable, EepGet.StatusListener {
|
||||
private boolean _isRunning;
|
||||
private String _status;
|
||||
private long _startedOn;
|
||||
private long _written;
|
||||
public UpdateRunner() {
|
||||
_isRunning = false;
|
||||
_status = "<b>Updating</b><br />";
|
||||
}
|
||||
public boolean isRunning() { return _isRunning; }
|
||||
public String getStatus() { return _status; }
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
update();
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.updateInProgress", "false");
|
||||
_isRunning = false;
|
||||
}
|
||||
private void update() {
|
||||
_startedOn = -1;
|
||||
_status = "<b>Updating</b><br />";
|
||||
String updateURL = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
|
||||
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
|
||||
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
|
||||
String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT);
|
||||
int proxyPort = -1;
|
||||
try {
|
||||
proxyPort = Integer.parseInt(port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
EepGet get = null;
|
||||
if (shouldProxy)
|
||||
get = new EepGet(_context, proxyHost, proxyPort, 10, SIGNED_UPDATE_FILE, updateURL);
|
||||
else
|
||||
get = new EepGet(_context, 10, SIGNED_UPDATE_FILE, updateURL);
|
||||
get.addStatusListener(UpdateRunner.this);
|
||||
_startedOn = _context.clock().now();
|
||||
get.fetch();
|
||||
} catch (Throwable t) {
|
||||
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t);
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
}
|
||||
}
|
||||
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Attempt failed on " + url, cause);
|
||||
_written = 0;
|
||||
// ignored
|
||||
}
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
_written += currentWrite;
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append("<b>Updating</b> ");
|
||||
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
|
||||
synchronized (_pct) {
|
||||
buf.append(_pct.format(pct));
|
||||
}
|
||||
buf.append(":<br />\n").append(_written+alreadyTransferred);
|
||||
buf.append(" transferred<br />");
|
||||
_status = buf.toString();
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
_status = "<b>Update downloaded</b><br />";
|
||||
TrustedUpdate up = new TrustedUpdate(_context);
|
||||
boolean ok = up.migrateVerified(SIGNED_UPDATE_FILE, "i2pupdate.zip");
|
||||
File f = new File(SIGNED_UPDATE_FILE);
|
||||
f.delete();
|
||||
if (ok) {
|
||||
_log.log(Log.CRIT, "Update was VERIFIED, restarting to install it");
|
||||
_status = "<b>Update verified</b><br />Restarting<br />";
|
||||
restart();
|
||||
} else {
|
||||
_log.log(Log.CRIT, "Update was INVALID - have you changed your keys?");
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
}
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_log.log(Log.CRIT, "Update did not download completely (" + bytesTransferred + " with "
|
||||
+ bytesRemaining + " after " + currentAttempt + " tries)");
|
||||
|
||||
_status = "<b>Transfer failed</b><br />";
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
}
|
||||
}
|
||||
|
||||
private void restart() {
|
||||
_context.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
|
||||
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
|
||||
}
|
||||
}
|
@@ -2,9 +2,11 @@
|
||||
%>Network | <% } else { %><a href="config.jsp">Network</a> | <% }
|
||||
if (request.getRequestURI().indexOf("configservice.jsp") != -1) {
|
||||
%>Service | <% } else { %><a href="configservice.jsp">Service</a> | <% }
|
||||
if (request.getRequestURI().indexOf("configupdate.jsp") != -1) {
|
||||
%>Update | <% } else { %><a href="configupdate.jsp">Update</a> | <% }
|
||||
if (request.getRequestURI().indexOf("configtunnels.jsp") != -1) {
|
||||
%>Tunnels | <% } else { %><a href="configtunnels.jsp">Tunnels</a> | <% }
|
||||
if (request.getRequestURI().indexOf("configlogging.jsp") != -1) {
|
||||
%>Logging | <% } else { %><a href="configlogging.jsp">Logging</a> | <% }
|
||||
if (request.getRequestURI().indexOf("configadvanced.jsp") != -1) {
|
||||
%>Advanced | <% } else { %><a href="configadvanced.jsp">Advanced</a> | <% } %></h4>
|
||||
%>Advanced<% } else { %><a href="configadvanced.jsp">Advanced</a><% } %></h4>
|
||||
|
51
apps/routerconsole/jsp/configupdate.jsp
Normal file
51
apps/routerconsole/jsp/configupdate.jsp
Normal file
@@ -0,0 +1,51 @@
|
||||
<%@page contentType="text/html"%>
|
||||
<%@page pageEncoding="UTF-8"%>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2P Router Console - config update</title>
|
||||
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||
</head><body>
|
||||
|
||||
<%@include file="nav.jsp" %>
|
||||
<%@include file="summary.jsp" %>
|
||||
|
||||
<div class="main" id="main">
|
||||
<%@include file="confignav.jsp" %>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigUpdateHandler" id="formhandler" scope="request" />
|
||||
<jsp:setProperty name="formhandler" property="*" />
|
||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<font color="red"><jsp:getProperty name="formhandler" property="errors" /></font>
|
||||
<i><jsp:getProperty name="formhandler" property="notices" /></i>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigUpdateHelper" id="updatehelper" scope="request" />
|
||||
<jsp:setProperty name="updatehelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
|
||||
<form action="configupdate.jsp" method="POST">
|
||||
<% String prev = System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce");
|
||||
if (prev != null) System.setProperty("net.i2p.router.web.ConfigUpdateHandler.noncePrev", prev);
|
||||
System.setProperty("net.i2p.router.web.ConfigUpdateHandler.nonce", new java.util.Random().nextLong()+""); %>
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce")%>" />
|
||||
<input type="hidden" name="action" value="update" />
|
||||
News URL:
|
||||
<input type="text" size="60" name="newsURL" value="<jsp:getProperty name="updatehelper" property="newsURL" />"><br />
|
||||
Refresh frequency:
|
||||
<jsp:getProperty name="updatehelper" property="refreshFrequencySelectBox" /><br />
|
||||
Update URL:
|
||||
<input type="text" size="60" name="updateURL" value="<jsp:getProperty name="updatehelper" property="updateURL" />"><br />
|
||||
Update policy:
|
||||
<jsp:getProperty name="updatehelper" property="updatePolicySelectBox" /><br />
|
||||
Update anonymously?
|
||||
<jsp:getProperty name="updatehelper" property="updateThroughProxy" /><br />
|
||||
Proxy host: <input type="text" size="10" name="proxyHost" value="<jsp:getProperty name="updatehelper" property="proxyHost" />" /><br />
|
||||
Proxy port: <input type="text" size="4" name="proxyPort" value="<jsp:getProperty name="updatehelper" property="proxyPort" />" /><br />
|
||||
<!-- prompt for the eepproxy -->
|
||||
Trusted keys:
|
||||
<textarea name="trustedKeys" disabled="true" cols="60" rows="2"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea>
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -60,3 +60,12 @@ div.main {
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
div.news {
|
||||
margin: 0em 1em 1em 224px;
|
||||
padding: .5em 1em;
|
||||
background-color: #ffffc0;
|
||||
border: medium solid #ffffd0;
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
}
|
||||
|
@@ -10,6 +10,13 @@
|
||||
<%@include file="nav.jsp" %>
|
||||
<%@include file="summary.jsp" %>
|
||||
|
||||
<div class="news" id="news">
|
||||
<jsp:useBean class="net.i2p.router.web.ContentHelper" id="newshelper" scope="request" />
|
||||
<jsp:setProperty name="newshelper" property="page" value="docs/news.xml" />
|
||||
<jsp:setProperty name="newshelper" property="maxLines" value="300" />
|
||||
<jsp:getProperty name="newshelper" property="content" />
|
||||
</div>
|
||||
|
||||
<div class="main" id="main">
|
||||
<jsp:useBean class="net.i2p.router.web.ContentHelper" id="contenthelper" scope="request" />
|
||||
<jsp:setProperty name="contenthelper" property="page" value="docs/readme.html" />
|
||||
|
@@ -19,6 +19,9 @@
|
||||
<h4>Connection logs:</h4><a name="connectionlogs"> </a>
|
||||
<jsp:getProperty name="logsHelper" property="connectionLogs" />
|
||||
<hr />
|
||||
<h4>Critical logs:</h4><a name="criticallogs"> </a>
|
||||
<jsp:getProperty name="logsHelper" property="criticalLogs" />
|
||||
<hr />
|
||||
<h4>Service logs:</h4><a name="servicelogs"> </a>
|
||||
<jsp:getProperty name="logsHelper" property="serviceLogs" />
|
||||
</div>
|
||||
|
@@ -4,14 +4,34 @@
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ReseedHandler" id="reseed" scope="request" />
|
||||
<jsp:setProperty name="reseed" property="*" />
|
||||
<jsp:useBean class="net.i2p.router.web.UpdateHandler" id="update" scope="request" />
|
||||
<jsp:setProperty name="update" property="*" />
|
||||
<jsp:setProperty name="update" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
|
||||
<div class="routersummary">
|
||||
<u><b>General</b></u><br />
|
||||
<b>Ident:</b> <jsp:getProperty name="helper" property="ident" /><br />
|
||||
<b>Version:</b> <jsp:getProperty name="helper" property="version" /><br />
|
||||
<b>Uptime:</b> <jsp:getProperty name="helper" property="uptime" /><br />
|
||||
<b>Memory:</b> <jsp:getProperty name="helper" property="memory" /><br />
|
||||
<hr />
|
||||
<b>Now:</b> <jsp:getProperty name="helper" property="time" /><br />
|
||||
<b>Memory:</b> <jsp:getProperty name="helper" property="memory" /><br /><%
|
||||
if (helper.updateAvailable()) {
|
||||
if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) {
|
||||
out.print(update.getStatus());
|
||||
} else {
|
||||
long nonce = new java.util.Random().nextLong();
|
||||
String prev = System.getProperty("net.i2p.router.web.UpdateHandler.nonce");
|
||||
if (prev != null) System.setProperty("net.i2p.router.web.UpdateHandler.noncePrev", prev);
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.nonce", nonce+"");
|
||||
String uri = request.getRequestURI();
|
||||
if (uri.indexOf('?') > 0)
|
||||
uri = uri + "&updateNonce=" + nonce;
|
||||
else
|
||||
uri = uri + "?updateNonce=" + nonce;
|
||||
out.print(" <a href=\"" + uri + "\">Update available</a>");
|
||||
}
|
||||
}
|
||||
%><hr />
|
||||
|
||||
<u><b>Peers</b></u><br />
|
||||
<b>Active:</b> <jsp:getProperty name="helper" property="activePeers" />/<jsp:getProperty name="helper" property="activeProfiles" /><br />
|
||||
@@ -23,7 +43,7 @@
|
||||
if (helper.getActivePeers() <= 0) {
|
||||
%><b><a href="config.jsp">check your NAT/firewall</a></b><br /><%
|
||||
}
|
||||
if (helper.getActiveProfiles() <= 10) { // 10 is the min fallback
|
||||
if (helper.allowReseed()) {
|
||||
if ("true".equals(System.getProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false"))) {
|
||||
out.print(" <i>reseeding</i>");
|
||||
} else {
|
||||
|
12
apps/routerconsole/jsp/verifyupdate.jsp
Normal file
12
apps/routerconsole/jsp/verifyupdate.jsp
Normal file
@@ -0,0 +1,12 @@
|
||||
<%@page contentType="text/html" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2P Router Console - verify update file signature</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- net.i2p.crypto.TrustedUpdate.verify(request.getParameter("filename")) -->
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -17,7 +17,6 @@ import java.io.InputStreamReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -221,7 +220,7 @@ public class SAMBridge implements Runnable {
|
||||
SAMBridge bridge = new SAMBridge(host, port, opts, keyfile);
|
||||
I2PThread t = new I2PThread(bridge, "SAMListener");
|
||||
if (Boolean.valueOf(System.getProperty("sam.shutdownOnOOM", "false")).booleanValue()) {
|
||||
t.addOOMEventListener(new I2PThread.OOMEventListener() {
|
||||
I2PThread.addOOMEventListener(new I2PThread.OOMEventListener() {
|
||||
public void outOfMemory(OutOfMemoryError err) {
|
||||
err.printStackTrace();
|
||||
System.err.println("OOMed, die die die");
|
||||
|
@@ -8,9 +8,7 @@ package net.i2p.sam;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
|
@@ -132,6 +132,8 @@ public class SAMStreamSession {
|
||||
if (socketMgr == null) {
|
||||
throw new SAMException("Error creating I2PSocketManager");
|
||||
}
|
||||
|
||||
socketMgr.addDisconnectListener(new DisconnectListener());
|
||||
|
||||
forceFlush = Boolean.valueOf(allprops.getProperty(PROP_FORCE_FLUSH, DEFAULT_FORCE_FLUSH)).booleanValue();
|
||||
|
||||
@@ -156,6 +158,12 @@ public class SAMStreamSession {
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
private class DisconnectListener implements I2PSocketManager.DisconnectListener {
|
||||
public void sessionDisconnected() {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SAM STREAM session Destination.
|
||||
@@ -333,7 +341,7 @@ public class SAMStreamSession {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and close a SAM STREAM session socket handler.
|
||||
* Remove and gracefully close a SAM STREAM session socket handler.
|
||||
*
|
||||
* @param id Handler id to be removed
|
||||
*/
|
||||
@@ -349,12 +357,12 @@ public class SAMStreamSession {
|
||||
if (reader != null)
|
||||
reader.stopRunning();
|
||||
if (sender != null)
|
||||
sender.stopRunning();
|
||||
_log.debug("Removed SAM STREAM session socket handler " + id);
|
||||
sender.shutDownGracefully();
|
||||
_log.debug("Removed SAM STREAM session socket handler (gracefully) " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and close all the socket handlers managed by this SAM
|
||||
* Remove and hard close all the socket handlers managed by this SAM
|
||||
* STREAM session.
|
||||
*
|
||||
*/
|
||||
@@ -370,7 +378,7 @@ public class SAMStreamSession {
|
||||
while (iter.hasNext()) {
|
||||
id = (Integer)iter.next();
|
||||
((SAMStreamSessionSocketReader)handlersMap.get(id)).stopRunning();
|
||||
((StreamSender)sendersMap.get(id)).stopRunning();
|
||||
((StreamSender)sendersMap.get(id)).shutDownGracefully();
|
||||
}
|
||||
handlersMap.clear();
|
||||
sendersMap.clear();
|
||||
@@ -490,25 +498,20 @@ public class SAMStreamSession {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket reader
|
||||
* Stop a SAM STREAM session socket reader thead immediately.
|
||||
*
|
||||
*/
|
||||
public void stopRunning() {
|
||||
_log.debug("stopRunning() invoked on socket handler " + id);
|
||||
_log.debug("stopRunning() invoked on socket reader " + id);
|
||||
synchronized (runningLock) {
|
||||
if (stillRunning) {
|
||||
stillRunning = false;
|
||||
try {
|
||||
i2pSocket.close();
|
||||
} catch (IOException e) {
|
||||
_log.debug("Caught IOException", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_log.debug("SAM STREAM session socket handler running");
|
||||
_log.debug("run() called for socket reader " + id);
|
||||
|
||||
int read = -1;
|
||||
byte[] data = new byte[SOCKET_HANDLER_BUF_SIZE];
|
||||
@@ -560,7 +563,9 @@ public class SAMStreamSession {
|
||||
private int _id;
|
||||
private ByteCache _cache;
|
||||
private OutputStream _out = null;
|
||||
private boolean _stillRunning;
|
||||
private boolean _stillRunning, _shuttingDownGracefully;
|
||||
private Object runningLock = new Object();
|
||||
private I2PSocket i2pSocket = null;
|
||||
|
||||
public StreamSender(I2PSocket s, int id) throws IOException {
|
||||
_data = new ArrayList(1);
|
||||
@@ -568,6 +573,8 @@ public class SAMStreamSession {
|
||||
_cache = ByteCache.getInstance(4, 32*1024);
|
||||
_out = s.getOutputStream();
|
||||
_stillRunning = true;
|
||||
_shuttingDownGracefully = false;
|
||||
i2pSocket = s;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,28 +601,54 @@ public class SAMStreamSession {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket sender
|
||||
* Stop a SAM STREAM session socket sender thread immediately
|
||||
*
|
||||
*/
|
||||
public void stopRunning() {
|
||||
_log.debug("stopRunning() invoked on socket sender " + _id);
|
||||
_stillRunning = false;
|
||||
synchronized (_data) {
|
||||
_data.clear();
|
||||
_data.notifyAll();
|
||||
synchronized (runningLock) {
|
||||
if (_stillRunning) {
|
||||
_stillRunning = false;
|
||||
try {
|
||||
i2pSocket.close();
|
||||
} catch (IOException e) {
|
||||
_log.debug("Caught IOException", e);
|
||||
}
|
||||
synchronized (_data) {
|
||||
_data.clear();
|
||||
_data.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket sender gracefully: stop the
|
||||
* sender thread once all pending data has been sent.
|
||||
*/
|
||||
public void shutDownGracefully() {
|
||||
_log.debug("shutDownGracefully() invoked on socket sender " + _id);
|
||||
_shuttingDownGracefully = true;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_log.debug("run() called for socket sender " + _id);
|
||||
ByteArray data = null;
|
||||
while (_stillRunning) {
|
||||
data = null;
|
||||
try {
|
||||
synchronized (_data) {
|
||||
if (_data.size() > 0)
|
||||
if (_data.size() > 0) {
|
||||
data = (ByteArray)_data.remove(0);
|
||||
else
|
||||
} else if (_shuttingDownGracefully) {
|
||||
/* No data left and shutting down gracefully?
|
||||
If so, stop the sender. */
|
||||
stopRunning();
|
||||
break;
|
||||
} else {
|
||||
/* Wait for data. */
|
||||
_data.wait(5000);
|
||||
}
|
||||
}
|
||||
|
||||
if (data != null) {
|
||||
|
@@ -15,7 +15,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.Socket;
|
||||
|
@@ -2,7 +2,6 @@ package net.i2p.sam.client;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Properties;
|
||||
|
@@ -1,27 +1,19 @@
|
||||
package net.i2p.sam.client;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
||||
import net.i2p.sam.client.SAMEventHandler;
|
||||
import net.i2p.sam.client.SAMClientEventListenerImpl;
|
||||
import net.i2p.sam.client.SAMReader;
|
||||
|
||||
/**
|
||||
|
@@ -1,27 +1,17 @@
|
||||
package net.i2p.sam.client;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
||||
import net.i2p.sam.client.SAMEventHandler;
|
||||
import net.i2p.sam.client.SAMClientEventListenerImpl;
|
||||
import net.i2p.sam.client.SAMReader;
|
||||
|
||||
/**
|
||||
|
@@ -30,14 +30,32 @@ public class TestStreamTransfer {
|
||||
private static Log _log = new Log(TestStreamTransfer.class);
|
||||
private static String _alice = null;
|
||||
private static boolean _dead = false;
|
||||
private static Object _counterLock = new Object();
|
||||
private static int _recvCounter = 0, _closeCounter = 0;
|
||||
|
||||
private static void runTest(String samHost, int samPort, String conOptions) {
|
||||
int nTests = 20;
|
||||
startAlice(samHost, samPort, conOptions);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
/* Start up nTests different test threads. */
|
||||
for (int i = 0; i < nTests; i++) {
|
||||
testBob("bob" + i, samHost, samPort, conOptions);
|
||||
if (i % 2 == 1)
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
/* Wait until the correct number of messages have been received
|
||||
by Alices and the correct number of streams have been closed
|
||||
by Bobs. */
|
||||
while (true) {
|
||||
synchronized (_counterLock) {
|
||||
if (_recvCounter == nTests * 2 && _closeCounter == nTests) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
|
||||
_log.info("Receive counter is: " + _recvCounter + " Close counter is: " + _closeCounter);
|
||||
}
|
||||
/* Return, assuming the test has passed. */
|
||||
_log.info("Unit test passed.");
|
||||
}
|
||||
|
||||
private static void startAlice(String host, int port, String conOptions) {
|
||||
@@ -151,6 +169,9 @@ public class TestStreamTransfer {
|
||||
return;
|
||||
}
|
||||
_log.info("\n== Received from the stream " + id + ": [" + new String(payload) + "]");
|
||||
synchronized (_counterLock) {
|
||||
_recvCounter++;
|
||||
}
|
||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
||||
/*
|
||||
// now echo it back
|
||||
@@ -225,11 +246,15 @@ public class TestStreamTransfer {
|
||||
_log.info("\n** Sending FooBarBaz!");
|
||||
out.write(req.getBytes());
|
||||
out.flush();
|
||||
try { Thread.sleep(20*1000); } catch (InterruptedException ie) {}
|
||||
/* Don't delay here, so we can test whether all data is
|
||||
sent even if we do a STREAM CLOSE immediately. */
|
||||
_log.info("Sending close");
|
||||
req = "STREAM CLOSE ID=42\n";
|
||||
out.write(req.getBytes());
|
||||
out.flush();
|
||||
synchronized (_counterLock) {
|
||||
_closeCounter++;
|
||||
}
|
||||
try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
|
||||
//_dead = true;
|
||||
s.close();
|
||||
|
@@ -2,19 +2,15 @@ package net.i2p.client.streaming;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.SessionTag;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
|
||||
@@ -57,7 +53,7 @@ public class Connection {
|
||||
private I2PSocketFull _socket;
|
||||
/** set to an error cause if the connection could not be established */
|
||||
private String _connectionError;
|
||||
private boolean _disconnectScheduled;
|
||||
private long _disconnectScheduledOn;
|
||||
private long _lastReceivedOn;
|
||||
private ActivityTimer _activityTimer;
|
||||
/** window size when we last saw congestion */
|
||||
@@ -75,8 +71,8 @@ public class Connection {
|
||||
private long _lifetimeDupMessageSent;
|
||||
private long _lifetimeDupMessageReceived;
|
||||
|
||||
public static final long MAX_RESEND_DELAY = 60*1000;
|
||||
public static final long MIN_RESEND_DELAY = 30*1000;
|
||||
public static final long MAX_RESEND_DELAY = 20*1000;
|
||||
public static final long MIN_RESEND_DELAY = 10*1000;
|
||||
|
||||
/** wait up to 5 minutes after disconnection so we can ack/close packets */
|
||||
public static int DISCONNECT_TIMEOUT = 5*60*1000;
|
||||
@@ -113,7 +109,7 @@ public class Connection {
|
||||
_connectionManager = manager;
|
||||
_resetReceived = false;
|
||||
_connected = true;
|
||||
_disconnectScheduled = false;
|
||||
_disconnectScheduledOn = -1;
|
||||
_lastReceivedOn = -1;
|
||||
_activityTimer = new ActivityTimer();
|
||||
_ackSinceCongestion = true;
|
||||
@@ -181,9 +177,15 @@ public class Connection {
|
||||
}
|
||||
}
|
||||
}
|
||||
void windowAdjusted() {
|
||||
synchronized (_outboundPackets) {
|
||||
_outboundPackets.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
void ackImmediately() {
|
||||
_receiver.send(null, 0, 0);
|
||||
PacketLocal packet = _receiver.send(null, 0, 0);
|
||||
//packet.releasePayload();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,6 +193,10 @@ public class Connection {
|
||||
*
|
||||
*/
|
||||
void sendReset() {
|
||||
if (_disconnectScheduledOn < 0) {
|
||||
_disconnectScheduledOn = _context.clock().now();
|
||||
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
|
||||
}
|
||||
_resetSent = true;
|
||||
if (_resetSentOn <= 0)
|
||||
_resetSentOn = _context.clock().now();
|
||||
@@ -252,7 +258,7 @@ public class Connection {
|
||||
}
|
||||
packet.setFlag(Packet.FLAG_DELAY_REQUESTED);
|
||||
|
||||
long timeout = (_options.getRTT() < MIN_RESEND_DELAY ? MIN_RESEND_DELAY : _options.getRTT());
|
||||
long timeout = _options.getRTT() + MIN_RESEND_DELAY;
|
||||
if (timeout > MAX_RESEND_DELAY)
|
||||
timeout = MAX_RESEND_DELAY;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -382,6 +388,10 @@ public class Connection {
|
||||
}
|
||||
|
||||
void resetReceived() {
|
||||
if (_disconnectScheduledOn < 0) {
|
||||
_disconnectScheduledOn = _context.clock().now();
|
||||
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
|
||||
}
|
||||
_resetReceived = true;
|
||||
MessageOutputStream mos = _outputStream;
|
||||
MessageInputStream mis = _inputStream;
|
||||
@@ -398,6 +408,7 @@ public class Connection {
|
||||
public boolean getHardDisconnected() { return _hardDisconnected; }
|
||||
public boolean getResetSent() { return _resetSent; }
|
||||
public long getResetSentOn() { return _resetSentOn; }
|
||||
public long getDisconnectScheduledOn() { return _disconnectScheduledOn; }
|
||||
|
||||
void disconnect(boolean cleanDisconnect) {
|
||||
disconnect(cleanDisconnect, true);
|
||||
@@ -424,8 +435,8 @@ public class Connection {
|
||||
killOutstandingPackets();
|
||||
}
|
||||
if (removeFromConMgr) {
|
||||
if (!_disconnectScheduled) {
|
||||
_disconnectScheduled = true;
|
||||
if (_disconnectScheduledOn < 0) {
|
||||
_disconnectScheduledOn = _context.clock().now();
|
||||
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
@@ -445,8 +456,8 @@ public class Connection {
|
||||
SimpleTimer.getInstance().removeEvent(_activityTimer);
|
||||
_activityTimer = null;
|
||||
|
||||
if (!_disconnectScheduled) {
|
||||
_disconnectScheduled = true;
|
||||
if (_disconnectScheduledOn < 0) {
|
||||
_disconnectScheduledOn = _context.clock().now();
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Connection disconnect complete from dead, drop the con "
|
||||
@@ -573,15 +584,23 @@ 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; }
|
||||
public void setCloseSentOn(long when) { _closeSentOn = when; }
|
||||
public void setCloseSentOn(long when) {
|
||||
_closeSentOn = when;
|
||||
if (_disconnectScheduledOn < 0) {
|
||||
_disconnectScheduledOn = _context.clock().now();
|
||||
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
public long getCloseReceivedOn() { return _closeReceivedOn; }
|
||||
public void setCloseReceivedOn(long when) { _closeReceivedOn = when; }
|
||||
|
||||
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();
|
||||
@@ -850,7 +869,10 @@ public class Connection {
|
||||
_log.warn("Congestion resending packet " + _packet.getSequenceNum() + ": new windowSize " + newWindowSize
|
||||
+ ") for " + Connection.this.toString());
|
||||
|
||||
// setRTT has its own ceiling
|
||||
getOptions().setRTT(getOptions().getRTT() + 10*1000);
|
||||
getOptions().setWindowSize(newWindowSize);
|
||||
windowAdjusted();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,13 +892,15 @@ public class Connection {
|
||||
_context.sessionKeyManager().failTags(_remotePeer.getPublicKey());
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Resend packet " + _packet + " time " + numSends +
|
||||
" activeResends: " + _activeResends +
|
||||
" (wsize "
|
||||
+ newWindowSize + " lifetime "
|
||||
+ (_context.clock().now() - _packet.getCreatedOn()) + "ms)");
|
||||
_outboundQueue.enqueue(_packet);
|
||||
if (numSends - 1 <= _options.getMaxResends()) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Resend packet " + _packet + " time " + numSends +
|
||||
" activeResends: " + _activeResends +
|
||||
" (wsize "
|
||||
+ newWindowSize + " lifetime "
|
||||
+ (_context.clock().now() - _packet.getCreatedOn()) + "ms)");
|
||||
_outboundQueue.enqueue(_packet);
|
||||
}
|
||||
|
||||
_lastSendTime = _context.clock().now();
|
||||
|
||||
@@ -889,7 +913,7 @@ public class Connection {
|
||||
return;
|
||||
}
|
||||
|
||||
if (numSends > _options.getMaxResends()) {
|
||||
if (numSends - 1 > _options.getMaxResends()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Too many resends");
|
||||
_packet.cancelled();
|
||||
|
@@ -1,8 +1,7 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.IOException;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -131,13 +130,19 @@ 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);
|
||||
byte data[] = new byte[size];
|
||||
//ByteArray data = packet.acquirePayload();
|
||||
ByteArray data = new ByteArray(new byte[size]);
|
||||
if (size > 0)
|
||||
System.arraycopy(buf, off, data, 0, size);
|
||||
System.arraycopy(buf, off, data.getData(), 0, size);
|
||||
data.setValid(size);
|
||||
data.setOffset(0);
|
||||
packet.setPayload(data);
|
||||
if (ackOnly && !forceIncrement)
|
||||
if ( (ackOnly && !forceIncrement) && (!isFirst) )
|
||||
packet.setSequenceNum(0);
|
||||
else
|
||||
packet.setSequenceNum(con.getNextOutboundPacketNum());
|
||||
@@ -155,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());
|
||||
|
@@ -328,6 +328,7 @@ public class ConnectionManager {
|
||||
}
|
||||
|
||||
_outboundQueue.enqueue(packet);
|
||||
packet.releasePayload();
|
||||
|
||||
if (blocking) {
|
||||
synchronized (req) {
|
||||
|
@@ -81,8 +81,8 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
super.init(opts);
|
||||
setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
|
||||
setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK));
|
||||
setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 16*1024));
|
||||
setRTT(getInt(opts, PROP_INITIAL_RTT, 30*1000));
|
||||
setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 4*1024));
|
||||
setRTT(getInt(opts, PROP_INITIAL_RTT, 10*1000));
|
||||
setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1));
|
||||
setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 1000));
|
||||
setSendAckDelay(getInt(opts, PROP_INITIAL_ACK_DELAY, 1000));
|
||||
@@ -107,7 +107,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
if (opts.containsKey(PROP_MAX_MESSAGE_SIZE))
|
||||
setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, Packet.MAX_PAYLOAD_SIZE));
|
||||
if (opts.containsKey(PROP_INITIAL_RTT))
|
||||
setRTT(getInt(opts, PROP_INITIAL_RTT, 30*1000));
|
||||
setRTT(getInt(opts, PROP_INITIAL_RTT, 10*1000));
|
||||
if (opts.containsKey(PROP_INITIAL_RECEIVE_WINDOW))
|
||||
setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1));
|
||||
if (opts.containsKey(PROP_INITIAL_RESEND_DELAY))
|
||||
@@ -160,6 +160,8 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
public void setWindowSize(int numMsgs) {
|
||||
if (numMsgs > _maxWindowSize)
|
||||
numMsgs = _maxWindowSize;
|
||||
else if (numMsgs <= 0)
|
||||
numMsgs = 1;
|
||||
_windowSize = numMsgs;
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,7 @@ public class ConnectionPacketHandler {
|
||||
if (!ok) {
|
||||
if ( (!packet.isFlagSet(Packet.FLAG_RESET)) && (_log.shouldLog(Log.ERROR)) )
|
||||
_log.error("Packet does NOT verify: " + packet);
|
||||
packet.releasePayload();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -47,6 +48,7 @@ public class ConnectionPacketHandler {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Received a packet after hard disconnect, ignoring: " + packet + " on " + con);
|
||||
}
|
||||
packet.releasePayload();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,6 +74,7 @@ public class ConnectionPacketHandler {
|
||||
+ ": dropping " + packet);
|
||||
ack(con, packet.getAckThrough(), packet.getNacks(), null, false);
|
||||
con.getOptions().setChoke(5*1000);
|
||||
packet.releasePayload();
|
||||
return;
|
||||
}
|
||||
con.getOptions().setChoke(0);
|
||||
@@ -91,6 +94,7 @@ public class ConnectionPacketHandler {
|
||||
con.closeReceived();
|
||||
|
||||
boolean fastAck = false;
|
||||
boolean ackOnly = false;
|
||||
|
||||
if (isNew) {
|
||||
con.incrementUnackedPacketsReceived();
|
||||
@@ -127,11 +131,19 @@ public class ConnectionPacketHandler {
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("ACK only packet received: " + packet);
|
||||
ackOnly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fastAck = fastAck || ack(con, packet.getAckThrough(), packet.getNacks(), packet, isNew);
|
||||
|
||||
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE) &&
|
||||
((packet.getSendStreamId() == null) ||
|
||||
DataHelper.eq(packet.getSendStreamId(), Packet.STREAM_ID_UNKNOWN) ) ) {
|
||||
// don't honor the ACK 0 in SYN packets received when the other side
|
||||
// has obviously not seen our messages
|
||||
} else {
|
||||
fastAck = fastAck || ack(con, packet.getAckThrough(), packet.getNacks(), packet, isNew);
|
||||
}
|
||||
con.eventOccurred();
|
||||
if (fastAck) {
|
||||
if (con.getLastSendTime() + 2000 < _context.clock().now()) {
|
||||
@@ -140,6 +152,11 @@ public class ConnectionPacketHandler {
|
||||
con.ackImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
if (ackOnly || !isNew) {
|
||||
// non-ack message payloads are queued in the MessageInputStream
|
||||
packet.releasePayload();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ack(Connection con, long ackThrough, long nacks[], Packet packet, boolean isNew) {
|
||||
@@ -199,6 +216,8 @@ public class ConnectionPacketHandler {
|
||||
+ con.getLastCongestionSeenAt() + " (#resends: " + numResends
|
||||
+ ") for " + con);
|
||||
|
||||
// setRTT has its own ceiling
|
||||
con.getOptions().setRTT(con.getOptions().getRTT() + 10*1000);
|
||||
con.getOptions().setWindowSize(oldSize);
|
||||
|
||||
congested = true;
|
||||
@@ -224,6 +243,9 @@ public class ConnectionPacketHandler {
|
||||
newWindowSize += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (newWindowSize <= 0)
|
||||
newWindowSize = 1;
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("New window size " + newWindowSize + "/" + oldWindow + " congestionSeenAt: "
|
||||
@@ -233,6 +255,7 @@ public class ConnectionPacketHandler {
|
||||
con.setCongestionWindowEnd(newWindowSize + lowest);
|
||||
}
|
||||
|
||||
con.windowAdjusted();
|
||||
return congested;
|
||||
}
|
||||
|
||||
@@ -255,11 +278,15 @@ public class ConnectionPacketHandler {
|
||||
con.setRemotePeer(packet.getOptionalFrom());
|
||||
return true;
|
||||
} else {
|
||||
// neither RST nor SYN and we dont have the stream id yet? nuh uh
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Packet without RST or SYN where we dont know stream ID: "
|
||||
+ packet);
|
||||
return false;
|
||||
// neither RST nor SYN and we dont have the stream id yet?
|
||||
if (packet.getSequenceNum() <= 2) {
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Packet without RST or SYN where we dont know stream ID: "
|
||||
+ packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) {
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import net.i2p.I2PException;
|
||||
|
||||
/**
|
||||
|
@@ -13,9 +13,15 @@ import net.i2p.data.Destination;
|
||||
public class I2PSocketFull implements I2PSocket {
|
||||
private Connection _connection;
|
||||
private I2PSocket.SocketErrorListener _listener;
|
||||
private Destination _remotePeer;
|
||||
private Destination _localPeer;
|
||||
|
||||
public I2PSocketFull(Connection con) {
|
||||
_connection = con;
|
||||
if (con != null) {
|
||||
_remotePeer = con.getRemotePeer();
|
||||
_localPeer = con.getSession().getMyDestination();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
@@ -35,44 +41,70 @@ public class I2PSocketFull implements I2PSocket {
|
||||
Connection getConnection() { return _connection; }
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return _connection.getInputStream();
|
||||
Connection c = _connection;
|
||||
if (c != null)
|
||||
return c.getInputStream();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public I2PSocketOptions getOptions() {
|
||||
return _connection.getOptions();
|
||||
Connection c = _connection;
|
||||
if (c != null)
|
||||
return c.getOptions();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return _connection.getOutputStream();
|
||||
Connection c = _connection;
|
||||
if (c != null)
|
||||
return c.getOutputStream();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public Destination getPeerDestination() {
|
||||
return _connection.getRemotePeer();
|
||||
}
|
||||
public Destination getPeerDestination() { return _remotePeer; }
|
||||
|
||||
public long getReadTimeout() {
|
||||
return _connection.getOptions().getReadTimeout();
|
||||
I2PSocketOptions opts = getOptions();
|
||||
if (opts != null)
|
||||
return opts.getReadTimeout();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Destination getThisDestination() {
|
||||
return _connection.getSession().getMyDestination();
|
||||
}
|
||||
public Destination getThisDestination() { return _localPeer; }
|
||||
|
||||
public void setOptions(I2PSocketOptions options) {
|
||||
Connection c = _connection;
|
||||
if (c == null) return;
|
||||
|
||||
if (options instanceof ConnectionOptions)
|
||||
_connection.setOptions((ConnectionOptions)options);
|
||||
c.setOptions((ConnectionOptions)options);
|
||||
else
|
||||
_connection.setOptions(new ConnectionOptions(options));
|
||||
c.setOptions(new ConnectionOptions(options));
|
||||
}
|
||||
|
||||
public void setReadTimeout(long ms) {
|
||||
_connection.getOptions().setReadTimeout(ms);
|
||||
Connection c = _connection;
|
||||
if (c == null) return;
|
||||
|
||||
c.getOptions().setReadTimeout(ms);
|
||||
}
|
||||
|
||||
public void setSocketErrorListener(I2PSocket.SocketErrorListener lsnr) {
|
||||
_listener = lsnr;
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
Connection c = _connection;
|
||||
return ((c == null) ||
|
||||
(!c.getIsConnected()) ||
|
||||
(c.getResetReceived()) ||
|
||||
(c.getResetSent()));
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
_connection = null;
|
||||
_listener = null;
|
||||
|
@@ -1,15 +1,8 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -17,7 +10,6 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSessionListener;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -105,7 +97,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
|
||||
}
|
||||
|
||||
public I2PSocket receiveSocket() throws I2PException {
|
||||
if (_session.isClosed()) throw new I2PException("Session closed");
|
||||
verifySession();
|
||||
Connection con = _connectionManager.getConnectionHandler().accept(-1);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("receiveSocket() called: " + con);
|
||||
@@ -149,6 +141,12 @@ public class I2PSocketManagerFull implements I2PSocketManager {
|
||||
return _serverSocket;
|
||||
}
|
||||
|
||||
private void verifySession() throws I2PException {
|
||||
if (!_connectionManager.getSession().isClosed())
|
||||
return;
|
||||
_connectionManager.getSession().connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new connected socket (block until the socket is created)
|
||||
*
|
||||
@@ -160,8 +158,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
|
||||
*/
|
||||
public I2PSocket connect(Destination peer, I2PSocketOptions options)
|
||||
throws I2PException, NoRouteToHostException {
|
||||
if (_connectionManager.getSession().isClosed())
|
||||
throw new I2PException("Session is closed");
|
||||
verifySession();
|
||||
if (options == null)
|
||||
options = _defaultOptions;
|
||||
ConnectionOptions opts = null;
|
||||
|
@@ -92,7 +92,9 @@ public class MessageHandler implements I2PSessionListener {
|
||||
*/
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("error occurred: " + message, error);
|
||||
_log.error("error occurred: " + message + "- " + error.getMessage());
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("cause", error);
|
||||
//_manager.disconnectAllHard();
|
||||
}
|
||||
|
||||
|
@@ -2,8 +2,6 @@ package net.i2p.client.streaming;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -13,6 +11,7 @@ import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -52,6 +51,7 @@ public class MessageInputStream extends InputStream {
|
||||
private int _readTimeout;
|
||||
private IOException _streamError;
|
||||
private long _readTotal;
|
||||
private ByteCache _cache;
|
||||
|
||||
private byte[] _oneByte = new byte[1];
|
||||
|
||||
@@ -70,6 +70,7 @@ public class MessageInputStream extends InputStream {
|
||||
_dataLock = new Object();
|
||||
_closeReceived = false;
|
||||
_locallyClosed = false;
|
||||
_cache = ByteCache.getInstance(128, Packet.MAX_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
/** What is the highest block ID we've completely received through? */
|
||||
@@ -166,7 +167,7 @@ public class MessageInputStream extends InputStream {
|
||||
buf.append("Close received, ready bytes: ");
|
||||
long available = 0;
|
||||
for (int i = 0; i < _readyDataBlocks.size(); i++)
|
||||
available += ((ByteArray)_readyDataBlocks.get(i)).getData().length;
|
||||
available += ((ByteArray)_readyDataBlocks.get(i)).getValid();
|
||||
available -= _readyDataBlockIndex;
|
||||
buf.append(available);
|
||||
buf.append(" blocks: ").append(_readyDataBlocks.size());
|
||||
@@ -178,8 +179,8 @@ public class MessageInputStream extends InputStream {
|
||||
ByteArray ba = (ByteArray)_notYetReadyBlocks.get(id);
|
||||
buf.append(id).append(" ");
|
||||
|
||||
if (ba.getData() != null)
|
||||
notAvailable += ba.getData().length;
|
||||
if (ba != null)
|
||||
notAvailable += ba.getValid();
|
||||
}
|
||||
|
||||
buf.append("not ready bytes: ").append(notAvailable);
|
||||
@@ -198,10 +199,10 @@ public class MessageInputStream extends InputStream {
|
||||
*
|
||||
* @return true if this is a new packet, false if it is a dup
|
||||
*/
|
||||
public boolean messageReceived(long messageId, byte payload[]) {
|
||||
public boolean messageReceived(long messageId, ByteArray payload) {
|
||||
synchronized (_dataLock) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("received " + messageId + " with " + payload.length);
|
||||
_log.debug("received " + messageId + " with " + payload.getValid());
|
||||
if (messageId <= _highestReadyBlockId) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("ignoring dup message " + messageId);
|
||||
@@ -212,17 +213,17 @@ public class MessageInputStream extends InputStream {
|
||||
_highestBlockId = messageId;
|
||||
|
||||
if (_highestReadyBlockId + 1 == messageId) {
|
||||
if (!_locallyClosed && payload.length > 0) {
|
||||
if (!_locallyClosed && payload.getValid() > 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("accepting bytes as ready: " + payload.length);
|
||||
_readyDataBlocks.add(new ByteArray(payload));
|
||||
_log.debug("accepting bytes as ready: " + payload.getValid());
|
||||
_readyDataBlocks.add(payload);
|
||||
}
|
||||
_highestReadyBlockId = messageId;
|
||||
long cur = _highestReadyBlockId + 1;
|
||||
// now pull in any previously pending blocks
|
||||
while (_notYetReadyBlocks.containsKey(new Long(cur))) {
|
||||
ByteArray ba = (ByteArray)_notYetReadyBlocks.remove(new Long(cur));
|
||||
if ( (ba != null) && (ba.getData() != null) && (ba.getData().length > 0) ) {
|
||||
if ( (ba != null) && (ba.getData() != null) && (ba.getValid() > 0) ) {
|
||||
_readyDataBlocks.add(ba);
|
||||
}
|
||||
|
||||
@@ -238,7 +239,7 @@ public class MessageInputStream extends InputStream {
|
||||
if (_locallyClosed) // dont need the payload, just the msgId in order
|
||||
_notYetReadyBlocks.put(new Long(messageId), new ByteArray(null));
|
||||
else
|
||||
_notYetReadyBlocks.put(new Long(messageId), new ByteArray(payload));
|
||||
_notYetReadyBlocks.put(new Long(messageId), payload);
|
||||
_dataLock.notifyAll();
|
||||
}
|
||||
}
|
||||
@@ -324,21 +325,25 @@ public class MessageInputStream extends InputStream {
|
||||
} else {
|
||||
// either was already ready, or we wait()ed and it arrived
|
||||
ByteArray cur = (ByteArray)_readyDataBlocks.get(0);
|
||||
byte rv = cur.getData()[_readyDataBlockIndex];
|
||||
byte rv = cur.getData()[cur.getOffset()+_readyDataBlockIndex];
|
||||
_readyDataBlockIndex++;
|
||||
if (cur.getData().length <= _readyDataBlockIndex) {
|
||||
boolean removed = false;
|
||||
if (cur.getValid() <= _readyDataBlockIndex) {
|
||||
_readyDataBlockIndex = 0;
|
||||
_readyDataBlocks.remove(0);
|
||||
removed = true;
|
||||
}
|
||||
_readTotal++;
|
||||
target[offset + i] = rv; // rv < 0 ? rv + 256 : rv
|
||||
if ( (_readyDataBlockIndex <= 3) || (_readyDataBlockIndex >= cur.getData().length - 5) ) {
|
||||
if ( (_readyDataBlockIndex <= 3) || (_readyDataBlockIndex >= cur.getValid() - 5) ) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("read(...," + offset+", " + length+ ")[" + i
|
||||
+ "] after ready data: readyDataBlockIndex=" + _readyDataBlockIndex
|
||||
+ " readyBlocks=" + _readyDataBlocks.size()
|
||||
+ " readTotal=" + _readTotal);
|
||||
}
|
||||
//if (removed)
|
||||
// _cache.release(cur);
|
||||
}
|
||||
} // for (int i = 0; i < length; i++) {
|
||||
} // synchronized (_dataLock)
|
||||
@@ -357,9 +362,9 @@ public class MessageInputStream extends InputStream {
|
||||
for (int i = 0; i < _readyDataBlocks.size(); i++) {
|
||||
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
|
||||
if (i == 0)
|
||||
numBytes += cur.getData().length - _readyDataBlockIndex;
|
||||
numBytes += cur.getValid() - _readyDataBlockIndex;
|
||||
else
|
||||
numBytes += cur.getData().length;
|
||||
numBytes += cur.getValid();
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -380,13 +385,13 @@ public class MessageInputStream extends InputStream {
|
||||
for (int i = 0; i < _readyDataBlocks.size(); i++) {
|
||||
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
|
||||
if (i == 0)
|
||||
numBytes += cur.getData().length - _readyDataBlockIndex;
|
||||
numBytes += cur.getValid() - _readyDataBlockIndex;
|
||||
else
|
||||
numBytes += cur.getData().length;
|
||||
numBytes += cur.getValid();
|
||||
}
|
||||
for (Iterator iter = _notYetReadyBlocks.values().iterator(); iter.hasNext(); ) {
|
||||
ByteArray cur = (ByteArray)iter.next();
|
||||
numBytes += cur.getData().length;
|
||||
numBytes += cur.getValid();
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
@@ -399,9 +404,9 @@ public class MessageInputStream extends InputStream {
|
||||
for (int i = 0; i < _readyDataBlocks.size(); i++) {
|
||||
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
|
||||
if (i == 0)
|
||||
numBytes += cur.getData().length - _readyDataBlockIndex;
|
||||
numBytes += cur.getValid() - _readyDataBlockIndex;
|
||||
else
|
||||
numBytes += cur.getData().length;
|
||||
numBytes += cur.getValid();
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
@@ -409,6 +414,8 @@ public class MessageInputStream extends InputStream {
|
||||
|
||||
public void close() {
|
||||
synchronized (_dataLock) {
|
||||
//while (_readyDataBlocks.size() > 0)
|
||||
// _cache.release((ByteArray)_readyDataBlocks.remove(0));
|
||||
_readyDataBlocks.clear();
|
||||
|
||||
// we don't need the data, but we do need to keep track of the messageIds
|
||||
@@ -416,6 +423,7 @@ public class MessageInputStream extends InputStream {
|
||||
for (Iterator iter = _notYetReadyBlocks.values().iterator(); iter.hasNext(); ) {
|
||||
ByteArray ba = (ByteArray)iter.next();
|
||||
ba.setData(null);
|
||||
//_cache.release(ba);
|
||||
}
|
||||
_locallyClosed = true;
|
||||
_dataLock.notifyAll();
|
||||
|
@@ -3,11 +3,13 @@ package net.i2p.client.streaming;
|
||||
import java.util.Arrays;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.util.ByteCache;
|
||||
|
||||
/**
|
||||
* Contain a single packet transferred as part of a streaming connection.
|
||||
@@ -56,12 +58,13 @@ public class Packet {
|
||||
private long _nacks[];
|
||||
private int _resendDelay;
|
||||
private int _flags;
|
||||
private byte _payload[];
|
||||
private ByteArray _payload;
|
||||
// the next four are set only if the flags say so
|
||||
private Signature _optionSignature;
|
||||
private Destination _optionFrom;
|
||||
private int _optionDelay;
|
||||
private int _optionMaxSize;
|
||||
private ByteCache _cache;
|
||||
|
||||
/**
|
||||
* The receiveStreamId will be set to this when the packet doesn't know
|
||||
@@ -135,6 +138,10 @@ public class Packet {
|
||||
|
||||
public static final int DEFAULT_MAX_SIZE = 32*1024;
|
||||
private static final int MAX_DELAY_REQUEST = 65535;
|
||||
|
||||
public Packet() {
|
||||
_cache = ByteCache.getInstance(128, MAX_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
/** what stream is this packet a part of? */
|
||||
public byte[] getSendStreamId() {
|
||||
@@ -200,14 +207,28 @@ public class Packet {
|
||||
public static final int MAX_PAYLOAD_SIZE = 32*1024;
|
||||
|
||||
/** get the actual payload of the message. may be null */
|
||||
public byte[] getPayload() { return _payload; }
|
||||
public void setPayload(byte payload[]) {
|
||||
public ByteArray getPayload() { return _payload; }
|
||||
public void setPayload(ByteArray payload) {
|
||||
//if ( (_payload != null) && (_payload != payload) )
|
||||
// _cache.release(_payload);
|
||||
_payload = payload;
|
||||
if ( (payload != null) && (payload.length > MAX_PAYLOAD_SIZE) )
|
||||
throw new IllegalArgumentException("Too large payload: " + payload.length);
|
||||
if ( (payload != null) && (payload.getValid() > MAX_PAYLOAD_SIZE) )
|
||||
throw new IllegalArgumentException("Too large payload: " + payload.getValid());
|
||||
}
|
||||
public int getPayloadSize() {
|
||||
return (_payload == null ? 0 : _payload.length);
|
||||
return (_payload == null ? 0 : _payload.getValid());
|
||||
}
|
||||
public void releasePayload() {
|
||||
//if (_payload != null)
|
||||
// _cache.release(_payload);
|
||||
_payload = null;
|
||||
}
|
||||
public ByteArray acquirePayload() {
|
||||
ByteArray old = _payload;
|
||||
_payload = new ByteArray(new byte[Packet.MAX_PAYLOAD_SIZE]); //_cache.acquire();
|
||||
//if (old != null)
|
||||
// _cache.release(old);
|
||||
return _payload;
|
||||
}
|
||||
|
||||
/** is a particular flag set on this packet? */
|
||||
@@ -340,12 +361,12 @@ public class Packet {
|
||||
|
||||
if (_payload != null) {
|
||||
try {
|
||||
System.arraycopy(_payload, 0, buffer, cur, _payload.length);
|
||||
System.arraycopy(_payload.getData(), _payload.getOffset(), buffer, cur, _payload.getValid());
|
||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||
System.err.println("payload.length: " + _payload.length + " buffer.length: " + buffer.length + " cur: " + cur);
|
||||
System.err.println("payload.length: " + _payload.getValid() + " buffer.length: " + buffer.length + " cur: " + cur);
|
||||
throw aioobe;
|
||||
}
|
||||
cur += _payload.length;
|
||||
cur += _payload.getValid();
|
||||
}
|
||||
|
||||
return cur - offset;
|
||||
@@ -382,7 +403,7 @@ public class Packet {
|
||||
size += 2; // option size
|
||||
|
||||
if (_payload != null) {
|
||||
size += _payload.length;
|
||||
size += _payload.getValid();
|
||||
}
|
||||
|
||||
return size;
|
||||
@@ -445,8 +466,10 @@ public class Packet {
|
||||
throw new IllegalArgumentException("length: " + length + " offset: " + offset + " begin: " + payloadBegin);
|
||||
|
||||
// skip ahead to the payload
|
||||
_payload = new byte[payloadSize];
|
||||
System.arraycopy(buffer, payloadBegin, _payload, 0, payloadSize);
|
||||
_payload = new ByteArray(new byte[payloadSize]); //_cache.acquire();
|
||||
System.arraycopy(buffer, payloadBegin, _payload.getData(), 0, payloadSize);
|
||||
_payload.setValid(payloadSize);
|
||||
_payload.setOffset(0);
|
||||
|
||||
// ok now lets go back and deal with the options
|
||||
if (isFlagSet(FLAG_DELAY_REQUESTED)) {
|
||||
@@ -529,6 +552,11 @@ public class Packet {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer str = formatAsString();
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
protected StringBuffer formatAsString() {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(toId(_sendStreamId));
|
||||
//buf.append("<-->");
|
||||
@@ -545,9 +573,9 @@ public class Packet {
|
||||
buf.append(" ").append(_nacks[i]);
|
||||
}
|
||||
}
|
||||
if ( (_payload != null) && (_payload.length > 0) )
|
||||
buf.append(" data: ").append(_payload.length);
|
||||
return buf.toString();
|
||||
if ( (_payload != null) && (_payload.getValid() > 0) )
|
||||
buf.append(" data: ").append(_payload.getValid());
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static final String toId(byte id[]) {
|
||||
|
@@ -106,12 +106,16 @@ public class PacketHandler {
|
||||
|
||||
private static final SimpleDateFormat _fmt = new SimpleDateFormat("HH:mm:ss.SSS");
|
||||
void displayPacket(Packet packet, String prefix, String suffix) {
|
||||
String msg = null;
|
||||
if (!_log.shouldLog(Log.DEBUG)) return;
|
||||
StringBuffer buf = new StringBuffer(256);
|
||||
synchronized (_fmt) {
|
||||
msg = _fmt.format(new Date()) + ": " + prefix + " " + packet.toString() + (suffix != null ? " " + suffix : "");
|
||||
buf.append(_fmt.format(new Date()));
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
System.out.println(msg);
|
||||
buf.append(": ").append(prefix).append(" ");
|
||||
buf.append(packet.toString());
|
||||
if (suffix != null)
|
||||
buf.append(" ").append(suffix);
|
||||
System.out.println(buf.toString());
|
||||
}
|
||||
|
||||
private void receiveKnownCon(Connection con, Packet packet) {
|
||||
@@ -137,28 +141,33 @@ public class PacketHandler {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Received forged reset for " + con, ie);
|
||||
}
|
||||
} else if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
|
||||
} else {
|
||||
if ( (con.getSendStreamId() == null) ||
|
||||
(DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) ) {
|
||||
byte oldId[] =con.getSendStreamId();
|
||||
// con fully established, w00t
|
||||
con.setSendStreamId(packet.getReceiveStreamId());
|
||||
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) // con fully established, w00t
|
||||
con.setSendStreamId(packet.getReceiveStreamId());
|
||||
|
||||
try {
|
||||
con.getPacketHandler().receivePacket(packet, con);
|
||||
} catch (I2PException ie) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Received forged syn for " + con, ie);
|
||||
_log.warn("Received forged packet for " + con + ": " + packet, ie);
|
||||
con.setSendStreamId(oldId);
|
||||
}
|
||||
} else {
|
||||
} else if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Receive a syn packet with the wrong IDs, sending reset: " + packet);
|
||||
sendReset(packet);
|
||||
packet.releasePayload();
|
||||
} else {
|
||||
if (!con.getResetSent()) {
|
||||
// someone is sending us a packet on the wrong stream
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Received a packet on the wrong stream: " + packet + " connection: " + con);
|
||||
}
|
||||
packet.releasePayload();
|
||||
}
|
||||
} else {
|
||||
// someone is sending us a packet on the wrong stream
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Received a packet on the wrong stream: " + packet + " connection: " + con);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,6 +193,7 @@ public class PacketHandler {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Echo packet received with no stream IDs: " + packet);
|
||||
}
|
||||
packet.releasePayload();
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Packet received on an unknown stream (and not an ECHO): " + packet);
|
||||
@@ -218,6 +228,7 @@ public class PacketHandler {
|
||||
+ buf.toString() + " sendId: "
|
||||
+ (sendId != null ? Base64.encode(sendId) : " unknown"));
|
||||
}
|
||||
packet.releasePayload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import java.util.Set;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
|
||||
@@ -26,6 +27,7 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
private long _ackOn;
|
||||
private long _cancelledOn;
|
||||
private SimpleTimer.TimedEvent _resendEvent;
|
||||
private ByteCache _cache = ByteCache.getInstance(128, MAX_PAYLOAD_SIZE);
|
||||
|
||||
public PacketLocal(I2PAppContext ctx, Destination to) {
|
||||
this(ctx, to, null);
|
||||
@@ -79,10 +81,11 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
_numSends++;
|
||||
_lastSend = _context.clock().now();
|
||||
}
|
||||
public void ackReceived() {
|
||||
public void ackReceived() {
|
||||
synchronized (this) {
|
||||
if (_ackOn <= 0)
|
||||
_ackOn = _context.clock().now();
|
||||
_ackOn = _context.clock().now();
|
||||
releasePayload();
|
||||
notifyAll();
|
||||
}
|
||||
SimpleTimer.getInstance().removeEvent(_resendEvent);
|
||||
@@ -90,6 +93,7 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
public void cancelled() {
|
||||
synchronized (this) {
|
||||
_cancelledOn = _context.clock().now();
|
||||
releasePayload();
|
||||
notifyAll();
|
||||
}
|
||||
SimpleTimer.getInstance().removeEvent(_resendEvent);
|
||||
@@ -110,16 +114,44 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
|
||||
public void setResendPacketEvent(SimpleTimer.TimedEvent evt) { _resendEvent = evt; }
|
||||
|
||||
public String toString() {
|
||||
String str = super.toString();
|
||||
public StringBuffer formatAsString() {
|
||||
StringBuffer buf = super.formatAsString();
|
||||
|
||||
Connection con = _connection;
|
||||
if (con != null)
|
||||
buf.append(" rtt ").append(con.getOptions().getRTT());
|
||||
|
||||
if ( (_tagsSent != null) && (_tagsSent.size() > 0) )
|
||||
str = str + " with tags";
|
||||
buf.append(" with tags");
|
||||
|
||||
if (_ackOn > 0)
|
||||
return str + " ack after " + getAckTime() + (_numSends <= 1 ? "" : " sent " + _numSends + " times");
|
||||
else
|
||||
return str + (_numSends <= 1 ? "" : " sent " + _numSends + " times");
|
||||
buf.append(" ack after ").append(getAckTime());
|
||||
|
||||
if (_numSends > 1)
|
||||
buf.append(" sent ").append(_numSends).append(" times");
|
||||
|
||||
if (isFlagSet(Packet.FLAG_SYNCHRONIZE) ||
|
||||
isFlagSet(Packet.FLAG_CLOSE) ||
|
||||
isFlagSet(Packet.FLAG_RESET)) {
|
||||
|
||||
if (con != null) {
|
||||
buf.append(" from ");
|
||||
Destination local = con.getSession().getMyDestination();
|
||||
if (local != null)
|
||||
buf.append(local.calculateHash().toBase64().substring(0,4));
|
||||
else
|
||||
buf.append("unknown");
|
||||
|
||||
buf.append(" to ");
|
||||
Destination remote = con.getRemotePeer();
|
||||
if (remote != null)
|
||||
buf.append(remote.calculateHash().toBase64().substring(0,4));
|
||||
else
|
||||
buf.append("unknown");
|
||||
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
public void waitForAccept(int maxWaitMs) {
|
||||
@@ -131,10 +163,12 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
int window = _connection.getOptions().getWindowSize();
|
||||
boolean accepted = _connection.packetSendChoke(maxWaitMs);
|
||||
long after = _context.clock().now();
|
||||
if (accepted)
|
||||
if (accepted) {
|
||||
_acceptedOn = after;
|
||||
else
|
||||
} else {
|
||||
_acceptedOn = -1;
|
||||
releasePayload();
|
||||
}
|
||||
int afterQueued = _connection.getUnackedPacketsSent();
|
||||
if ( (after - before > 1000) && (_log.shouldLog(Log.DEBUG)) )
|
||||
_log.debug("Took " + (after-before) + "ms to get "
|
||||
@@ -149,11 +183,12 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
long expiration = _context.clock().now()+maxWaitMs;
|
||||
while (true) {
|
||||
long timeRemaining = expiration - _context.clock().now();
|
||||
if ( (timeRemaining <= 0) && (maxWaitMs > 0) ) return;
|
||||
if ( (timeRemaining <= 0) && (maxWaitMs > 0) ) break;
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (_ackOn > 0) return;
|
||||
if (_cancelledOn > 0) return;
|
||||
if (_ackOn > 0) break;
|
||||
if (_cancelledOn > 0) break;
|
||||
if (!_connection.getIsConnected()) break;
|
||||
if (timeRemaining > 60*1000)
|
||||
timeRemaining = 60*1000;
|
||||
else if (timeRemaining <= 0)
|
||||
@@ -162,6 +197,8 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
if (!writeSuccessful())
|
||||
releasePayload();
|
||||
}
|
||||
|
||||
public boolean writeAccepted() { return _acceptedOn > 0 && _cancelledOn <= 0; }
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
@@ -49,12 +48,16 @@ class PacketQueue {
|
||||
tagsSent = new HashSet(0);
|
||||
|
||||
// cache this from before sendMessage
|
||||
String conStr = (packet.getConnection() != null ? packet.getConnection().toString() : "");
|
||||
String conStr = null;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
conStr = (packet.getConnection() != null ? packet.getConnection().toString() : "");
|
||||
if (packet.getAckTime() > 0) {
|
||||
_log.debug("Not resending " + packet);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Not resending " + packet);
|
||||
return;
|
||||
} else {
|
||||
_log.debug("Sending... " + packet);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sending... " + packet);
|
||||
}
|
||||
|
||||
ByteArray ba = _cache.acquire();
|
||||
@@ -125,6 +128,17 @@ class PacketQueue {
|
||||
String suffix = (c != null ? "wsize " + c.getOptions().getWindowSize() : null);
|
||||
_connectionManager.getPacketHandler().displayPacket(packet, "SEND", suffix);
|
||||
}
|
||||
|
||||
if ( (packet.getSequenceNum() == 0) && (!packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) ) {
|
||||
// ack only, so release it asap
|
||||
packet.releasePayload();
|
||||
} else if (packet.isFlagSet(Packet.FLAG_ECHO) && !packet.isFlagSet(Packet.FLAG_SIGNATURE_INCLUDED) ) {
|
||||
// pong
|
||||
packet.releasePayload();
|
||||
} else if (packet.isFlagSet(Packet.FLAG_RESET)) {
|
||||
// reset
|
||||
packet.releasePayload();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ class SchedulerConnectedBulk extends SchedulerImpl {
|
||||
|
||||
public boolean accept(Connection con) {
|
||||
boolean ok = (con != null) &&
|
||||
(con.getAckedPackets() > 0) &&
|
||||
(con.getHighestAckedThrough() >= 0) &&
|
||||
(con.getOptions().getProfile() == ConnectionOptions.PROFILE_BULK) &&
|
||||
(!con.getResetReceived()) &&
|
||||
( (con.getCloseSentOn() <= 0) || (con.getCloseReceivedOn() <= 0) );
|
||||
|
@@ -39,7 +39,7 @@ class SchedulerConnecting extends SchedulerImpl {
|
||||
boolean notYetConnected = (con.getIsConnected()) &&
|
||||
//(con.getSendStreamId() == null) && // not null on recv
|
||||
(con.getLastSendId() >= 0) &&
|
||||
(con.getAckedPackets() <= 0) &&
|
||||
(con.getHighestAckedThrough() < 0) &&
|
||||
(!con.getResetReceived());
|
||||
return notYetConnected;
|
||||
}
|
||||
|
@@ -32,19 +32,13 @@ class SchedulerDead extends SchedulerImpl {
|
||||
|
||||
public boolean accept(Connection con) {
|
||||
if (con == null) return false;
|
||||
long timeSinceClose = _context.clock().now() - con.getCloseSentOn();
|
||||
if (con.getResetSent())
|
||||
timeSinceClose = _context.clock().now() - con.getResetSentOn();
|
||||
boolean nothingLeftToDo = (con.getCloseSentOn() > 0) &&
|
||||
(con.getCloseReceivedOn() > 0) &&
|
||||
(con.getUnackedPacketsReceived() <= 0) &&
|
||||
(con.getUnackedPacketsSent() <= 0) &&
|
||||
(con.getResetSent()) &&
|
||||
long timeSinceClose = _context.clock().now() - con.getDisconnectScheduledOn();
|
||||
boolean nothingLeftToDo = (con.getDisconnectScheduledOn() > 0) &&
|
||||
(timeSinceClose >= Connection.DISCONNECT_TIMEOUT);
|
||||
boolean timedOut = (con.getOptions().getConnectTimeout() < con.getLifetime()) &&
|
||||
con.getSendStreamId() == null &&
|
||||
con.getLifetime() >= Connection.DISCONNECT_TIMEOUT;
|
||||
return con.getResetReceived() || nothingLeftToDo || timedOut;
|
||||
return nothingLeftToDo || timedOut;
|
||||
}
|
||||
|
||||
public void eventOccurred(Connection con) {
|
||||
|
@@ -38,7 +38,7 @@ class SchedulerHardDisconnected extends SchedulerImpl {
|
||||
timeSinceClose = _context.clock().now() - con.getResetSentOn();
|
||||
boolean ok = (con.getHardDisconnected() || con.getResetSent()) &&
|
||||
(timeSinceClose < Connection.DISCONNECT_TIMEOUT);
|
||||
return ok;
|
||||
return ok || con.getResetReceived();
|
||||
}
|
||||
|
||||
public void eventOccurred(Connection con) {
|
||||
|
@@ -6,6 +6,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -29,7 +30,7 @@ public class MessageInputStreamTest {
|
||||
for (int i = 0; i < orig.length / 1024; i++) {
|
||||
byte msg[] = new byte[1024];
|
||||
System.arraycopy(orig, i*1024, msg, 0, 1024);
|
||||
in.messageReceived(i, msg);
|
||||
in.messageReceived(i, new ByteArray(msg));
|
||||
}
|
||||
|
||||
byte read[] = new byte[orig.length];
|
||||
@@ -59,7 +60,7 @@ public class MessageInputStreamTest {
|
||||
byte msg[] = new byte[1024];
|
||||
Integer cur = (Integer)order.get(i);
|
||||
System.arraycopy(orig, cur.intValue()*1024, msg, 0, 1024);
|
||||
in.messageReceived(cur.intValue(), msg);
|
||||
in.messageReceived(cur.intValue(), new ByteArray(msg));
|
||||
_log.debug("Injecting " + cur);
|
||||
}
|
||||
|
||||
@@ -91,7 +92,7 @@ public class MessageInputStreamTest {
|
||||
byte msg[] = new byte[1024];
|
||||
Integer cur = (Integer)order.get(i);
|
||||
System.arraycopy(orig, cur.intValue()*1024, msg, 0, 1024);
|
||||
in.messageReceived(cur.intValue(), msg);
|
||||
in.messageReceived(cur.intValue(), new ByteArray(msg));
|
||||
_log.debug("Injecting " + cur);
|
||||
}
|
||||
}
|
||||
@@ -126,7 +127,7 @@ public class MessageInputStreamTest {
|
||||
byte msg[] = new byte[1024];
|
||||
Integer cur = (Integer)order.get(i);
|
||||
System.arraycopy(orig, cur.intValue()*1024, msg, 0, 1024);
|
||||
in.messageReceived(cur.intValue(), msg);
|
||||
in.messageReceived(cur.intValue(), new ByteArray(msg));
|
||||
_log.debug("Injecting " + cur);
|
||||
|
||||
try {
|
||||
|
@@ -34,8 +34,10 @@
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete>
|
||||
<fileset dir="src/WEB-INF/classes/" includes="**/*.class, susimail.war" />
|
||||
<fileset dir="src/WEB-INF/classes/" includes="**/*.class" />
|
||||
</delete>
|
||||
<delete dir="src/WEB-INF/classes/i2p"/>
|
||||
<delete file="susimail.war"/>
|
||||
</target>
|
||||
<target name="cleandep" depends="clean" />
|
||||
<target name="distclean" depends="clean" />
|
||||
|
96
apps/susimail/src/css.css
Normal file
96
apps/susimail/src/css.css
Normal file
@@ -0,0 +1,96 @@
|
||||
body {
|
||||
background-color:white;
|
||||
}
|
||||
|
||||
li {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
line-height:12pt;
|
||||
font-size:10pt;
|
||||
margin-left:5mm;
|
||||
margin-right:5mm;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
line-height:12pt;
|
||||
margin-left:5mm;
|
||||
margin-right:5mm;
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
p.hl {
|
||||
font-size:12pt;
|
||||
letter-spacing:2pt;
|
||||
line-height:18pt;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
p.text {
|
||||
margin-left:10mm;
|
||||
margin-right:10mm;
|
||||
}
|
||||
|
||||
p.error {
|
||||
color:#ff0000;
|
||||
}
|
||||
|
||||
p.info {
|
||||
color:#327BBF;
|
||||
}
|
||||
|
||||
span.coloured {
|
||||
color:#327BBF;
|
||||
}
|
||||
|
||||
p.footer {
|
||||
margin-left:10mm;
|
||||
margin-right:10mm;
|
||||
font-size:8pt;
|
||||
line-height:10pt;
|
||||
}
|
||||
|
||||
p.mailbody {
|
||||
font-family:Courier-Fixed;
|
||||
margin-left:1cm;
|
||||
margin-right:1cm;
|
||||
}
|
||||
|
||||
a {
|
||||
color:#327BBF;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
td {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
line-height:12pt;
|
||||
margin-left:5mm;
|
||||
margin-right:5mm;
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
tr.list0 {
|
||||
background-color:#e0e0e0;
|
||||
}
|
||||
|
||||
tr.list1 {
|
||||
background-color:#ffffff;
|
||||
}
|
||||
|
||||
table.noborder {
|
||||
margin-left:0mm;
|
||||
margin-top:0mm;
|
||||
margin-right:0mm;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family:Courier-Fixed;
|
||||
margin-left:1cm;
|
||||
margin-right:1cm;
|
||||
}
|
@@ -19,11 +19,10 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.5 $
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
package i2p.susi.webmail;
|
||||
|
||||
import i2p.susi.debug.Debug;
|
||||
import i2p.susi.util.Config;
|
||||
import i2p.susi.util.ReadBuffer;
|
||||
import i2p.susi.webmail.encoding.Encoding;
|
||||
|
@@ -19,13 +19,12 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
package i2p.susi.webmail;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import i2p.susi.debug.Debug;
|
||||
import i2p.susi.webmail.pop3.POP3MailBox;
|
||||
|
||||
/**
|
||||
|
@@ -10,8 +10,6 @@
|
||||
package net.i2p.apps.systray;
|
||||
|
||||
import java.awt.Frame;
|
||||
import java.io.File;
|
||||
|
||||
import snoozesoft.systray4j.SysTrayMenu;
|
||||
import snoozesoft.systray4j.SysTrayMenuEvent;
|
||||
import snoozesoft.systray4j.SysTrayMenuIcon;
|
||||
|
@@ -193,6 +193,7 @@
|
||||
<copy file="installer/resources/osid" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/postinstall.bat" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/postinstall.sh" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/startRouter.sh" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/systray.config" todir="pkg-temp/" />
|
||||
<!-- <copy file="installer/resources/uninstall_i2p_service_unix" todir="pkg-temp/" /> -->
|
||||
<copy file="installer/resources/uninstall_i2p_service_winnt.bat" todir="pkg-temp/" />
|
||||
@@ -221,6 +222,7 @@
|
||||
<copy file="core/perl/i2ptest.sh" todir="pkg-temp/scripts/" />
|
||||
<mkdir dir="pkg-temp/docs" />
|
||||
<copy file="readme.html" todir="pkg-temp/docs/" />
|
||||
<copy file="initialNews.xml" tofile="pkg-temp/docs/news.xml" />
|
||||
<copy file="installer/resources/startconsole.html" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/start.ico" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/console.ico" todir="pkg-temp/docs/" />
|
||||
@@ -250,21 +252,27 @@
|
||||
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
|
||||
|
||||
<!-- for the i2p 0.5 release, push jetty 5.2.1 -->
|
||||
<!--
|
||||
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/commons-logging.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/commons-el.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/javax.servlet.jar" todir="pkg-temp/lib/" />
|
||||
-->
|
||||
<!-- requires commons-* to be added to the classpath (boo, hiss) -->
|
||||
<!--
|
||||
<copy file="installer/resources/wrapper.config" todir="pkg-temp/" />
|
||||
<touch file="pkg-temp/wrapper.config.updated" />
|
||||
-->
|
||||
|
||||
<copy file="build/i2ptunnel.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/routerconsole.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/addressbook.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/susimail.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="history.txt" todir="pkg-temp/" />
|
||||
<mkdir dir="pkg-temp/docs/" />
|
||||
<copy file="news.xml" todir="pkg-temp/docs/" />
|
||||
<!-- the addressbook handles this for updates -->
|
||||
<!-- <copy file="hosts.txt" todir="pkg-temp/" /> -->
|
||||
<mkdir dir="pkg-temp/eepsite" />
|
||||
|
@@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
public final static String ID = "$Revision: 1.27 $ $Date: 2005/02/16 17:23:50 $";
|
||||
public final static String VERSION = "0.5";
|
||||
public final static String ID = "$Revision: 1.33 $ $Date: 2005/03/29 19:07:37 $";
|
||||
public final static String VERSION = "0.5.0.6";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
@@ -91,7 +91,6 @@ public class I2PAppContext {
|
||||
public static I2PAppContext getGlobalContext() {
|
||||
synchronized (I2PAppContext.class) {
|
||||
if (_globalAppContext == null) {
|
||||
System.err.println("*** Building a seperate global context!");
|
||||
_globalAppContext = new I2PAppContext(false, null);
|
||||
}
|
||||
}
|
||||
|
@@ -30,7 +30,6 @@ import net.i2p.data.i2cp.ReportAbuseMessage;
|
||||
import net.i2p.data.i2cp.SendMessageMessage;
|
||||
import net.i2p.data.i2cp.SessionConfig;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
/**
|
||||
* Produce the various messages the session needs to send to the router.
|
||||
@@ -53,13 +52,17 @@ class I2CPMessageProducer {
|
||||
CreateSessionMessage msg = new CreateSessionMessage();
|
||||
SessionConfig cfg = new SessionConfig(session.getMyDestination());
|
||||
cfg.setOptions(session.getOptions());
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("config created");
|
||||
try {
|
||||
cfg.signSessionConfig(session.getPrivateKey());
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2PSessionException("Unable to sign the session config", dfe);
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("config signed");
|
||||
msg.setSessionConfig(cfg);
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("config loaded into message");
|
||||
session.sendMessage(msg);
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("config message sent");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -39,6 +39,7 @@ import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||
import net.i2p.data.i2cp.SessionId;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
|
||||
/**
|
||||
* Implementation of an I2P session running over TCP. This class is NOT thread safe -
|
||||
@@ -78,7 +79,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
/** class that generates new messages */
|
||||
protected I2CPMessageProducer _producer;
|
||||
/** map of integer --> MessagePayloadMessage */
|
||||
Map _availableMessages;
|
||||
private Map _availableMessages;
|
||||
|
||||
protected I2PClientMessageHandlerMap _handlerMap;
|
||||
|
||||
@@ -225,6 +226,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
*/
|
||||
public void connect() throws I2PSessionException {
|
||||
_closed = false;
|
||||
_availabilityNotifier.stopNotifying();
|
||||
I2PThread notifier = new I2PThread(_availabilityNotifier);
|
||||
notifier.setName("Notifier " + _myDestination.calculateHash().toBase64().substring(0,4));
|
||||
notifier.setDaemon(true);
|
||||
@@ -289,7 +291,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
*
|
||||
*/
|
||||
public byte[] receiveMessage(int msgId) throws I2PSessionException {
|
||||
MessagePayloadMessage msg = (MessagePayloadMessage) _availableMessages.remove(new Integer(msgId));
|
||||
MessagePayloadMessage msg = null;
|
||||
synchronized (_availableMessages) {
|
||||
msg = (MessagePayloadMessage) _availableMessages.remove(new Integer(msgId));
|
||||
}
|
||||
if (msg == null) return null;
|
||||
return msg.getPayload().getUnencryptedData();
|
||||
}
|
||||
@@ -338,12 +343,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
* Recieve a payload message and let the app know its available
|
||||
*/
|
||||
public void addNewMessage(MessagePayloadMessage msg) {
|
||||
_availableMessages.put(new Integer(msg.getMessageId().getMessageId()), msg);
|
||||
synchronized (_availableMessages) {
|
||||
_availableMessages.put(new Integer(msg.getMessageId().getMessageId()), msg);
|
||||
}
|
||||
int id = msg.getMessageId().getMessageId();
|
||||
byte data[] = msg.getPayload().getUnencryptedData();
|
||||
if ((data == null) || (data.length <= 0)) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error(getPrefix() + "addNewMessage of a message with no unencrypted data",
|
||||
if (_log.shouldLog(Log.CRIT))
|
||||
_log.log(Log.CRIT, getPrefix() + "addNewMessage of a message with no unencrypted data",
|
||||
new Exception("Empty message"));
|
||||
} else {
|
||||
int size = data.length;
|
||||
@@ -351,6 +358,20 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix() + "Notified availability for session " + _sessionId + ", message " + id);
|
||||
}
|
||||
SimpleTimer.getInstance().addEvent(new VerifyUsage(id), 30*1000);
|
||||
}
|
||||
private class VerifyUsage implements SimpleTimer.TimedEvent {
|
||||
private int _msgId;
|
||||
public VerifyUsage(int id) { _msgId = id; }
|
||||
public void timeReached() {
|
||||
MessagePayloadMessage removed = null;
|
||||
synchronized (_availableMessages) {
|
||||
removed = (MessagePayloadMessage)_availableMessages.remove(new Integer(_msgId));
|
||||
}
|
||||
if (removed != null)
|
||||
_log.log(Log.CRIT, "Message NOT removed! id=" + _msgId + ": " + removed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AvailabilityNotifier implements Runnable {
|
||||
@@ -401,6 +422,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
} catch (Exception e) {
|
||||
_log.log(Log.CRIT, "Error notifying app of message availability", e);
|
||||
}
|
||||
} else {
|
||||
_log.log(Log.CRIT, "Unable to notify an app that " + msgId + " of size " + size + " is available!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,12 +504,15 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
|
||||
long beforeSync = _context.clock().now();
|
||||
long inSync = 0;
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync to write");
|
||||
try {
|
||||
synchronized (_out) {
|
||||
inSync = _context.clock().now();
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("before writeMessage");
|
||||
message.writeMessage(_out);
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("after writeMessage");
|
||||
_out.flush();
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("after flush");
|
||||
}
|
||||
} catch (I2CPMessageException ime) {
|
||||
throw new I2PSessionException(getPrefix() + "Error writing out the message", ime);
|
||||
@@ -504,7 +530,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
* Pass off the error to the listener
|
||||
*/
|
||||
void propogateError(String msg, Throwable error) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error(getPrefix() + "Error occurred: " + msg, error);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error(getPrefix() + "Error occurred: " + msg + " - " + error.getMessage());
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + " cause", error);
|
||||
|
||||
if (_sessionListener != null) _sessionListener.errorOccurred(this, msg, error);
|
||||
}
|
||||
|
||||
|
@@ -73,10 +73,11 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
}
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent)
|
||||
throws I2PSessionException {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("sending message");
|
||||
if (isClosed()) throw new I2PSessionException("Already closed");
|
||||
if (SHOULD_COMPRESS) payload = DataHelper.compress(payload, offset, size);
|
||||
else throw new IllegalStateException("we need to update sendGuaranteed to support partial send");
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("message compressed");
|
||||
// we always send as guaranteed (so we get the session keys/tags acked),
|
||||
// but only block until the appropriate event has been reached (guaranteed
|
||||
// success or accepted). we may want to break this out into a seperate
|
||||
@@ -111,10 +112,12 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent)
|
||||
throws I2PSessionException {
|
||||
long begin = _context.clock().now();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("begin sendBestEffort");
|
||||
SessionKey key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey());
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("key fetched");
|
||||
if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey());
|
||||
SessionTag tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key);
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("tag consumed");
|
||||
Set sentTags = null;
|
||||
int oldTags = _context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key);
|
||||
long availTimeLeft = _context.sessionKeyManager().getAvailableTimeLeft(dest.getPublicKey(), key);
|
||||
@@ -151,7 +154,10 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
sentTags.addAll(tagsSent);
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("before creating nonce");
|
||||
|
||||
long nonce = _context.random().nextInt(Integer.MAX_VALUE);
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync state");
|
||||
MessageState state = new MessageState(nonce, getPrefix());
|
||||
state.setKey(key);
|
||||
state.setTags(sentTags);
|
||||
@@ -171,6 +177,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
}
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync state");
|
||||
long beforeSendingSync = _context.clock().now();
|
||||
long inSendingSync = 0;
|
||||
synchronized (_sendingStates) {
|
||||
|
@@ -57,8 +57,8 @@ class MessagePayloadMessageHandler extends HandlerImpl {
|
||||
Payload payload = msg.getPayload();
|
||||
byte[] data = _context.elGamalAESEngine().decrypt(payload.getEncryptedData(), session.getDecryptionKey());
|
||||
if (data == null) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error decrypting the payload");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error decrypting the payload");
|
||||
throw new DataFormatException("Unable to decrypt the payload");
|
||||
}
|
||||
payload.setUnencryptedData(data);
|
||||
|
@@ -1,9 +1,7 @@
|
||||
package net.i2p.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
|
@@ -41,7 +41,8 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
}
|
||||
|
||||
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
|
||||
_log.debug("Handle message " + message);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
RequestLeaseSetMessage msg = (RequestLeaseSetMessage) message;
|
||||
LeaseSet leaseSet = new LeaseSet();
|
||||
for (int i = 0; i < msg.getEndpoints(); i++) {
|
||||
|
@@ -8,8 +8,6 @@
|
||||
package net.i2p.client.naming;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
@@ -9,10 +9,7 @@ package net.i2p.crypto;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.SessionKey;
|
||||
@@ -43,6 +40,19 @@ public class AESEngine {
|
||||
* @param length how much data to encrypt
|
||||
*/
|
||||
public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) {
|
||||
encrypt(payload, payloadIndex, out, outIndex, sessionKey, iv, 0, length);
|
||||
}
|
||||
|
||||
/** Encrypt the payload with the session key
|
||||
* @param payload data to be encrypted
|
||||
* @param payloadIndex index into the payload to start encrypting
|
||||
* @param out where to store the result
|
||||
* @param outIndex where in out to start writing
|
||||
* @param sessionKey private esession key to encrypt to
|
||||
* @param iv IV for CBC
|
||||
* @param length how much data to encrypt
|
||||
*/
|
||||
public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int ivOffset, int length) {
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
_log.warn("Warning: AES is disabled");
|
||||
}
|
||||
@@ -123,6 +133,19 @@ public class AESEngine {
|
||||
* @param length how much data to decrypt
|
||||
*/
|
||||
public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) {
|
||||
decrypt(payload, payloadIndex, out, outIndex, sessionKey, iv, 0, length);
|
||||
}
|
||||
|
||||
/** Decrypt the data with the session key
|
||||
* @param payload data to be decrypted
|
||||
* @param payloadIndex index into the payload to start decrypting
|
||||
* @param out where to store the cleartext
|
||||
* @param outIndex where in out to start writing
|
||||
* @param sessionKey private session key to decrypt to
|
||||
* @param iv IV for CBC
|
||||
* @param length how much data to decrypt
|
||||
*/
|
||||
public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int ivOffset, int length) {
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
_log.warn("Warning: AES is disabled");
|
||||
}
|
||||
|
@@ -14,9 +14,6 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user