forked from I2P_Developers/i2p.i2p
Compare commits
76 Commits
i2p_0_4_0_
...
i2p_0_4_1_
Author | SHA1 | Date | |
---|---|---|---|
![]() |
503b289240 | ||
![]() |
35e3bbb862 | ||
![]() |
8dc261da79 | ||
![]() |
65676f8988 | ||
![]() |
730da3aa27 | ||
![]() |
ff8674bca9 | ||
![]() |
c7cfef3b61 | ||
![]() |
32188b1cc0 | ||
![]() |
37479d8c0d | ||
![]() |
f5c7d6576d | ||
![]() |
38c422bbc0 | ||
![]() |
39d4e5ea81 | ||
![]() |
4191ad1cbf | ||
![]() |
29287da37c | ||
![]() |
98c780415b | ||
![]() |
756af9c699 | ||
![]() |
7f9076bb1d | ||
![]() |
2404f1ab9a | ||
![]() |
64bcfd09ec | ||
![]() |
6251d22c6e | ||
![]() |
de1b4937a1 | ||
![]() |
d092dd79ba | ||
![]() |
a3ba968386 | ||
![]() |
5ca2b97128 | ||
![]() |
c9daad1cfd | ||
![]() |
0526d5b53a | ||
![]() |
34163fb8e4 | ||
![]() |
98d2d661a8 | ||
![]() |
d9f0a0fd74 | ||
![]() |
d20d043e0f | ||
![]() |
ce186e1872 | ||
![]() |
a14da92e1d | ||
![]() |
2b54d850ea | ||
![]() |
a63c1b19fc | ||
![]() |
34f74cd6ef | ||
![]() |
c0b8e62135 | ||
![]() |
ea24166b8e | ||
![]() |
178b229d66 | ||
![]() |
276493da65 | ||
![]() |
e85dadfef2 | ||
![]() |
1c70efb350 | ||
![]() |
6804a0c564 | ||
![]() |
6eb7ecc2d4 | ||
![]() |
f4956b06b6 | ||
![]() |
9a2f7c2660 | ||
![]() |
b6017c558a | ||
![]() |
62ed6c6a58 | ||
![]() |
24966c812f | ||
![]() |
ea8dc2e0af | ||
![]() |
010b285e67 | ||
![]() |
774231f347 | ||
![]() |
ff1dfd8f25 | ||
![]() |
2741ac195d | ||
![]() |
cf780e296e | ||
![]() |
0361246db0 | ||
![]() |
63355ecd5b | ||
![]() |
0f54ba59fb | ||
![]() |
b67b243ebd | ||
![]() |
4c29c20613 | ||
![]() |
4c2619d948 | ||
![]() |
ea5662a4a2 | ||
![]() |
7c1ce777a1 | ||
![]() |
3bb85f2d61 | ||
![]() |
93e36b3113 | ||
![]() |
932fb670e3 | ||
![]() |
54dce61a95 | ||
![]() |
e686c0e0a2 | ||
![]() |
05acf32f39 | ||
![]() |
67064012c9 | ||
![]() |
10e93c3b1b | ||
![]() |
5b2ec1cbb5 | ||
![]() |
972f701c5c | ||
![]() |
51285efbc3 | ||
![]() |
e2635705f9 | ||
![]() |
7762107543 | ||
![]() |
9123ad89c8 |
@@ -199,10 +199,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
host = getHostName(destination);
|
||||
if ( (host != null) && ("i2p".equals(host)) ) {
|
||||
int pos2;
|
||||
if ((pos2 = line.indexOf("?")) != -1) {
|
||||
if ((pos2 = request.indexOf("?")) != -1) {
|
||||
// Try to find an address helper in the fragments
|
||||
String fragments = line.substring(pos2 + 1);
|
||||
// and split the request into it's component parts for rebuilding later
|
||||
String fragments = request.substring(pos2 + 1);
|
||||
String uriPath = request.substring(0, pos2);
|
||||
pos2 = fragments.indexOf(" ");
|
||||
String protocolVersion = fragments.substring(pos2 + 1);
|
||||
String urlEncoding = "";
|
||||
fragments = fragments.substring(0, pos2);
|
||||
fragments = fragments + "&";
|
||||
String fragment;
|
||||
@@ -215,8 +219,17 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
if (pos2 >= 0) {
|
||||
addressHelpers.put(destination,fragment.substring(pos2 + 1));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// append each fragment unless it's the address helper
|
||||
if ("".equals(urlEncoding)) {
|
||||
urlEncoding = "?" + fragment;
|
||||
} else {
|
||||
urlEncoding = urlEncoding + "&" + fragment;
|
||||
}
|
||||
}
|
||||
}
|
||||
// reconstruct the request minus the i2paddresshelper GET var
|
||||
request = uriPath + urlEncoding + " " + protocolVersion;
|
||||
}
|
||||
|
||||
String addressHelper = (String) addressHelpers.get(destination);
|
||||
|
@@ -148,6 +148,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
I2PServerSocket i2pss = sockMgr.getServerSocket();
|
||||
while (true) {
|
||||
I2PSocket i2ps = i2pss.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
I2PThread t = new I2PThread(new Handler(i2ps));
|
||||
t.start();
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@@ -375,10 +376,16 @@ public class TunnelController implements Logging {
|
||||
buf.append("Full destination: ");
|
||||
buf.append("<input type=\"text\" size=\"10\" onclick=\"this.select();\" ");
|
||||
buf.append("value=\"").append(dest.toBase64()).append("\" />\n");
|
||||
long val = new Random().nextLong();
|
||||
if (val < 0) val = 0 - val;
|
||||
buf.append("<br />You can <a href=\"http://temp").append(val);
|
||||
buf.append(".i2p/?i2paddresshelper=").append(dest.toBase64()).append("\">view</a>");
|
||||
buf.append(" it in a browser (only when you're using the eepProxy)\n");
|
||||
buf.append("<br />If you are going to share this on IRC, you need to split it up:<br />\n");
|
||||
String str = dest.toBase64();
|
||||
buf.append(str.substring(0, str.length()/2)).append("<br />\n");
|
||||
buf.append(str.substring(str.length()/2)).append("<br />\n");
|
||||
buf.append("You can also post it to <a href=\"http://forum.i2p/viewforum.php?f=16\">Eepsite announcement forum</a><br />");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import java.util.Random;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Uuuugly... generate the edit/add forms for the various
|
||||
* Uuuugly code to generate the edit/add forms for the various
|
||||
* I2PTunnel types (httpclient/client/server)
|
||||
*
|
||||
*/
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
<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" />
|
||||
|
@@ -234,7 +234,7 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the socket from the I2P side, e. g. by a close packet.
|
||||
* Close the socket from the I2P side (by a close packet)
|
||||
*/
|
||||
protected void internalClose() {
|
||||
synchronized (flagLock) {
|
||||
|
@@ -118,7 +118,7 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
return;
|
||||
}
|
||||
if (msg.length < 4) {
|
||||
_log.error(getName() + ": ==== packet too short ====");
|
||||
_log.warn(getName() + ": ==== packet too short ====");
|
||||
return;
|
||||
}
|
||||
int type = msg[0] & 0xff;
|
||||
@@ -155,7 +155,7 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
return;
|
||||
}
|
||||
} catch (I2PException ise) {
|
||||
_log.error(getName() + ": Error processing", ise);
|
||||
_log.warn(getName() + ": Error processing", ise);
|
||||
} catch (IllegalStateException ise) {
|
||||
_log.debug(getName() + ": Error processing", ise);
|
||||
}
|
||||
@@ -176,7 +176,7 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
}
|
||||
|
||||
if (s == null) {
|
||||
_log.warn(getName() + ": No socket responsible for ACK packet");
|
||||
_log.warn(getName() + ": No socket responsible for ACK packet for id " + getReadableForm(id));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -223,7 +223,8 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
s = (I2PSocketImpl) _outSockets.get(id);
|
||||
}
|
||||
|
||||
_log.debug(getName() + ": *Disconnect outgoing for socket " + s);
|
||||
_log.debug(getName() + ": *Disconnect outgoing for socket " + s + " on id "
|
||||
+ getReadableForm(id));
|
||||
try {
|
||||
if (s != null) {
|
||||
if (payload.length > 0) {
|
||||
@@ -241,7 +242,7 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
}
|
||||
return;
|
||||
} catch (Exception t) {
|
||||
_log.error(getName() + ": Ignoring error on disconnect for socket " + s, t);
|
||||
_log.warn(getName() + ": Ignoring error on disconnect for socket " + s, t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +260,8 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
|
||||
// packet send outgoing
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getName() + ": *Packet send outgoing [" + payload.length + "] for socket " + s);
|
||||
_log.debug(getName() + ": *Packet send outgoing [" + payload.length + "] for socket "
|
||||
+ s + " on id " + getReadableForm(id));
|
||||
if (s != null) {
|
||||
s.queueData(payload);
|
||||
return;
|
||||
@@ -293,7 +295,8 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
s.setRemoteID(id);
|
||||
}
|
||||
}
|
||||
_log.debug(getName() + ": *Syn! for socket " + s);
|
||||
_log.debug(getName() + ": *Syn! for socket " + s + " on id " + getReadableForm(newLocalID)
|
||||
+ " from " + d.calculateHash().toBase64().substring(0,6));
|
||||
|
||||
if (!acceptConnections) {
|
||||
// The app did not instantiate an I2PServerSocket
|
||||
@@ -303,7 +306,7 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
replySentOk = _session.sendMessage(d, packet);
|
||||
}
|
||||
if (!replySentOk) {
|
||||
_log.error(getName() + ": Error sending close to " + d.calculateHash().toBase64()
|
||||
_log.warn(getName() + ": Error sending close to " + d.calculateHash().toBase64()
|
||||
+ " in response to a new con message",
|
||||
new Exception("Failed creation"));
|
||||
}
|
||||
@@ -360,13 +363,13 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
return;
|
||||
} else {
|
||||
if ( (payload.length > 0) && (_log.shouldLog(Log.ERROR)) )
|
||||
_log.error(getName() + ": Disconnect packet had " + payload.length + " bytes");
|
||||
_log.warn(getName() + ": Disconnect packet had " + payload.length + " bytes");
|
||||
if (s != null)
|
||||
s.internalClose();
|
||||
return;
|
||||
}
|
||||
} catch (Exception t) {
|
||||
_log.error(getName() + ": Ignoring error on disconnect", t);
|
||||
_log.warn(getName() + ": Ignoring error on disconnect", t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -454,6 +457,10 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
s = new I2PSocketImpl(peer, this, true, localID);
|
||||
_outSockets.put(localID, s);
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getName() + ": connect(" + peer.calculateHash().toBase64().substring(0,6)
|
||||
+ ", ...): localID = " + lcID);
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream pubkey = new ByteArrayOutputStream();
|
||||
_session.getMyDestination().writeBytes(pubkey);
|
||||
@@ -462,18 +469,30 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
boolean sent = false;
|
||||
sent = _session.sendMessage(peer, packet);
|
||||
if (!sent) {
|
||||
_log.info(getName() + ": Unable to send & receive ack for SYN packet for socket " + s);
|
||||
_log.info(getName() + ": Unable to send & receive ack for SYN packet for socket "
|
||||
+ s + " with localID = " + lcID);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
_context.statManager().addRateData("streaming.synNoAck", 1, 1);
|
||||
throw new I2PException("Error sending through I2P network");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getName() + ": syn sent ok to "
|
||||
+ peer.calculateHash().toBase64().substring(0,6)
|
||||
+ " with localID = " + lcID);
|
||||
}
|
||||
if (options != null)
|
||||
remoteID = s.getRemoteID(true, options.getConnectTimeout());
|
||||
else
|
||||
remoteID = s.getRemoteID(true, getDefaultOptions().getConnectTimeout());
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getName() + ": remoteID received from "
|
||||
+ peer.calculateHash().toBase64().substring(0,6)
|
||||
+ ": " + getReadableForm(remoteID)
|
||||
+ " with localID = " + lcID);
|
||||
|
||||
if (remoteID == null) {
|
||||
_context.statManager().addRateData("streaming.nackReceived", 1, 1);
|
||||
throw new ConnectException("Connection refused by peer for socket " + s);
|
||||
@@ -488,9 +507,10 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
|
||||
return s;
|
||||
} catch (InterruptedIOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error(getName() + ": Timeout waiting for ack from syn for id "
|
||||
+ getReadableForm(lcID) + " for socket " + s, ioe);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getName() + ": Timeout waiting for ack from syn for id "
|
||||
+ lcID + " to " + peer.calculateHash().toBase64().substring(0,6)
|
||||
+ " for socket " + s, ioe);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
@@ -498,14 +518,24 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
_context.statManager().addRateData("streaming.synNoAck", 1, 1);
|
||||
throw new InterruptedIOException("Timeout waiting for ack");
|
||||
} catch (ConnectException ex) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getName() + ": Connection error waiting for ack from syn for id "
|
||||
+ lcID + " to " + peer.calculateHash().toBase64().substring(0,6)
|
||||
+ " for socket " + s, ex);
|
||||
s.internalClose();
|
||||
throw ex;
|
||||
} catch (NoRouteToHostException ex) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getName() + ": No route to host waiting for ack from syn for id "
|
||||
+ lcID + " to " + peer.calculateHash().toBase64().substring(0,6)
|
||||
+ " for socket " + s, ex);
|
||||
s.internalClose();
|
||||
throw ex;
|
||||
} catch (IOException ex) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error(getName() + ": Error sending syn on id " + getReadableForm(lcID) + " for socket " + s, ex);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getName() + ": Error sending syn on id "
|
||||
+ lcID + " to " + peer.calculateHash().toBase64().substring(0,6)
|
||||
+ " for socket " + s, ex);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
@@ -513,7 +543,9 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
throw new I2PException("Unhandled IOException occurred");
|
||||
} catch (I2PException ex) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getName() + ": Error sending syn on id " + getReadableForm(lcID) + " for socket " + s, ex);
|
||||
_log.info(getName() + ": Error sending syn on id "
|
||||
+ lcID + " to " + peer.calculateHash().toBase64().substring(0,6)
|
||||
+ " for socket " + s, ex);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
@@ -521,7 +553,9 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
throw ex;
|
||||
} catch (Exception e) {
|
||||
s.internalClose();
|
||||
_log.error(getName() + ": Unhandled error connecting", e);
|
||||
_log.warn(getName() + ": Unhandled error connecting on "
|
||||
+ lcID + " to " + peer.calculateHash().toBase64().substring(0,6)
|
||||
+ " for socket " + s, e);
|
||||
throw new ConnectException("Unhandled error connecting: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -592,7 +626,7 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
_session.destroySession();
|
||||
_log.debug(getName() + ": I2P session destroyed");
|
||||
} catch (I2PSessionException e) {
|
||||
_log.error(getName() + ": Error destroying I2P session", e);
|
||||
_log.warn(getName() + ": Error destroying I2P session", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,15 +652,17 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
try {
|
||||
return _session.sendMessage(peer, new byte[] { (byte) CHAFF});
|
||||
} catch (I2PException ex) {
|
||||
_log.error(getName() + ": I2PException:", ex);
|
||||
_log.warn(getName() + ": I2PException:", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSocket(I2PSocketImpl sock) {
|
||||
String localId = sock.getLocalID();
|
||||
boolean removed = false;
|
||||
synchronized (lock) {
|
||||
_inSockets.remove(sock.getLocalID());
|
||||
_outSockets.remove(sock.getLocalID());
|
||||
removed = (null != _inSockets.remove(localId));
|
||||
removed = removed || (null != _outSockets.remove(localId));
|
||||
lock.notify();
|
||||
}
|
||||
|
||||
@@ -637,9 +673,10 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
long recv = sock.getBytesReceived();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug(getName() + ": Removing socket \"" + getReadableForm(sock.getLocalID()) + "\" [" + sock
|
||||
_log.debug(getName() + ": Removing socket \"" + getReadableForm(localId) + "\" [" + sock
|
||||
+ ", send: " + sent + ", recv: " + recv
|
||||
+ ", lifetime: " + lifetime + "ms, time since close: " + timeSinceClose + ")]",
|
||||
+ ", lifetime: " + lifetime + "ms, time since close: " + timeSinceClose
|
||||
+ " removed? " + removed + ")]",
|
||||
new Exception("removeSocket called"));
|
||||
}
|
||||
|
||||
|
@@ -145,11 +145,16 @@ public class ConfigNetHandler extends FormHandler {
|
||||
}
|
||||
|
||||
int fetched = 0;
|
||||
int errors = 0;
|
||||
for (Iterator iter = urls.iterator(); iter.hasNext(); ) {
|
||||
fetchSeed(seedURL, (String)iter.next());
|
||||
fetched++;
|
||||
try {
|
||||
fetchSeed(seedURL, (String)iter.next());
|
||||
fetched++;
|
||||
} catch (Exception e) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
addFormNotice("Reseeded with " + fetched + " peers");
|
||||
addFormNotice("Reseeded with " + fetched + " peers (and " + errors + " failures)");
|
||||
} catch (Throwable t) {
|
||||
_context.logManager().getLog(ConfigNetHandler.class).error("Error reseeding", t);
|
||||
addFormError("Error reseeding (RESEED_EXCEPTION)");
|
||||
|
@@ -4,8 +4,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.FileUtil;
|
||||
|
||||
public class ContentHelper {
|
||||
private String _page;
|
||||
@@ -40,14 +40,14 @@ public class ContentHelper {
|
||||
}
|
||||
}
|
||||
public String getContent() {
|
||||
String str = DataHelper.readTextFile(_page, _maxLines);
|
||||
String str = FileUtil.readTextFile(_page, _maxLines);
|
||||
if (str == null)
|
||||
return "";
|
||||
else
|
||||
return str;
|
||||
}
|
||||
public String getTextContent() {
|
||||
String str = DataHelper.readTextFile(_page, _maxLines);
|
||||
String str = FileUtil.readTextFile(_page, _maxLines);
|
||||
if (str == null)
|
||||
return "";
|
||||
else
|
||||
|
@@ -4,8 +4,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.FileUtil;
|
||||
|
||||
public class LogsHelper {
|
||||
private RouterContext _context;
|
||||
@@ -28,7 +28,7 @@ public class LogsHelper {
|
||||
public String getLogs() {
|
||||
List msgs = _context.logManager().getBuffer().getMostRecentMessages();
|
||||
StringBuffer buf = new StringBuffer(16*1024);
|
||||
buf.append("<h2>Most recent console messages:</h2><ul>");
|
||||
buf.append("<ul>");
|
||||
buf.append("<code>\n");
|
||||
for (int i = msgs.size(); i > 0; i--) {
|
||||
String msg = (String)msgs.get(i - 1);
|
||||
@@ -42,10 +42,26 @@ public class LogsHelper {
|
||||
}
|
||||
|
||||
public String getServiceLogs() {
|
||||
String str = DataHelper.readTextFile("wrapper.log", 500);
|
||||
String str = FileUtil.readTextFile("wrapper.log", 500);
|
||||
if (str == null)
|
||||
return "";
|
||||
else
|
||||
return "<pre>" + str + "</pre>";
|
||||
}
|
||||
|
||||
public String getConnectionLogs() {
|
||||
List msgs = _context.commSystem().getMostRecentErrorMessages();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@@ -2,11 +2,14 @@ package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
|
||||
public class NetDbHelper {
|
||||
private RouterContext _context;
|
||||
private Writer _out;
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
*
|
||||
@@ -23,13 +26,21 @@ public class NetDbHelper {
|
||||
|
||||
public NetDbHelper() {}
|
||||
|
||||
public void setWriter(Writer writer) { _out = writer; }
|
||||
|
||||
public String getNetDbSummary() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024);
|
||||
try {
|
||||
_context.netDb().renderStatusHTML(baos);
|
||||
if (_out != null) {
|
||||
_context.netDb().renderStatusHTML(_out);
|
||||
return "";
|
||||
} else {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024);
|
||||
_context.netDb().renderStatusHTML(new OutputStreamWriter(baos));
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,34 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
|
||||
/**
|
||||
* Simple helper to query the appropriate router for data necessary to render
|
||||
* any emergency notices
|
||||
*/
|
||||
public class NoticeHelper {
|
||||
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 String getSystemNotice() {
|
||||
if (_context.router().gracefulShutdownInProgress()) {
|
||||
return "Graceful shutdown in "
|
||||
+ DataHelper.formatDuration(_context.router().getShutdownTimeRemaining());
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,8 @@ package net.i2p.router.web;
|
||||
|
||||
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;
|
||||
@@ -9,6 +11,7 @@ import net.i2p.router.admin.StatsGenerator;
|
||||
|
||||
public class OldConsoleHelper {
|
||||
private RouterContext _context;
|
||||
private Writer _out;
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
*
|
||||
@@ -25,11 +28,20 @@ public class OldConsoleHelper {
|
||||
|
||||
public OldConsoleHelper() {}
|
||||
|
||||
public void setWriter(Writer writer) {
|
||||
_out = writer;
|
||||
}
|
||||
|
||||
public String getConsole() {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(128*1024);
|
||||
_context.router().renderStatusHTML(baos);
|
||||
return baos.toString();
|
||||
if (_out != null) {
|
||||
_context.router().renderStatusHTML(_out);
|
||||
return "";
|
||||
} else {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(128*1024);
|
||||
_context.router().renderStatusHTML(new OutputStreamWriter(baos));
|
||||
return baos.toString();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
return "<b>Error rending the console</b>";
|
||||
}
|
||||
@@ -38,9 +50,14 @@ public class OldConsoleHelper {
|
||||
public String getStats() {
|
||||
StatsGenerator gen = new StatsGenerator(_context);
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024);
|
||||
gen.generateStatsPage(baos);
|
||||
return baos.toString();
|
||||
if (_out != null) {
|
||||
gen.generateStatsPage(_out);
|
||||
return "";
|
||||
} else {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024);
|
||||
gen.generateStatsPage(new OutputStreamWriter(baos));
|
||||
return baos.toString();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
return "<b>Error rending the console</b>";
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
|
||||
@@ -26,7 +27,7 @@ public class ProfilesHelper {
|
||||
public String getProfileSummary() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(16*1024);
|
||||
try {
|
||||
_context.profileOrganizer().renderStatusHTML(baos);
|
||||
_context.profileOrganizer().renderStatusHTML(new OutputStreamWriter(baos));
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
@@ -36,7 +37,7 @@ public class ProfilesHelper {
|
||||
public String getShitlistSummary() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
||||
try {
|
||||
_context.shitlist().renderStatusHTML(baos);
|
||||
_context.shitlist().renderStatusHTML(new OutputStreamWriter(baos));
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.apps.systray.SysTray;
|
||||
import net.i2p.util.FileUtil;
|
||||
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.WebApplicationContext;
|
||||
@@ -21,6 +23,10 @@ public class RouterConsoleRunner {
|
||||
private String _listenHost = "127.0.0.1";
|
||||
private String _webAppsDir = "./webapps/";
|
||||
|
||||
static {
|
||||
System.setProperty("org.mortbay.http.Version.paranoid", "true");
|
||||
}
|
||||
|
||||
public RouterConsoleRunner(String args[]) {
|
||||
if (args.length == 3) {
|
||||
_listenPort = args[0].trim();
|
||||
@@ -35,6 +41,14 @@ public class RouterConsoleRunner {
|
||||
}
|
||||
|
||||
public void startConsole() {
|
||||
File workDir = new File("work");
|
||||
boolean workDirRemoved = FileUtil.rmdir(workDir, false);
|
||||
if (!workDirRemoved)
|
||||
System.err.println("ERROR: Unable to remove Jetty temporary work directory");
|
||||
boolean workDirCreated = workDir.mkdirs();
|
||||
if (!workDirCreated)
|
||||
System.err.println("ERROR: Unable to create Jetty temporary work directory");
|
||||
|
||||
_server = new Server();
|
||||
WebApplicationContext contexts[] = null;
|
||||
try {
|
||||
|
@@ -2,6 +2,7 @@ package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
@@ -297,26 +298,27 @@ public class SummaryHelper {
|
||||
}
|
||||
|
||||
private static String getTransferred(long bytes) {
|
||||
double val = bytes;
|
||||
int scale = 0;
|
||||
if (bytes > 1024*1024*1024) {
|
||||
// gigs transferred
|
||||
scale = 3;
|
||||
bytes /= (1024*1024*1024);
|
||||
val /= (double)(1024*1024*1024);
|
||||
} else if (bytes > 1024*1024) {
|
||||
// megs transferred
|
||||
scale = 2;
|
||||
bytes /= (1024*1024);
|
||||
val /= (double)(1024*1024);
|
||||
} else if (bytes > 1024) {
|
||||
// kbytes transferred
|
||||
scale = 1;
|
||||
bytes /= 1024;
|
||||
val /= (double)1024;
|
||||
} else {
|
||||
scale = 0;
|
||||
}
|
||||
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
|
||||
String str = fmt.format(bytes);
|
||||
String str = fmt.format(val);
|
||||
switch (scale) {
|
||||
case 1: return str + "KB";
|
||||
case 2: return str + "MB";
|
||||
@@ -333,7 +335,9 @@ public class SummaryHelper {
|
||||
public String getDestinations() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
||||
try {
|
||||
_context.clientManager().renderStatusHTML(baos);
|
||||
OutputStreamWriter osw = new OutputStreamWriter(baos);
|
||||
_context.clientManager().renderStatusHTML(osw);
|
||||
osw.flush();
|
||||
return new String(baos.toByteArray());
|
||||
} catch (IOException ioe) {
|
||||
_context.logManager().getLog(SummaryHelper.class).error("Error rendering client info", ioe);
|
||||
@@ -396,8 +400,7 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0ms";
|
||||
|
||||
Rate delayRate = _context.statManager().getRate("transport.sendProcessingTime").getRate(60*1000);
|
||||
return ((int)delayRate.getAverageValue()) + "ms";
|
||||
return _context.throttle().getMessageDelay() + "ms";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,7 +412,6 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0ms";
|
||||
|
||||
Rate lagRate = _context.statManager().getRate("tunnel.testSuccessTime").getRate(10*60*1000);
|
||||
return ((int)lagRate.getAverageValue()) + "ms";
|
||||
return _context.throttle().getTunnelLag() + "ms";
|
||||
}
|
||||
}
|
@@ -35,8 +35,11 @@
|
||||
<input name="port" type="text" size="4" value="<jsp:getProperty name="nethelper" property="port" />" /> <br />
|
||||
<i>The hostname/IP address and TCP port must be reachable from the outside world. If
|
||||
you are behind a firewall or NAT, this means you must poke a hole for this port. If
|
||||
you are using DHCP and do not have a static IP address, you must use a service like
|
||||
<a href="http://dyndns.org/">dyndns</a>. The "guess" functionality makes an HTTP request
|
||||
you are using DHCP and do not have a static IP address, you should either use a service like
|
||||
<a href="http://dyndns.org/">dyndns</a> or leave the hostname blank. If you leave it blank,
|
||||
your router will autodetect the 'correct' IP address by asking a peer (and unconditionally
|
||||
believing them if the address is routable and you don't have any established connections yet).
|
||||
The "guess" functionality makes an HTTP request
|
||||
to <a href="http://www.whatismyip.com/">www.whatismyip.com</a>.</i>
|
||||
<hr />
|
||||
<b>Enable internal time synchronization?</b> <input type="checkbox" <jsp:getProperty name="nethelper" property="enableTimeSyncChecked" /> name="enabletimesync" /><br />
|
||||
|
@@ -29,7 +29,7 @@
|
||||
<input type="hidden" name="action" value="blah" />
|
||||
<b>Logging filename:</b>
|
||||
<input type="text" name="logfilename" size="40" value="<jsp:getProperty name="logginghelper" property="logFilePattern" />" /><br />
|
||||
<i>(the symbol '#' will be replaced during log rotation)</i><br />
|
||||
<i>(the symbol '@' will be replaced during log rotation)</i><br />
|
||||
<b>Log record format:</b>
|
||||
<input type="text" name="logformat" size="20" value="<jsp:getProperty name="logginghelper" property="recordPattern" />" /><br />
|
||||
<i>(use 'd' = date, 'c' = class, 't' = thread, 'p' = priority, 'm' = message)</i><br />
|
||||
|
@@ -16,6 +16,9 @@
|
||||
<h4>Router logs:</h4>
|
||||
<jsp:getProperty name="logsHelper" property="logs" />
|
||||
<hr />
|
||||
<h4>Connection logs:</h4><a name="connectionlogs"> </a>
|
||||
<jsp:getProperty name="logsHelper" property="connectionLogs" />
|
||||
<hr />
|
||||
<h4>Service logs:</h4><a name="servicelogs"> </a>
|
||||
<jsp:getProperty name="logsHelper" property="serviceLogs" />
|
||||
</div>
|
||||
|
@@ -25,3 +25,7 @@
|
||||
<jsp:setProperty name="navhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<jsp:getProperty name="navhelper" property="clientAppLinks" />
|
||||
</h4>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.NoticeHelper" id="noticehelper" scope="request" />
|
||||
<jsp:setProperty name="noticehelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<b><jsp:getProperty name="noticehelper" property="systemNotice" /></b>
|
||||
|
@@ -13,6 +13,7 @@
|
||||
<div class="main" id="main">
|
||||
<jsp:useBean class="net.i2p.router.web.NetDbHelper" id="netdbHelper" scope="request" />
|
||||
<jsp:setProperty name="netdbHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<jsp:setProperty name="netdbHelper" property="writer" value="<%=out%>" />
|
||||
<jsp:getProperty name="netdbHelper" property="netDbSummary" />
|
||||
</div>
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="conhelper" scope="request" />
|
||||
<jsp:setProperty name="conhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<jsp:setProperty name="conhelper" property="writer" value="<%=out%>" />
|
||||
|
||||
<div class="main" id="main">
|
||||
<jsp:getProperty name="conhelper" property="console" />
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="oldhelper" scope="request" />
|
||||
<jsp:setProperty name="oldhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<jsp:setProperty name="oldhelper" property="writer" value="<%=out%>" />
|
||||
|
||||
<div class="main" id="main">
|
||||
<jsp:getProperty name="oldhelper" property="stats" />
|
||||
|
@@ -28,6 +28,20 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* I2P-Ping won't compile on Windows because Windows lacks getopt()
|
||||
*/
|
||||
|
||||
/*
|
||||
* Exit values:
|
||||
* 0: Received at least one response from one dest, or help
|
||||
* message was successfully displayed
|
||||
* 1: Received no responses from any dest
|
||||
* 2: Naming lookup failed, or dest unspecified
|
||||
* 3: SAM error
|
||||
*/
|
||||
|
||||
#include <getopt.h> /* needed on Gentoo Linux */
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -58,10 +72,11 @@ sam_sid_t laststream = 0;
|
||||
bool mihi = false;
|
||||
bool bell = false;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
int count = INT_MAX; /* number of times to ping */
|
||||
int pongcount = -1;
|
||||
char *samhost = "localhost";
|
||||
uint16_t samport = 7656;
|
||||
|
||||
@@ -88,7 +103,7 @@ int main(int argc, char* argv[])
|
||||
quiet = true;
|
||||
break;
|
||||
case 'v': /* version */
|
||||
puts("$Id: i2p-ping.c,v 1.2 2004/07/31 22:20:22 mpc Exp $");
|
||||
puts("$Id: i2p-ping.c,v 1.4 2004/09/22 20:05:40 jrandom Exp $");
|
||||
puts("Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>");
|
||||
break;
|
||||
case '?':
|
||||
@@ -101,7 +116,7 @@ int main(int argc, char* argv[])
|
||||
argv += optind;
|
||||
if (argc == 0) { /* they forgot to specify a ping target */
|
||||
fprintf(stderr, "Ping who?\n");
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Hook up the callback functions - required by LibSAM */
|
||||
@@ -120,9 +135,10 @@ int main(int argc, char* argv[])
|
||||
if (rc != SAM_OK) {
|
||||
fprintf(stderr, "SAM connection failed: %s\n", sam_strerror(rc));
|
||||
sam_session_free(&session);
|
||||
return 1;
|
||||
return 3;
|
||||
}
|
||||
|
||||
pongcount = 0;
|
||||
for (int j = 0; j < argc; j++) {
|
||||
if (strlen(argv[j]) == 516) {
|
||||
memcpy(dest, argv[j], SAM_PUBKEY_LEN);
|
||||
@@ -144,6 +160,8 @@ int main(int argc, char* argv[])
|
||||
time_t finish = time(0);
|
||||
laststream = 0;
|
||||
if (laststatus == SAM_OK) {
|
||||
pongcount++;
|
||||
|
||||
if (bell)
|
||||
printf("\a"); /* putchar() doesn't work for some reason */
|
||||
if (!mihi)
|
||||
@@ -164,7 +182,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
sam_close(session);
|
||||
sam_session_free(&session);
|
||||
return 0;
|
||||
return pongcount == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
void usage()
|
||||
@@ -178,7 +196,7 @@ void usage()
|
||||
*/
|
||||
static void closeback(sam_sess_t *session, sam_sid_t stream_id, samerr_t reason)
|
||||
{
|
||||
fprintf(stderr, "Connection closed to stream %d: %s\n", stream_id,
|
||||
fprintf(stderr, "Connection closed to stream %d: %s\n", (int)stream_id,
|
||||
sam_strerror(reason));
|
||||
}
|
||||
|
||||
@@ -207,7 +225,7 @@ static void databack(sam_sess_t *session, sam_sid_t stream_id, void *data,
|
||||
static void diedback(sam_sess_t *session)
|
||||
{
|
||||
fprintf(stderr, "Lost SAM connection!\n");
|
||||
exit(1);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -228,7 +246,7 @@ static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result)
|
||||
{
|
||||
if (result != SAM_OK) {
|
||||
fprintf(stderr, "Naming lookup failed: %s\n", sam_strerror(result));
|
||||
exit(1);
|
||||
exit(2);
|
||||
}
|
||||
memcpy(dest, pubkey, SAM_PUBKEY_LEN);
|
||||
gotdest = true;
|
||||
@@ -238,7 +256,7 @@ static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result)
|
||||
* Our connection attempt returned a result
|
||||
*/
|
||||
static void statusback(sam_sess_t *session, sam_sid_t stream_id,
|
||||
samerr_t result)
|
||||
samerr_t result)
|
||||
{
|
||||
laststatus = result;
|
||||
laststream = stream_id;
|
||||
|
@@ -55,7 +55,7 @@ static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result);
|
||||
bool gotdest = false;
|
||||
sam_pubkey_t dest;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
* The target of our attack is specified on the command line
|
||||
@@ -142,7 +142,7 @@ int main(int argc, char* argv[])
|
||||
* service programs don't need input ;)
|
||||
*/
|
||||
static void dgramback(sam_sess_t *session, sam_pubkey_t dest, void *data,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
puts("Received a datagram (ignored)");
|
||||
free(data);
|
||||
|
@@ -49,7 +49,7 @@ public class SysTray implements SysTrayMenuListener {
|
||||
if (!(new File("router.config")).exists())
|
||||
openRouterConsole("http://localhost:" + _portString + "/index.jsp");
|
||||
|
||||
if (System.getProperty("os.name").startsWith("Windows"))
|
||||
if ( (System.getProperty("os.name").startsWith("Windows")) && (!Boolean.getBoolean("systray.disable")) )
|
||||
_instance = new SysTray();
|
||||
}
|
||||
|
||||
|
26
build.xml
26
build.xml
@@ -6,7 +6,7 @@
|
||||
<echo message=" dist: distclean then package everything up (installer, clean tarball, update tarball)" />
|
||||
<echo message=" installer: build the GUI installer" />
|
||||
<echo message=" tarball: tar the full install into i2p.tar.bz2 (extracts to build a new clean install)" />
|
||||
<echo message=" updater: tar the built i2p specific files into an i2pupdate.tar.bz2 (extracts safely over existing installs)" />
|
||||
<echo message=" updater: tar the built i2p specific files into an i2pupdate.zip (extracts safely over existing installs)" />
|
||||
<echo message=" distclean: clean up all derived files" />
|
||||
<echo message=" javadoc: generate javadoc for the entire project into ./build/javadoc" />
|
||||
</target>
|
||||
@@ -57,7 +57,7 @@
|
||||
<target name="javadoc">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/javadoc" />
|
||||
<javadoc
|
||||
<javadoc access="package"
|
||||
destdir="./build/javadoc"
|
||||
packagenames="*"
|
||||
use="true"
|
||||
@@ -143,7 +143,7 @@
|
||||
<target name="pkgclean">
|
||||
<delete dir="pkg-temp" />
|
||||
<delete>
|
||||
<fileset dir="." includes="i2p.tar.bz2 install.jar i2pupdate.tar.bz2" />
|
||||
<fileset dir="." includes="i2p.tar.bz2 install.jar i2pupdate.zip" />
|
||||
</delete>
|
||||
</target>
|
||||
<target name="preppkg" depends="build">
|
||||
@@ -207,8 +207,12 @@
|
||||
<copy file="history.txt" todir="pkg-temp/" />
|
||||
<mkdir dir="pkg-temp/docs" />
|
||||
<copy file="readme.html" todir="pkg-temp/docs/" />
|
||||
<mkdir dir="pkg-temp/work" />
|
||||
<touch file="pkg-temp/work/ignore.this" />
|
||||
<mkdir dir="pkg-temp/eepsite" />
|
||||
<mkdir dir="pkg-temp/eepsite/webapps" />
|
||||
<mkdir dir="pkg-temp/eepsite/logs" />
|
||||
<mkdir dir="pkg-temp/eepsite/docroot" />
|
||||
<copy file="installer/resources/eepsite_index.html" tofile="pkg-temp/eepsite/docroot/index.html" />
|
||||
<copy file="installer/resources/jetty.xml" tofile="pkg-temp/eepsite/jetty.xml" />
|
||||
</target>
|
||||
<target name="tarball" depends="preppkg">
|
||||
<tar compression="bzip2" destfile="i2p.tar.bz2">
|
||||
@@ -217,24 +221,18 @@
|
||||
</target>
|
||||
<target name="updater" depends="build">
|
||||
<delete dir="pkg-temp" />
|
||||
<copy file="build/heartbeat.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/i2p.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/mstreaming.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/router.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/sam.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/systray.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/i2ptunnel.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/routerconsole.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="history.txt" todir="pkg-temp/" />
|
||||
<copy file="hosts.txt" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/install_i2p_service_winnt.bat" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/uninstall_i2p_service_winnt.bat" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/i2prouter" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/i2prouter.bat" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/i2prouter_win9x.bat" todir="pkg-temp/" />
|
||||
<copy file="installer/resources/wrapper.config" todir="pkg-temp/" />
|
||||
<mkdir dir="pkg-temp/eepsite" />
|
||||
<mkdir dir="pkg-temp/eepsite/webapps" />
|
||||
<copy file="installer/resources/jetty.xml" tofile="pkg-temp/eepsite/jetty.xml" />
|
||||
<zip destfile="i2pupdate.zip" basedir="pkg-temp" />
|
||||
</target>
|
||||
<taskdef name="izpack" classpath="${basedir}/installer/lib/izpack/standalone-compiler.jar" classname="com.izforge.izpack.ant.IzPackTask" />
|
||||
|
@@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
public final static String ID = "$Revision: 1.19 $ $Date: 2004/09/03 14:46:07 $";
|
||||
public final static String VERSION = "0.4.0.1";
|
||||
public final static String ID = "$Revision: 1.22 $ $Date: 2004/10/01 12:23:00 $";
|
||||
public final static String VERSION = "0.4.1.2";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
@@ -284,7 +284,7 @@ public class I2PAppContext {
|
||||
* matter. Though for the crazy people out there, we do expose a way to
|
||||
* disable it.
|
||||
*/
|
||||
public AESEngine AESEngine() {
|
||||
public AESEngine aes() {
|
||||
if (!_AESEngineInitialized) initializeAESEngine();
|
||||
return _AESEngine;
|
||||
}
|
||||
|
@@ -580,7 +580,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
while (true) {
|
||||
long delay = BASE_RECONNECT_DELAY << i;
|
||||
i++;
|
||||
if (delay > MAX_RECONNECT_DELAY)
|
||||
if ( (delay > MAX_RECONNECT_DELAY) || (delay <= 0) )
|
||||
delay = MAX_RECONNECT_DELAY;
|
||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||
|
||||
|
@@ -33,7 +33,6 @@ import net.i2p.util.Log;
|
||||
* @author jrandom
|
||||
*/
|
||||
class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
private final static Log _log = new Log(RequestLeaseSetMessageHandler.class);
|
||||
private Map _existingLeaseSets;
|
||||
|
||||
public RequestLeaseSetMessageHandler(I2PAppContext context) {
|
||||
|
@@ -10,7 +10,10 @@ 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;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Destination;
|
||||
@@ -34,42 +37,58 @@ public class HostsTxtNamingService extends NamingService {
|
||||
* If this system property is specified, the tunnel will read the
|
||||
* given file for hostname=destKey values when resolving names
|
||||
*/
|
||||
public final static String PROP_HOSTS_FILE = "i2p.hostsfile";
|
||||
public final static String PROP_HOSTS_FILE = "i2p.hostsfilelist";
|
||||
|
||||
/** default hosts.txt filename */
|
||||
public final static String DEFAULT_HOSTS_FILE = "hosts.txt";
|
||||
public final static String DEFAULT_HOSTS_FILE = "userhosts.txt,hosts.txt";
|
||||
|
||||
private final static Log _log = new Log(HostsTxtNamingService.class);
|
||||
|
||||
private List getFilenames() {
|
||||
String list = _context.getProperty(PROP_HOSTS_FILE, DEFAULT_HOSTS_FILE);
|
||||
StringTokenizer tok = new StringTokenizer(list, ",");
|
||||
List rv = new ArrayList(tok.countTokens());
|
||||
while (tok.hasMoreTokens())
|
||||
rv.add(tok.nextToken());
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Destination lookup(String hostname) {
|
||||
// Try to look it up in hosts.txt
|
||||
// Reload file each time to catch changes.
|
||||
// (and it's easier :P
|
||||
String hostsfile = _context.getProperty(PROP_HOSTS_FILE, DEFAULT_HOSTS_FILE);
|
||||
Properties hosts = new Properties();
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
File f = new File(hostsfile);
|
||||
if (f.canRead()) {
|
||||
fis = new FileInputStream(f);
|
||||
hosts.load(fis);
|
||||
} else {
|
||||
_log.error("Hosts file " + hostsfile + " does not exist.");
|
||||
}
|
||||
} catch (Exception ioe) {
|
||||
_log.error("Error loading hosts file " + hostsfile, ioe);
|
||||
} finally {
|
||||
if (fis != null) try {
|
||||
fis.close();
|
||||
} catch (IOException ioe) { // nop
|
||||
// check the list each time, reloading the file on each
|
||||
// lookup
|
||||
|
||||
List filenames = getFilenames();
|
||||
for (int i = 0; i < filenames.size(); i++) {
|
||||
String hostsfile = (String)filenames.get(i);
|
||||
Properties hosts = new Properties();
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
File f = new File(hostsfile);
|
||||
if ( (f.exists()) && (f.canRead()) ) {
|
||||
fis = new FileInputStream(f);
|
||||
hosts.load(fis);
|
||||
|
||||
String key = hosts.getProperty(hostname);
|
||||
if ( (key != null) && (key.trim().length() > 0) ) {
|
||||
return lookupBase64(key);
|
||||
}
|
||||
|
||||
} else {
|
||||
_log.warn("Hosts file " + hostsfile + " does not exist.");
|
||||
}
|
||||
} catch (Exception ioe) {
|
||||
_log.error("Error loading hosts file " + hostsfile, ioe);
|
||||
} finally {
|
||||
if (fis != null) try {
|
||||
fis.close();
|
||||
} catch (IOException ioe) { // nop
|
||||
}
|
||||
}
|
||||
// not found, continue to the next file
|
||||
}
|
||||
String res = hosts.getProperty(hostname);
|
||||
// If we can't find name in hosts, assume it's a key.
|
||||
if ((res == null) || (res.trim().length() == 0)) {
|
||||
res = hostname;
|
||||
}
|
||||
return lookupBase64(res);
|
||||
// If we can't find name in any of the hosts files,
|
||||
// assume it's a key.
|
||||
return lookupBase64(hostname);
|
||||
}
|
||||
|
||||
public String reverseLookup(Destination dest) {
|
||||
|
@@ -37,28 +37,23 @@ public class AESEngine {
|
||||
|
||||
/** 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 initializationVector IV for CBC
|
||||
* @return encrypted data
|
||||
* @param iv IV for CBC
|
||||
* @param length how much data to encrypt
|
||||
*/
|
||||
public byte[] encrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) {
|
||||
if ((initializationVector == null) || (payload == null) || (sessionKey == null)
|
||||
|| (initializationVector.length != 16)) return null;
|
||||
|
||||
byte cyphertext[] = null;
|
||||
if ((payload.length % 16) == 0)
|
||||
cyphertext = new byte[payload.length];
|
||||
else
|
||||
cyphertext = new byte[payload.length + (16 - (payload.length % 16))];
|
||||
System.arraycopy(payload, 0, cyphertext, 0, payload.length);
|
||||
return cyphertext;
|
||||
public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) {
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
_log.warn("Warning: AES is disabled");
|
||||
}
|
||||
|
||||
public byte[] safeEncrypt(byte payload[], SessionKey sessionKey, byte iv[], int paddedSize) {
|
||||
if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null;
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(paddedSize + 64);
|
||||
Hash h = _context.sha().calculateHash(sessionKey.getData());
|
||||
Hash h = _context.sha().calculateHash(iv);
|
||||
try {
|
||||
h.writeBytes(baos);
|
||||
DataHelper.writeLong(baos, 4, payload.length);
|
||||
@@ -72,19 +67,23 @@ public class AESEngine {
|
||||
_log.error("Error writing data", dfe);
|
||||
return null;
|
||||
}
|
||||
return encrypt(baos.toByteArray(), sessionKey, iv);
|
||||
byte orig[] = baos.toByteArray();
|
||||
byte rv[] = new byte[orig.length];
|
||||
encrypt(orig, 0, rv, 0, sessionKey, iv, rv.length);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public byte[] safeDecrypt(byte payload[], SessionKey sessionKey, byte iv[]) {
|
||||
if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null;
|
||||
|
||||
byte decr[] = decrypt(payload, sessionKey, iv);
|
||||
byte decr[] = new byte[payload.length];
|
||||
decrypt(payload, 0, decr, 0, sessionKey, iv, payload.length);
|
||||
if (decr == null) {
|
||||
_log.error("Error decrypting the data - payload " + payload.length + " decrypted to null");
|
||||
return null;
|
||||
}
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(decr);
|
||||
Hash h = _context.sha().calculateHash(sessionKey.getData());
|
||||
Hash h = _context.sha().calculateHash(iv);
|
||||
try {
|
||||
Hash rh = new Hash();
|
||||
rh.readBytes(bais);
|
||||
@@ -110,19 +109,19 @@ public class AESEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/** decrypt the data with the session key provided
|
||||
* @param cyphertext encrypted data
|
||||
* @param sessionKey private session key
|
||||
* @param initializationVector IV for CBC
|
||||
* @return unencrypted data
|
||||
*/
|
||||
public byte[] decrypt(byte cyphertext[], SessionKey sessionKey, byte initializationVector[]) {
|
||||
if ((initializationVector == null) || (cyphertext == null) || (sessionKey == null)
|
||||
|| (initializationVector.length != 16)) return null;
|
||||
|
||||
byte payload[] = new byte[cyphertext.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 length) {
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
_log.warn("Warning: AES is disabled");
|
||||
return cyphertext;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
@@ -133,14 +132,16 @@ public class AESEngine {
|
||||
|
||||
byte sbuf[] = new byte[16];
|
||||
RandomSource.getInstance().nextBytes(sbuf);
|
||||
byte se[] = ctx.AESEngine().encrypt(sbuf, key, iv);
|
||||
byte sd[] = ctx.AESEngine().decrypt(se, key, iv);
|
||||
byte se[] = new byte[16];
|
||||
ctx.aes().encrypt(sbuf, 0, se, 0, key, iv, sbuf.length);
|
||||
byte sd[] = new byte[16];
|
||||
ctx.aes().decrypt(se, 0, sd, 0, key, iv, se.length);
|
||||
ctx.logManager().getLog(AESEngine.class).debug("Short test: " + DataHelper.eq(sd, sbuf));
|
||||
|
||||
byte lbuf[] = new byte[1024];
|
||||
RandomSource.getInstance().nextBytes(sbuf);
|
||||
byte le[] = ctx.AESEngine().safeEncrypt(lbuf, key, iv, 2048);
|
||||
byte ld[] = ctx.AESEngine().safeDecrypt(le, key, iv);
|
||||
byte le[] = ctx.aes().safeEncrypt(lbuf, key, iv, 2048);
|
||||
byte ld[] = ctx.aes().safeDecrypt(le, key, iv);
|
||||
ctx.logManager().getLog(AESEngine.class).debug("Long test: " + DataHelper.eq(ld, lbuf));
|
||||
}
|
||||
}
|
@@ -46,66 +46,81 @@ public class AESInputStream extends FilterInputStream {
|
||||
private long _cumulativePrepared; // how many bytes decrypted and added to _readyBuf
|
||||
private long _cumulativePaddingStripped; // how many bytes have been stripped
|
||||
|
||||
private ByteArrayOutputStream _encryptedBuf; // read from the stream but not yet decrypted
|
||||
private List _readyBuf; // list of Bytes ready to be consumed, where index 0 is the first
|
||||
/** read but not yet decrypted */
|
||||
private byte _encryptedBuf[];
|
||||
/** how many bytes have been added to the encryptedBuf since it was decrypted? */
|
||||
private int _writesSinceDecrypt;
|
||||
/** decrypted bytes ready for reading (first available == index of 0) */
|
||||
private int _decryptedBuf[];
|
||||
/** how many bytes are available for reading without decrypt? */
|
||||
private int _decryptedSize;
|
||||
|
||||
private final static int BLOCK_SIZE = CryptixRijndael_Algorithm._BLOCK_SIZE;
|
||||
private final static int READ_SIZE = BLOCK_SIZE;
|
||||
private final static int DECRYPT_SIZE = BLOCK_SIZE - 1;
|
||||
|
||||
public AESInputStream(I2PAppContext context, InputStream source, SessionKey key, byte iv[]) {
|
||||
public AESInputStream(I2PAppContext context, InputStream source, SessionKey key, byte[] iv) {
|
||||
super(source);
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(AESInputStream.class);
|
||||
_key = key;
|
||||
_lastBlock = new byte[BLOCK_SIZE];
|
||||
System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||
_encryptedBuf = new ByteArrayOutputStream(BLOCK_SIZE);
|
||||
_readyBuf = new ArrayList(1024);
|
||||
_encryptedBuf = new byte[BLOCK_SIZE];
|
||||
_writesSinceDecrypt = 0;
|
||||
_decryptedBuf = new int[BLOCK_SIZE-1];
|
||||
_decryptedSize = 0;
|
||||
_cumulativePaddingStripped = 0;
|
||||
_eofFound = false;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
while ((!_eofFound) && (_readyBuf.size() <= 0)) {
|
||||
refill(READ_SIZE);
|
||||
while ((!_eofFound) && (_decryptedSize <= 0)) {
|
||||
refill();
|
||||
}
|
||||
Integer nval = getNext();
|
||||
if (nval != null) {
|
||||
return nval.intValue();
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("No byte available. eof? " + _eofFound);
|
||||
|
||||
if (_eofFound)
|
||||
if (_decryptedSize > 0) {
|
||||
int c = _decryptedBuf[0];
|
||||
System.arraycopy(_decryptedBuf, 1, _decryptedBuf, 0, _decryptedBuf.length-1);
|
||||
_decryptedSize--;
|
||||
return c;
|
||||
} else if (_eofFound) {
|
||||
return -1;
|
||||
|
||||
throw new IOException("Not EOF, but none available? " + _readyBuf.size() + "/" + _encryptedBuf.size()
|
||||
+ "/" + _cumulativeRead + "... impossible");
|
||||
} else {
|
||||
throw new IOException("Not EOF, but none available? " + _decryptedSize
|
||||
+ "/" + _writesSinceDecrypt
|
||||
+ "/" + _cumulativeRead + "... impossible");
|
||||
}
|
||||
}
|
||||
|
||||
public int read(byte dest[]) throws IOException {
|
||||
for (int i = 0; i < dest.length; i++) {
|
||||
int val = read();
|
||||
if (val == -1) {
|
||||
// no more to read... can they expect more?
|
||||
if (_eofFound && (i == 0)) return -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
dest[i] = (byte) val;
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read the full buffer of size " + dest.length);
|
||||
return dest.length;
|
||||
return read(dest, 0, dest.length);
|
||||
}
|
||||
|
||||
public int read(byte dest[], int off, int len) throws IOException {
|
||||
byte buf[] = new byte[len];
|
||||
int read = read(buf);
|
||||
if (read == -1) return -1;
|
||||
System.arraycopy(buf, 0, dest, off, read);
|
||||
return read;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int val = read();
|
||||
if (val == -1) {
|
||||
// no more to read... can they expect more?
|
||||
if (_eofFound && (i == 0)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.info("EOF? " + _eofFound
|
||||
+ "\nread=" + i + " decryptedSize=" + _decryptedSize
|
||||
+ " \nencryptedSize=" + _writesSinceDecrypt
|
||||
+ " \ntotal=" + _cumulativeRead
|
||||
+ " \npadding=" + _cumulativePaddingStripped
|
||||
+ " \nprepared=" + _cumulativePrepared);
|
||||
return -1;
|
||||
} else {
|
||||
if (i != len)
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.info("non-terminal eof: " + _eofFound + " i=" + i + " len=" + len);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
dest[off+i] = (byte)val;
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read the full buffer of size " + len);
|
||||
return len;
|
||||
}
|
||||
|
||||
public long skip(long numBytes) throws IOException {
|
||||
@@ -117,25 +132,15 @@ public class AESInputStream extends FilterInputStream {
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return _readyBuf.size();
|
||||
return _decryptedSize;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
//_log.debug("We have " + _encryptedBuf.size() + " available to decrypt... doing so");
|
||||
//decrypt();
|
||||
//byte buf[] = new byte[_readyBuf.size()];
|
||||
//for (int i = 0; i < buf.length; i++)
|
||||
// buf[i] = ((Integer)_readyBuf.get(i)).byteValue();
|
||||
//_log.debug("After decrypt: readyBuf.size: " + _readyBuf.size() + "\n val:\t" + Base64.encode(buf));
|
||||
int ready = _readyBuf.size();
|
||||
int encrypted = _readyBuf.size();
|
||||
_readyBuf.clear();
|
||||
_encryptedBuf.reset();
|
||||
in.close();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Cumulative bytes read from source/decrypted/stripped: " + _cumulativeRead + "/"
|
||||
+ _cumulativePrepared + "/" + _cumulativePaddingStripped + "] remaining [" + ready + " ready, "
|
||||
+ encrypted + " still encrypted]");
|
||||
+ _cumulativePrepared + "/" + _cumulativePaddingStripped + "] remaining [" + _decryptedSize + " ready, "
|
||||
+ _writesSinceDecrypt + " still encrypted]");
|
||||
}
|
||||
|
||||
public void mark(int readLimit) { // nop
|
||||
@@ -149,120 +154,66 @@ public class AESInputStream extends FilterInputStream {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the next ready byte, or null if no bytes are ready. this does not refill or block
|
||||
*
|
||||
*/
|
||||
private Integer getNext() {
|
||||
if (_readyBuf.size() > 0) {
|
||||
return (Integer) _readyBuf.remove(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read at least one new byte from the underlying stream, and up to max new bytes,
|
||||
* but not necessarily enough for a new decrypted block. This blocks until at least
|
||||
* one new byte is read from the stream
|
||||
*
|
||||
*/
|
||||
private void refill(int max) throws IOException {
|
||||
private void refill() throws IOException {
|
||||
if (!_eofFound) {
|
||||
byte buf[] = new byte[max];
|
||||
int read = in.read(buf);
|
||||
int read = in.read(_encryptedBuf, _writesSinceDecrypt, _encryptedBuf.length - _writesSinceDecrypt);
|
||||
if (read == -1) {
|
||||
_eofFound = true;
|
||||
} else if (read > 0) {
|
||||
//_log.debug("Read from the source stream " + read + " bytes");
|
||||
_cumulativeRead += read;
|
||||
_encryptedBuf.write(buf, 0, read);
|
||||
_writesSinceDecrypt += read;
|
||||
}
|
||||
}
|
||||
if (false) return; // true to keep the data for decrypt/display on close
|
||||
if (_encryptedBuf.size() > 0) {
|
||||
if (_encryptedBuf.size() >= DECRYPT_SIZE) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("We have " + _encryptedBuf.size() + " available to decrypt... doing so");
|
||||
decrypt();
|
||||
if ( (_encryptedBuf.size() > 0) && (_log.shouldLog(Log.DEBUG)) )
|
||||
_log.debug("Bytes left in the encrypted buffer after decrypt: " + _encryptedBuf.size());
|
||||
} else {
|
||||
if (_eofFound) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("EOF and not enough bytes to decrypt [size = " + _encryptedBuf.size()
|
||||
+ " totalCumulative: " + _cumulativeRead + "/"+_cumulativePrepared +"]!");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Not enough bytes to decrypt [size = " + _encryptedBuf.size()
|
||||
+ " totalCumulative: " + _cumulativeRead + "/"+_cumulativePrepared +"]");
|
||||
}
|
||||
}
|
||||
if (_writesSinceDecrypt == BLOCK_SIZE) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("We have " + _writesSinceDecrypt + " available to decrypt... doing so");
|
||||
decryptBlock();
|
||||
if ( (_writesSinceDecrypt > 0) && (_log.shouldLog(Log.DEBUG)) )
|
||||
_log.debug("Bytes left in the encrypted buffer after decrypt: "
|
||||
+ _writesSinceDecrypt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take (n*BLOCK_SIZE) bytes off the _encryptedBuf, decrypt them, and place
|
||||
* them on _readyBuf
|
||||
*
|
||||
* Decrypt the
|
||||
*/
|
||||
private void decrypt() throws IOException {
|
||||
byte encrypted[] = _encryptedBuf.toByteArray();
|
||||
_encryptedBuf.reset();
|
||||
|
||||
if ((encrypted == null) || (encrypted.length <= 0))
|
||||
private void decryptBlock() throws IOException {
|
||||
if (_writesSinceDecrypt != BLOCK_SIZE)
|
||||
throw new IOException("Error decrypting - no data to decrypt");
|
||||
|
||||
if (_decryptedSize != 0)
|
||||
throw new IOException("wtf, decrypted size is not 0? " + _decryptedSize);
|
||||
|
||||
_context.aes().decrypt(_encryptedBuf, 0, _encryptedBuf, 0, _key, _lastBlock, BLOCK_SIZE);
|
||||
DataHelper.xor(_encryptedBuf, 0, _lastBlock, 0, _encryptedBuf, 0, BLOCK_SIZE);
|
||||
int payloadBytes = countBlockPayload(_encryptedBuf, 0);
|
||||
|
||||
int numBlocks = encrypted.length / BLOCK_SIZE;
|
||||
if ((encrypted.length % BLOCK_SIZE) != 0) {
|
||||
// it was flushed / handled off the BLOCK_SIZE segments, so put the excess
|
||||
// back into the _encryptedBuf for later handling
|
||||
int trailing = encrypted.length % BLOCK_SIZE;
|
||||
_encryptedBuf.write(encrypted, encrypted.length - trailing, trailing);
|
||||
byte nencrypted[] = new byte[encrypted.length - trailing];
|
||||
System.arraycopy(encrypted, 0, nencrypted, 0, nencrypted.length);
|
||||
encrypted = nencrypted;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Decrypt got odd segment - " + trailing
|
||||
+ " bytes pushed back for later decryption - corrupted or slow data stream perhaps?");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(encrypted.length + " bytes makes up " + numBlocks + " blocks to decrypt normally");
|
||||
for (int i = 0; i < payloadBytes; i++) {
|
||||
int c = _encryptedBuf[i];
|
||||
if (c <= 0)
|
||||
c += 256;
|
||||
_decryptedBuf[i] = c;
|
||||
}
|
||||
_decryptedSize = payloadBytes;
|
||||
|
||||
byte block[] = new byte[BLOCK_SIZE];
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
System.arraycopy(encrypted, i * BLOCK_SIZE, block, 0, BLOCK_SIZE);
|
||||
byte decrypted[] = _context.AESEngine().decrypt(block, _key, _lastBlock);
|
||||
byte data[] = DataHelper.xor(decrypted, _lastBlock);
|
||||
int cleaned[] = stripPadding(data);
|
||||
for (int j = 0; j < cleaned.length; j++) {
|
||||
if (cleaned[j] <= 0) {
|
||||
cleaned[j] += 256;
|
||||
//_log.error("(modified: " + cleaned[j] + ")");
|
||||
}
|
||||
_readyBuf.add(new Integer(cleaned[j]));
|
||||
}
|
||||
_cumulativePrepared += cleaned.length;
|
||||
//_log.debug("Updating last block for inputStream");
|
||||
System.arraycopy(decrypted, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||
}
|
||||
_cumulativePaddingStripped += BLOCK_SIZE - payloadBytes;
|
||||
_cumulativePrepared += payloadBytes;
|
||||
|
||||
int remaining = encrypted.length % BLOCK_SIZE;
|
||||
if (remaining != 0) {
|
||||
_encryptedBuf.write(encrypted, encrypted.length - remaining, remaining);
|
||||
_log.debug("After pushing " + remaining
|
||||
+ " bytes back onto the buffer, lets delay 1s our action so we don't fast busy until the net transfers data");
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
} else {
|
||||
//_log.debug("No remaining encrypted bytes beyond the block size");
|
||||
}
|
||||
System.arraycopy(_encryptedBuf, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||
|
||||
_writesSinceDecrypt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* How many non-padded bytes are there in the block starting at the given
|
||||
* location.
|
||||
*
|
||||
* PKCS#5 specifies the padding for the block has the # of padding bytes
|
||||
* located in the last byte of the block, and each of the padding bytes are
|
||||
* equal to that value.
|
||||
@@ -275,47 +226,58 @@ public class AESInputStream extends FilterInputStream {
|
||||
*
|
||||
* We use 16 byte blocks in this AES implementation
|
||||
*
|
||||
* @throws IOException if the padding is invalid
|
||||
*/
|
||||
private int[] stripPadding(byte data[]) throws IOException {
|
||||
int numPadBytes = data[data.length - 1];
|
||||
if ((numPadBytes >= data.length) || (numPadBytes <= 0)) {
|
||||
private int countBlockPayload(byte data[], int startIndex) throws IOException {
|
||||
int numPadBytes = data[startIndex + BLOCK_SIZE - 1];
|
||||
if ((numPadBytes >= BLOCK_SIZE) || (numPadBytes <= 0)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("stripPadding from block " + DataHelper.toHexString(data) + " (" + data.length + "bytes): "
|
||||
_log.debug("countBlockPayload on block index " + startIndex
|
||||
+ numPadBytes + " is an invalid # of pad bytes");
|
||||
throw new IOException("Invalid number of pad bytes (" + numPadBytes
|
||||
+ ") for " + data.length + " bytes");
|
||||
+ ") for " + startIndex + " index");
|
||||
}
|
||||
|
||||
int rv[] = new int[data.length - numPadBytes];
|
||||
// optional, but a really good idea: verify the padding
|
||||
if (true) {
|
||||
for (int i = data.length - numPadBytes; i < data.length; i++) {
|
||||
if (data[i] != (byte) numPadBytes) {
|
||||
for (int i = BLOCK_SIZE - numPadBytes; i < BLOCK_SIZE; i++) {
|
||||
if (data[startIndex + i] != (byte) numPadBytes) {
|
||||
throw new IOException("Incorrect padding on decryption: data[" + i
|
||||
+ "] = " + data[i] + " not " + numPadBytes);
|
||||
+ "] = " + data[startIndex + i] + " not " + numPadBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < rv.length; i++)
|
||||
rv[i] = data[i];
|
||||
_cumulativePaddingStripped += numPadBytes;
|
||||
return rv;
|
||||
|
||||
return BLOCK_SIZE - numPadBytes;
|
||||
}
|
||||
|
||||
int remainingBytes() {
|
||||
return _encryptedBuf.size();
|
||||
return _writesSinceDecrypt;
|
||||
}
|
||||
|
||||
int readyBytes() {
|
||||
return _readyBuf.size();
|
||||
return _decryptedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test AESOutputStream/AESInputStream
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
public static void main(String args[]) {
|
||||
I2PAppContext ctx = new I2PAppContext();
|
||||
|
||||
try {
|
||||
System.out.println("pwd=" + new java.io.File(".").getAbsolutePath());
|
||||
System.out.println("Beginning");
|
||||
runTest(ctx);
|
||||
} catch (Throwable e) {
|
||||
ctx.logManager().getLog(AESInputStream.class).error("Fail", e);
|
||||
}
|
||||
try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
|
||||
System.out.println("Done");
|
||||
}
|
||||
private static void runTest(I2PAppContext ctx) {
|
||||
Log log = ctx.logManager().getLog(AESInputStream.class);
|
||||
log.setMinimumPriority(Log.DEBUG);
|
||||
byte orig[] = new byte[1024 * 32];
|
||||
RandomSource.getInstance().nextBytes(orig);
|
||||
//byte orig[] = "you are my sunshine, my only sunshine".getBytes();
|
||||
@@ -351,10 +313,51 @@ public class AESInputStream extends FilterInputStream {
|
||||
}
|
||||
|
||||
log.info("Done testing 0 byte data");
|
||||
|
||||
for (int i = 0; i <= 32768; i++) {
|
||||
orig = new byte[i];
|
||||
ctx.random().nextBytes(orig);
|
||||
try {
|
||||
log.info("Testing " + orig.length);
|
||||
runTest(ctx, orig, key, iv);
|
||||
} catch (RuntimeException re) {
|
||||
log.error("Error testing " + orig.length);
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
orig = new byte[615280];
|
||||
|
||||
RandomSource.getInstance().nextBytes(orig);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
runTest(ctx, orig, key, iv);
|
||||
}
|
||||
|
||||
log.info("Done testing 615280 byte data");
|
||||
*/
|
||||
/*
|
||||
for (int i = 0; i < 100; i++) {
|
||||
orig = new byte[ctx.random().nextInt(1024*1024)];
|
||||
ctx.random().nextBytes(orig);
|
||||
try {
|
||||
runTest(ctx, orig, key, iv);
|
||||
} catch (RuntimeException re) {
|
||||
log.error("Error testing " + orig.length);
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Done testing 100 random lengths");
|
||||
*/
|
||||
|
||||
orig = new byte[32];
|
||||
RandomSource.getInstance().nextBytes(orig);
|
||||
runOffsetTest(ctx, orig, key, iv);
|
||||
try {
|
||||
runOffsetTest(ctx, orig, key, iv);
|
||||
} catch (Exception e) {
|
||||
log.info("Error running offset test", e);
|
||||
}
|
||||
|
||||
log.info("Done testing offset test (it should have come back with a statement NOT EQUAL!)");
|
||||
|
||||
@@ -377,30 +380,33 @@ public class AESInputStream extends FilterInputStream {
|
||||
long endE = Clock.getInstance().now();
|
||||
|
||||
ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encrypted);
|
||||
AESInputStream in = new AESInputStream(ctx, encryptedStream, key, iv);
|
||||
AESInputStream sin = new AESInputStream(ctx, encryptedStream, key, iv);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
|
||||
byte buf[] = new byte[1024 * 32];
|
||||
int read = DataHelper.read(in, buf);
|
||||
int read = DataHelper.read(sin, buf);
|
||||
if (read > 0) baos.write(buf, 0, read);
|
||||
in.close();
|
||||
sin.close();
|
||||
byte fin[] = baos.toByteArray();
|
||||
long end = Clock.getInstance().now();
|
||||
Hash origHash = SHA256Generator.getInstance().calculateHash(orig);
|
||||
|
||||
Hash newHash = SHA256Generator.getInstance().calculateHash(fin);
|
||||
boolean eq = origHash.equals(newHash);
|
||||
if (eq)
|
||||
log.info("Equal hashes. hash: " + origHash);
|
||||
else
|
||||
log.error("NOT EQUAL! \norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin));
|
||||
if (eq) {
|
||||
//log.info("Equal hashes. hash: " + origHash);
|
||||
} else {
|
||||
throw new RuntimeException("NOT EQUAL! len=" + orig.length + " read=" + read
|
||||
+ "\norig: \t" + Base64.encode(orig) + "\nnew : \t"
|
||||
+ Base64.encode(fin));
|
||||
}
|
||||
boolean ok = DataHelper.eq(orig, fin);
|
||||
log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length);
|
||||
log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms");
|
||||
log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms");
|
||||
log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms");
|
||||
|
||||
} catch (Throwable t) {
|
||||
log.error("ERROR transferring", t);
|
||||
} catch (IOException ioe) {
|
||||
log.error("ERROR transferring", ioe);
|
||||
}
|
||||
//try { Thread.sleep(5000); } catch (Throwable t) {}
|
||||
}
|
||||
@@ -422,15 +428,15 @@ public class AESInputStream extends FilterInputStream {
|
||||
System.arraycopy(encrypted, 0, encryptedSegment, 0, 40);
|
||||
|
||||
ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encryptedSegment);
|
||||
AESInputStream in = new AESInputStream(ctx, encryptedStream, key, iv);
|
||||
AESInputStream sin = new AESInputStream(ctx, encryptedStream, key, iv);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
|
||||
byte buf[] = new byte[1024 * 32];
|
||||
int read = DataHelper.read(in, buf);
|
||||
int remaining = in.remainingBytes();
|
||||
int readyBytes = in.readyBytes();
|
||||
int read = DataHelper.read(sin, buf);
|
||||
int remaining = sin.remainingBytes();
|
||||
int readyBytes = sin.readyBytes();
|
||||
log.info("Read: " + read);
|
||||
if (read > 0) baos.write(buf, 0, read);
|
||||
in.close();
|
||||
sin.close();
|
||||
byte fin[] = baos.toByteArray();
|
||||
log.info("fin.length: " + fin.length + " remaining: " + remaining + " ready: " + readyBytes);
|
||||
long end = Clock.getInstance().now();
|
||||
@@ -441,15 +447,16 @@ public class AESInputStream extends FilterInputStream {
|
||||
if (eq)
|
||||
log.info("Equal hashes. hash: " + origHash);
|
||||
else
|
||||
log.error("NOT EQUAL! \norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin));
|
||||
throw new RuntimeException("NOT EQUAL! len=" + orig.length + "\norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin));
|
||||
boolean ok = DataHelper.eq(orig, fin);
|
||||
log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length);
|
||||
log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms");
|
||||
log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms");
|
||||
log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms");
|
||||
|
||||
} catch (Throwable t) {
|
||||
log.error("ERROR transferring", t);
|
||||
} catch (RuntimeException re) {
|
||||
throw re;
|
||||
} catch (IOException ioe) {
|
||||
log.error("ERROR transferring", ioe);
|
||||
}
|
||||
//try { Thread.sleep(5000); } catch (Throwable t) {}
|
||||
}
|
||||
|
@@ -34,7 +34,15 @@ public class AESOutputStream extends FilterOutputStream {
|
||||
private I2PAppContext _context;
|
||||
private SessionKey _key;
|
||||
private byte[] _lastBlock;
|
||||
private ByteArrayOutputStream _inBuf;
|
||||
/**
|
||||
* buffer containing the unwritten bytes. The first unwritten
|
||||
* byte is _lastCommitted+1, and the last unwritten byte is _nextWrite-1
|
||||
* (aka the next byte to be written on the array is _nextWrite)
|
||||
*/
|
||||
private byte[] _unencryptedBuf;
|
||||
private byte _writeBlock[];
|
||||
/** how many bytes have we been given since we flushed it to the stream? */
|
||||
private int _writesSinceCommit;
|
||||
private long _cumulativeProvided; // how many bytes provided to this stream
|
||||
private long _cumulativeWritten; // how many bytes written to the underlying stream
|
||||
private long _cumulativePadding; // how many bytes of padding written
|
||||
@@ -51,31 +59,32 @@ public class AESOutputStream extends FilterOutputStream {
|
||||
_key = key;
|
||||
_lastBlock = new byte[BLOCK_SIZE];
|
||||
System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||
_inBuf = new ByteArrayOutputStream(MAX_BUF);
|
||||
_unencryptedBuf = new byte[MAX_BUF];
|
||||
_writeBlock = new byte[BLOCK_SIZE];
|
||||
_writesSinceCommit = 0;
|
||||
}
|
||||
|
||||
public void write(int val) throws IOException {
|
||||
_cumulativeProvided++;
|
||||
_inBuf.write(val);
|
||||
if (_inBuf.size() > MAX_BUF) doFlush();
|
||||
_unencryptedBuf[_writesSinceCommit++] = (byte)(val & 0xFF);
|
||||
if (_writesSinceCommit == _unencryptedBuf.length)
|
||||
doFlush();
|
||||
}
|
||||
|
||||
public void write(byte src[]) throws IOException {
|
||||
_cumulativeProvided += src.length;
|
||||
_inBuf.write(src);
|
||||
if (_inBuf.size() > MAX_BUF) doFlush();
|
||||
write(src, 0, src.length);
|
||||
}
|
||||
|
||||
public void write(byte src[], int off, int len) throws IOException {
|
||||
_cumulativeProvided += len;
|
||||
_inBuf.write(src, off, len);
|
||||
if (_inBuf.size() > MAX_BUF) doFlush();
|
||||
// i'm too lazy to unroll this into the partial writes (dealing with
|
||||
// wrapping around the buffer size)
|
||||
for (int i = 0; i < len; i++)
|
||||
write(src[i+off]);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
flush();
|
||||
out.close();
|
||||
_inBuf.reset();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Cumulative bytes provided to this stream / written out / padded: "
|
||||
+ _cumulativeProvided + "/" + _cumulativeWritten + "/" + _cumulativePadding);
|
||||
@@ -87,8 +96,10 @@ public class AESOutputStream extends FilterOutputStream {
|
||||
}
|
||||
|
||||
private void doFlush() throws IOException {
|
||||
writeEncrypted(_inBuf.toByteArray());
|
||||
_inBuf.reset();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("doFlush(): writesSinceCommit=" + _writesSinceCommit);
|
||||
writeEncrypted();
|
||||
_writesSinceCommit = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,41 +112,37 @@ public class AESOutputStream extends FilterOutputStream {
|
||||
* times).
|
||||
*
|
||||
*/
|
||||
private void writeEncrypted(byte src[]) throws IOException {
|
||||
if ((src == null) || (src.length == 0)) return;
|
||||
int numBlocks = src.length / (BLOCK_SIZE - 1);
|
||||
private void writeEncrypted() throws IOException {
|
||||
int numBlocks = _writesSinceCommit / (BLOCK_SIZE - 1);
|
||||
|
||||
byte block[] = new byte[BLOCK_SIZE];
|
||||
block[BLOCK_SIZE - 1] = 0x01; // the padding byte for "full" blocks
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("writeE(): #=" + _writesSinceCommit + " blocks=" + numBlocks);
|
||||
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
System.arraycopy(src, i * 15, block, 0, 15);
|
||||
byte data[] = DataHelper.xor(block, _lastBlock);
|
||||
byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock);
|
||||
_cumulativeWritten += encrypted.length;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Padding block " + i + " of " + numBlocks + " with 1 byte. orig= "
|
||||
+ DataHelper.toHexString(data) + " (size=" + data.length + ") encrypted= "
|
||||
+ DataHelper.toHexString(encrypted) + " (size=" + encrypted.length + ")");
|
||||
out.write(encrypted);
|
||||
System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE);
|
||||
DataHelper.xor(_unencryptedBuf, i * 15, _lastBlock, 0, _writeBlock, 0, 15);
|
||||
// the padding byte for "full" blocks
|
||||
_writeBlock[BLOCK_SIZE - 1] = (byte)(_lastBlock[BLOCK_SIZE - 1] ^ 0x01);
|
||||
_context.aes().encrypt(_writeBlock, 0, _writeBlock, 0, _key, _lastBlock, BLOCK_SIZE);
|
||||
out.write(_writeBlock);
|
||||
System.arraycopy(_writeBlock, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||
_cumulativeWritten += BLOCK_SIZE;
|
||||
_cumulativePadding++;
|
||||
}
|
||||
|
||||
if (src.length % 15 != 0) {
|
||||
if (_writesSinceCommit % 15 != 0) {
|
||||
// we need to do non trivial padding
|
||||
int remainingBytes = src.length - numBlocks * 15;
|
||||
int remainingBytes = _writesSinceCommit - numBlocks * 15;
|
||||
int paddingBytes = BLOCK_SIZE - remainingBytes;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Padding " + src.length + " with " + paddingBytes + " bytes in " + numBlocks + " blocks");
|
||||
System.arraycopy(src, numBlocks * 15, block, 0, remainingBytes);
|
||||
Arrays.fill(block, remainingBytes, BLOCK_SIZE, (byte) paddingBytes);
|
||||
byte data[] = DataHelper.xor(block, _lastBlock);
|
||||
byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock);
|
||||
out.write(encrypted);
|
||||
System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE);
|
||||
_log.debug("Padding " + _writesSinceCommit + " with " + paddingBytes + " bytes in " + (numBlocks+1) + " blocks");
|
||||
System.arraycopy(_unencryptedBuf, numBlocks * 15, _writeBlock, 0, remainingBytes);
|
||||
Arrays.fill(_writeBlock, remainingBytes, BLOCK_SIZE, (byte) paddingBytes);
|
||||
DataHelper.xor(_writeBlock, 0, _lastBlock, 0, _writeBlock, 0, BLOCK_SIZE);
|
||||
_context.aes().encrypt(_writeBlock, 0, _writeBlock, 0, _key, _lastBlock, BLOCK_SIZE);
|
||||
out.write(_writeBlock);
|
||||
System.arraycopy(_writeBlock, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||
_cumulativePadding += paddingBytes;
|
||||
_cumulativeWritten += encrypted.length;
|
||||
_cumulativeWritten += BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -12,6 +12,7 @@ package net.i2p.crypto;
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -33,104 +34,63 @@ public class CryptixAESEngine extends AESEngine {
|
||||
super(context);
|
||||
_log = context.logManager().getLog(CryptixAESEngine.class);
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) {
|
||||
if ((initializationVector == null) || (payload == null) || (payload.length <= 0) || (sessionKey == null)
|
||||
|| (initializationVector.length != 16)) return null;
|
||||
|
||||
public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) {
|
||||
if ( (payload == null) || (out == null) || (sessionKey == null) || (iv == null) || (iv.length != 16) )
|
||||
throw new NullPointerException("invalid args to aes");
|
||||
if (payload.length < payloadIndex + length)
|
||||
throw new IllegalArgumentException("Payload is too short");
|
||||
if (out.length < outIndex + length)
|
||||
throw new IllegalArgumentException("Output is too short");
|
||||
if (length <= 0)
|
||||
throw new IllegalArgumentException("Length is too small");
|
||||
if (length % 16 != 0)
|
||||
throw new IllegalArgumentException("Only lengths mod 16 are supported here");
|
||||
|
||||
if (USE_FAKE_CRYPTO) {
|
||||
_log.warn("AES Crypto disabled! Using trivial XOR");
|
||||
byte rv[] = new byte[payload.length];
|
||||
for (int i = 0; i < rv.length; i++)
|
||||
rv[i] = (byte) (payload[i] ^ FAKE_KEY);
|
||||
return rv;
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
return;
|
||||
}
|
||||
|
||||
int numblock = length / 16;
|
||||
|
||||
DataHelper.xor(iv, 0, payload, payloadIndex, out, outIndex, 16);
|
||||
encryptBlock(out, outIndex, sessionKey, out, outIndex);
|
||||
for (int x = 1; x < numblock; x++) {
|
||||
DataHelper.xor(out, outIndex + (x-1) * 16, payload, payloadIndex + x * 16, out, outIndex + x * 16, 16);
|
||||
encryptBlock(out, outIndex + x * 16, sessionKey, out, outIndex + x * 16);
|
||||
}
|
||||
}
|
||||
|
||||
public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) {
|
||||
if ((iv== null) || (payload == null) || (payload.length <= 0) || (sessionKey == null)
|
||||
|| (iv.length != 16))
|
||||
throw new IllegalArgumentException("bad setup");
|
||||
|
||||
if (USE_FAKE_CRYPTO) {
|
||||
_log.warn("AES Crypto disabled! Using trivial XOR");
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
return ;
|
||||
}
|
||||
|
||||
int numblock = payload.length / 16;
|
||||
if (payload.length % 16 != 0) numblock++;
|
||||
byte[][] plain = new byte[numblock][16];
|
||||
for (int x = 0; x < numblock; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
plain[x][y] = payload[x * 16 + y];
|
||||
}
|
||||
}
|
||||
|
||||
byte[][] cipher = new byte[numblock][16];
|
||||
cipher[0] = encrypt(xor(initializationVector, plain[0]), sessionKey);
|
||||
decryptBlock(payload, 0, sessionKey, out, 0);
|
||||
DataHelper.xor(out, 0, iv, 0, out, 0, 16);
|
||||
for (int x = 1; x < numblock; x++) {
|
||||
cipher[x] = encrypt(xor(cipher[x - 1], plain[x]), sessionKey);
|
||||
decryptBlock(payload, x * 16, sessionKey, out, x * 16);
|
||||
DataHelper.xor(out, x * 16, payload, (x - 1) * 16, out, x * 16, 16);
|
||||
}
|
||||
|
||||
byte[] ret = new byte[numblock * 16];
|
||||
for (int x = 0; x < numblock; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
ret[x * 16 + y] = cipher[x][y];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) {
|
||||
if ((initializationVector == null) || (payload == null) || (payload.length <= 0) || (sessionKey == null)
|
||||
|| (initializationVector.length != 16)) return null;
|
||||
|
||||
if (USE_FAKE_CRYPTO) {
|
||||
_log.warn("AES Crypto disabled! Using trivial XOR");
|
||||
byte rv[] = new byte[payload.length];
|
||||
for (int i = 0; i < rv.length; i++)
|
||||
rv[i] = (byte) (payload[i] ^ FAKE_KEY);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int numblock = payload.length / 16;
|
||||
if (payload.length % 16 != 0) numblock++;
|
||||
byte[][] cipher = new byte[numblock][16];
|
||||
for (int x = 0; x < numblock; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
cipher[x][y] = payload[x * 16 + y];
|
||||
}
|
||||
}
|
||||
|
||||
byte[][] plain = new byte[numblock][16];
|
||||
plain[0] = xor(decrypt(cipher[0], sessionKey), initializationVector);
|
||||
for (int x = 1; x < numblock; x++) {
|
||||
plain[x] = xor(decrypt(cipher[x], sessionKey), cipher[x - 1]);
|
||||
}
|
||||
|
||||
byte[] ret = new byte[numblock * 16];
|
||||
for (int x = 0; x < numblock; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
ret[x * 16 + y] = plain[x][y];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
final static byte[] xor(byte[] a, byte[] b) {
|
||||
if ((a == null) || (b == null) || (a.length != b.length)) return null;
|
||||
byte[] ret = new byte[a.length];
|
||||
for (int x = 0; x < a.length; x++) {
|
||||
ret[x] = (byte) (a[x] ^ b[x]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Encrypt the payload with the session key
|
||||
* @param payload data to be encrypted
|
||||
* @param sessionKey private esession key to encrypt to
|
||||
* @return encrypted data
|
||||
*/
|
||||
final byte[] encrypt(byte payload[], SessionKey sessionKey) {
|
||||
final void encryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte out[], int outIndex) {
|
||||
try {
|
||||
Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16);
|
||||
byte rv[] = new byte[payload.length];
|
||||
CryptixRijndael_Algorithm.blockEncrypt(payload, rv, 0, key, 16);
|
||||
return rv;
|
||||
CryptixRijndael_Algorithm.blockEncrypt(payload, out, inIndex, outIndex, key, 16);
|
||||
} catch (InvalidKeyException ike) {
|
||||
_log.error("Invalid key", ike);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,15 +99,55 @@ public class CryptixAESEngine extends AESEngine {
|
||||
* @param sessionKey private session key
|
||||
* @return unencrypted data
|
||||
*/
|
||||
final byte[] decrypt(byte payload[], SessionKey sessionKey) {
|
||||
final void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) {
|
||||
try {
|
||||
Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16);
|
||||
byte rv[] = new byte[payload.length];
|
||||
CryptixRijndael_Algorithm.blockDecrypt(payload, rv, 0, key, 16);
|
||||
return rv;
|
||||
CryptixRijndael_Algorithm.blockDecrypt(payload, rv, inIndex, outIndex, key, 16);
|
||||
} catch (InvalidKeyException ike) {
|
||||
_log.error("Invalid key", ike);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
I2PAppContext ctx = new I2PAppContext();
|
||||
try {
|
||||
testEDBlock(ctx);
|
||||
testED(ctx);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
private static void testED(I2PAppContext ctx) {
|
||||
SessionKey key = ctx.keyGenerator().generateSessionKey();
|
||||
byte iv[] = new byte[16];
|
||||
byte orig[] = new byte[128];
|
||||
byte encrypted[] = new byte[128];
|
||||
byte decrypted[] = new byte[128];
|
||||
ctx.random().nextBytes(iv);
|
||||
ctx.random().nextBytes(orig);
|
||||
CryptixAESEngine aes = new CryptixAESEngine(ctx);
|
||||
aes.encrypt(orig, 0, encrypted, 0, key, iv, orig.length);
|
||||
aes.decrypt(encrypted, 0, decrypted, 0, key, iv, encrypted.length);
|
||||
if (!DataHelper.eq(decrypted,orig))
|
||||
throw new RuntimeException("full D(E(orig)) != orig");
|
||||
else
|
||||
System.out.println("full D(E(orig)) == orig");
|
||||
}
|
||||
private static void testEDBlock(I2PAppContext ctx) {
|
||||
SessionKey key = ctx.keyGenerator().generateSessionKey();
|
||||
byte iv[] = new byte[16];
|
||||
byte orig[] = new byte[16];
|
||||
byte encrypted[] = new byte[16];
|
||||
byte decrypted[] = new byte[16];
|
||||
ctx.random().nextBytes(iv);
|
||||
ctx.random().nextBytes(orig);
|
||||
CryptixAESEngine aes = new CryptixAESEngine(ctx);
|
||||
aes.encryptBlock(orig, 0, key, encrypted, 0);
|
||||
aes.decryptBlock(encrypted, 0, key, decrypted, 0);
|
||||
if (!DataHelper.eq(decrypted,orig))
|
||||
throw new RuntimeException("block D(E(orig)) != orig");
|
||||
else
|
||||
System.out.println("block D(E(orig)) == orig");
|
||||
}
|
||||
}
|
@@ -382,7 +382,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
* @param inOffset Index of in from which to start considering data.
|
||||
* @param sessionKey The session key to use for encryption.
|
||||
*/
|
||||
public static final void blockEncrypt(byte[] in, byte[] result, int inOffset, Object sessionKey) {
|
||||
public static final void blockEncrypt(byte[] in, byte[] result, int inOffset, int outOffset, Object sessionKey) {
|
||||
if (_RDEBUG) trace(_IN, "blockEncrypt(" + in + ", " + inOffset + ", " + sessionKey + ")");
|
||||
int[][] Ke = (int[][]) ((Object[]) sessionKey)[0]; // extract encryption round keys
|
||||
int ROUNDS = Ke.length - 1;
|
||||
@@ -417,25 +417,25 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
// last round is special
|
||||
Ker = Ke[ROUNDS];
|
||||
int tt = Ker[0];
|
||||
result[0] = (byte) (_S[(t0 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[1] = (byte) (_S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[2] = (byte) (_S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[3] = (byte) (_S[t3 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_S[(t0 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_S[t3 & 0xFF] ^ tt);
|
||||
tt = Ker[1];
|
||||
result[4] = (byte) (_S[(t1 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[5] = (byte) (_S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[6] = (byte) (_S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[7] = (byte) (_S[t0 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_S[(t1 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_S[t0 & 0xFF] ^ tt);
|
||||
tt = Ker[2];
|
||||
result[8] = (byte) (_S[(t2 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[9] = (byte) (_S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[10] = (byte) (_S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[11] = (byte) (_S[t1 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_S[(t2 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_S[t1 & 0xFF] ^ tt);
|
||||
tt = Ker[3];
|
||||
result[12] = (byte) (_S[(t3 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[13] = (byte) (_S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[14] = (byte) (_S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[15] = (byte) (_S[t2 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_S[(t3 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_S[t2 & 0xFF] ^ tt);
|
||||
if (_RDEBUG && _debuglevel > 6) {
|
||||
System.out.println("CT=" + toString(result));
|
||||
System.out.println();
|
||||
@@ -452,7 +452,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
* @param inOffset Index of in from which to start considering data.
|
||||
* @param sessionKey The session key to use for decryption.
|
||||
*/
|
||||
public static final void blockDecrypt(byte[] in, byte[] result, int inOffset, Object sessionKey) {
|
||||
public static final void blockDecrypt(byte[] in, byte[] result, int inOffset, int outOffset, Object sessionKey) {
|
||||
if (_RDEBUG) trace(_IN, "blockDecrypt(" + in + ", " + inOffset + ", " + sessionKey + ")");
|
||||
int[][] Kd = (int[][]) ((Object[]) sessionKey)[1]; // extract decryption round keys
|
||||
int ROUNDS = Kd.length - 1;
|
||||
@@ -487,25 +487,25 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
// last round is special
|
||||
Kdr = Kd[ROUNDS];
|
||||
int tt = Kdr[0];
|
||||
result[0] = (byte) (_Si[(t0 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[1] = (byte) (_Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[2] = (byte) (_Si[(t2 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[3] = (byte) (_Si[t1 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_Si[(t0 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_Si[(t2 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_Si[t1 & 0xFF] ^ tt);
|
||||
tt = Kdr[1];
|
||||
result[4] = (byte) (_Si[(t1 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[5] = (byte) (_Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[6] = (byte) (_Si[(t3 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[7] = (byte) (_Si[t2 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_Si[(t1 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_Si[(t3 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_Si[t2 & 0xFF] ^ tt);
|
||||
tt = Kdr[2];
|
||||
result[8] = (byte) (_Si[(t2 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[9] = (byte) (_Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[10] = (byte) (_Si[(t0 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[11] = (byte) (_Si[t3 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_Si[(t2 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_Si[(t0 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_Si[t3 & 0xFF] ^ tt);
|
||||
tt = Kdr[3];
|
||||
result[12] = (byte) (_Si[(t3 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[13] = (byte) (_Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[14] = (byte) (_Si[(t1 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[15] = (byte) (_Si[t0 & 0xFF] ^ tt);
|
||||
result[outOffset++] = (byte) (_Si[(t3 >>> 24) & 0xFF] ^ (tt >>> 24));
|
||||
result[outOffset++] = (byte) (_Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
|
||||
result[outOffset++] = (byte) (_Si[(t1 >>> 8) & 0xFF] ^ (tt >>> 8));
|
||||
result[outOffset++] = (byte) (_Si[t0 & 0xFF] ^ tt);
|
||||
if (_RDEBUG && _debuglevel > 6) {
|
||||
System.out.println("PT=" + toString(result));
|
||||
System.out.println();
|
||||
@@ -618,9 +618,9 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
* @param sessionKey The session key to use for encryption.
|
||||
* @param blockSize The block size in bytes of this Rijndael.
|
||||
*/
|
||||
public static final void blockEncrypt(byte[] in, byte[] result, int inOffset, Object sessionKey, int blockSize) {
|
||||
public static final void blockEncrypt(byte[] in, byte[] result, int inOffset, int outOffset, Object sessionKey, int blockSize) {
|
||||
if (blockSize == _BLOCK_SIZE) {
|
||||
blockEncrypt(in, result, inOffset, sessionKey);
|
||||
blockEncrypt(in, result, inOffset, outOffset, sessionKey);
|
||||
return;
|
||||
}
|
||||
if (_RDEBUG) trace(_IN, "blockEncrypt(" + in + ", " + inOffset + ", " + sessionKey + ", " + blockSize + ")");
|
||||
@@ -636,7 +636,8 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
int[] a = new int[BC];
|
||||
int[] t = new int[BC]; // temporary work array
|
||||
int i;
|
||||
int j = 0, tt;
|
||||
int j = outOffset;
|
||||
int tt;
|
||||
|
||||
for (i = 0; i < BC; i++)
|
||||
// plaintext to ints + key
|
||||
@@ -673,9 +674,9 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
* @param sessionKey The session key to use for decryption.
|
||||
* @param blockSize The block size in bytes of this Rijndael.
|
||||
*/
|
||||
public static final void blockDecrypt(byte[] in, byte[] result, int inOffset, Object sessionKey, int blockSize) {
|
||||
public static final void blockDecrypt(byte[] in, byte[] result, int inOffset, int outOffset, Object sessionKey, int blockSize) {
|
||||
if (blockSize == _BLOCK_SIZE) {
|
||||
blockDecrypt(in, result, inOffset, sessionKey);
|
||||
blockDecrypt(in, result, inOffset, outOffset, sessionKey);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -692,7 +693,8 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
int[] a = new int[BC];
|
||||
int[] t = new int[BC]; // temporary work array
|
||||
int i;
|
||||
int j = 0, tt;
|
||||
int j = outOffset;
|
||||
int tt;
|
||||
|
||||
for (i = 0; i < BC; i++)
|
||||
// ciphertext to ints + key
|
||||
@@ -749,7 +751,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
System.out.println("PT=" + toString(pt));
|
||||
}
|
||||
byte[] ct = new byte[_BLOCK_SIZE];
|
||||
blockEncrypt(pt, ct, 0, key, _BLOCK_SIZE);
|
||||
blockEncrypt(pt, ct, 0, 0, key, _BLOCK_SIZE);
|
||||
|
||||
if (_RDEBUG && _debuglevel > 6) {
|
||||
System.out.println("Intermediate Plaintext Values (Decryption)");
|
||||
@@ -757,7 +759,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
|
||||
System.out.println("CT=" + toString(ct));
|
||||
}
|
||||
byte[] cpt = new byte[_BLOCK_SIZE];
|
||||
blockDecrypt(ct, cpt, 0, key, _BLOCK_SIZE);
|
||||
blockDecrypt(ct, cpt, 0, 0, key, _BLOCK_SIZE);
|
||||
|
||||
ok = areEqual(pt, cpt);
|
||||
if (!ok) throw new RuntimeException("Symmetric operation failed");
|
||||
|
@@ -13,8 +13,13 @@ import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
@@ -135,7 +140,62 @@ public class DHSessionKeyBuilder {
|
||||
_sessionKey = null;
|
||||
_extraExchangedBytes = new ByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Conduct a DH exchange over the streams, returning the resulting data.
|
||||
*
|
||||
* @return exchanged data
|
||||
* @throws IOException if there is an error (but does not close the streams
|
||||
*/
|
||||
public static DHSessionKeyBuilder exchangeKeys(InputStream in, OutputStream out) throws IOException {
|
||||
DHSessionKeyBuilder builder = new DHSessionKeyBuilder();
|
||||
|
||||
// send: X
|
||||
writeBigI(out, builder.getMyPublicValue());
|
||||
|
||||
// read: Y
|
||||
BigInteger Y = readBigI(in);
|
||||
if (Y == null) return null;
|
||||
builder.setPeerPublicValue(Y);
|
||||
return builder;
|
||||
}
|
||||
|
||||
static BigInteger readBigI(InputStream in) throws IOException {
|
||||
byte Y[] = new byte[256];
|
||||
int read = DataHelper.read(in, Y);
|
||||
if (read != 256) {
|
||||
return null;
|
||||
}
|
||||
if (1 == (Y[0] & 0x80)) {
|
||||
// high bit set, need to inject an additional byte to keep 2s complement
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("High bit set");
|
||||
byte Y2[] = new byte[257];
|
||||
System.arraycopy(Y, 0, Y2, 1, 256);
|
||||
Y = Y2;
|
||||
}
|
||||
return new NativeBigInteger(Y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the integer as a 256 byte value. This left pads with 0s so
|
||||
* to keep in 2s complement, and if it is already 257 bytes (due to
|
||||
* the sign bit) ignore that first byte.
|
||||
*/
|
||||
static void writeBigI(OutputStream out, BigInteger val) throws IOException {
|
||||
byte x[] = val.toByteArray();
|
||||
for (int i = x.length; i < 256; i++)
|
||||
out.write(0);
|
||||
if (x.length == 257)
|
||||
out.write(x, 1, 256);
|
||||
else if (x.length == 256)
|
||||
out.write(x);
|
||||
else if (x.length > 257)
|
||||
throw new IllegalArgumentException("Value is too large! length="+x.length);
|
||||
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private static final int getSize() {
|
||||
synchronized (_builders) {
|
||||
return _builders.size();
|
||||
@@ -292,8 +352,10 @@ public class DHSessionKeyBuilder {
|
||||
byte iv[] = new byte[16];
|
||||
RandomSource.getInstance().nextBytes(iv);
|
||||
String origVal = "1234567890123456"; // 16 bytes max using AESEngine
|
||||
byte enc[] = ctx.AESEngine().encrypt(origVal.getBytes(), key1, iv);
|
||||
byte dec[] = ctx.AESEngine().decrypt(enc, key2, iv);
|
||||
byte enc[] = new byte[16];
|
||||
byte dec[] = new byte[16];
|
||||
ctx.aes().encrypt(origVal.getBytes(), 0, enc, 0, key1, iv, 16);
|
||||
ctx.aes().decrypt(enc, 0, dec, 0, key2, iv, 16);
|
||||
String tranVal = new String(dec);
|
||||
if (origVal.equals(tranVal))
|
||||
_log.debug("**Success: D(E(val)) == val");
|
||||
|
@@ -248,7 +248,8 @@ public class ElGamalAESEngine {
|
||||
SessionKey foundKey) throws DataFormatException {
|
||||
//_log.debug("iv for decryption: " + DataHelper.toString(iv, 16));
|
||||
//_log.debug("decrypting AES block. encr.length = " + (encrypted == null? -1 : encrypted.length) + " sentTag: " + DataHelper.toString(sentTag, 32));
|
||||
byte decrypted[] = _context.AESEngine().decrypt(encrypted, key, iv);
|
||||
byte decrypted[] = new byte[encrypted.length];
|
||||
_context.aes().decrypt(encrypted, 0, decrypted, 0, key, iv, encrypted.length);
|
||||
//Hash h = _context.sha().calculateHash(decrypted);
|
||||
//_log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32));
|
||||
try {
|
||||
@@ -503,7 +504,8 @@ public class ElGamalAESEngine {
|
||||
byte aesUnencr[] = aesSrc.toByteArray();
|
||||
//Hash h = _context.sha().calculateHash(aesUnencr);
|
||||
//_log.debug("Hash of entire aes block before encryption: (len=" + aesUnencr.length + ")\n" + DataHelper.toString(h.getData(), 32));
|
||||
byte aesEncr[] = _context.AESEngine().encrypt(aesUnencr, key, iv);
|
||||
byte aesEncr[] = new byte[aesUnencr.length];
|
||||
_context.aes().encrypt(aesUnencr, 0, aesEncr, 0, key, iv, aesEncr.length);
|
||||
//_log.debug("Encrypted length: " + aesEncr.length);
|
||||
return aesEncr;
|
||||
} catch (IOException ioe) {
|
||||
|
@@ -62,40 +62,43 @@ public class SHA256Generator {
|
||||
* @return hash of the source
|
||||
*/
|
||||
public Hash calculateHash(byte[] source) {
|
||||
long length = source.length * 8;
|
||||
return calculateHash(source, 0, source.length);
|
||||
}
|
||||
public Hash calculateHash(byte[] source, int start, int len) {
|
||||
long length = len * 8;
|
||||
int k = 448 - (int) ((length + 1) % 512);
|
||||
if (k < 0) {
|
||||
k += 512;
|
||||
}
|
||||
int padbytes = k / 8;
|
||||
int wordlength = source.length / 4 + padbytes / 4 + 3;
|
||||
int wordlength = len / 4 + padbytes / 4 + 3;
|
||||
int[] M0 = new int[wordlength];
|
||||
int wordcount = 0;
|
||||
int x = 0;
|
||||
for (x = 0; x < (source.length / 4) * 4; x += 4) {
|
||||
M0[wordcount] = source[x] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[x + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] |= source[x + 2] << 24 >>> 24 << 8;
|
||||
M0[wordcount] |= source[x + 3] << 24 >>> 24 << 0;
|
||||
for (x = 0; x < (len / 4) * 4; x += 4) {
|
||||
M0[wordcount] = source[x+start] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[x+start + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] |= source[x+start + 2] << 24 >>> 24 << 8;
|
||||
M0[wordcount] |= source[x+start + 3] << 24 >>> 24 << 0;
|
||||
wordcount++;
|
||||
}
|
||||
switch (source.length - (wordcount + 1) * 4 + 4) {
|
||||
switch (len - (wordcount + 1) * 4 + 4) {
|
||||
case 0:
|
||||
M0[wordcount] |= 0x80000000;
|
||||
break;
|
||||
case 1:
|
||||
M0[wordcount] = source[x] << 24 >>> 24 << 24;
|
||||
M0[wordcount] = source[x+start] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= 0x00800000;
|
||||
break;
|
||||
case 2:
|
||||
M0[wordcount] = source[x] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[x + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] = source[x+start] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[x+start + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] |= 0x00008000;
|
||||
break;
|
||||
case 3:
|
||||
M0[wordcount] = source[x] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[x + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] |= source[x + 2] << 24 >>> 24 << 8;
|
||||
M0[wordcount] = source[x+start] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[x+start + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] |= source[x+start + 2] << 24 >>> 24 << 8;
|
||||
M0[wordcount] |= 0x00000080;
|
||||
break;
|
||||
}
|
||||
|
@@ -12,27 +12,23 @@ package net.i2p.data;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeMap;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import net.i2p.util.OrderedProperties;
|
||||
|
||||
@@ -99,24 +95,28 @@ public class DataHelper {
|
||||
*/
|
||||
public static void writeProperties(OutputStream rawStream, Properties props)
|
||||
throws DataFormatException, IOException {
|
||||
OrderedProperties p = new OrderedProperties();
|
||||
if (props != null) p.putAll(props);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
|
||||
for (Iterator iter = p.keySet().iterator(); iter.hasNext();) {
|
||||
String key = (String) iter.next();
|
||||
String val = p.getProperty(key);
|
||||
// now make sure they're in UTF-8
|
||||
//key = new String(key.getBytes(), "UTF-8");
|
||||
//val = new String(val.getBytes(), "UTF-8");
|
||||
writeString(baos, key);
|
||||
baos.write(_equalBytes);
|
||||
writeString(baos, val);
|
||||
baos.write(_semicolonBytes);
|
||||
if (props != null) {
|
||||
OrderedProperties p = new OrderedProperties();
|
||||
p.putAll(props);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
|
||||
for (Iterator iter = p.keySet().iterator(); iter.hasNext();) {
|
||||
String key = (String) iter.next();
|
||||
String val = p.getProperty(key);
|
||||
// now make sure they're in UTF-8
|
||||
//key = new String(key.getBytes(), "UTF-8");
|
||||
//val = new String(val.getBytes(), "UTF-8");
|
||||
writeString(baos, key);
|
||||
baos.write(_equalBytes);
|
||||
writeString(baos, val);
|
||||
baos.write(_semicolonBytes);
|
||||
}
|
||||
baos.close();
|
||||
byte propBytes[] = baos.toByteArray();
|
||||
writeLong(rawStream, 2, propBytes.length);
|
||||
rawStream.write(propBytes);
|
||||
} else {
|
||||
writeLong(rawStream, 2, 0);
|
||||
}
|
||||
baos.close();
|
||||
byte propBytes[] = baos.toByteArray();
|
||||
writeLong(rawStream, 2, propBytes.length);
|
||||
rawStream.write(propBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,7 +261,66 @@ public class DataHelper {
|
||||
throw new DataFormatException("Invalid value (must be positive)", iae);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] toLong(int numBytes, long value) throws IllegalArgumentException {
|
||||
if (numBytes <= 0) throw new IllegalArgumentException("Invalid number of bytes");
|
||||
if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
|
||||
byte val[] = new byte[numBytes];
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
val[numBytes-i-1] = (byte)(value >>> (i*8));
|
||||
return val;
|
||||
}
|
||||
|
||||
public static long fromLong(byte src[], int offset, int numBytes) {
|
||||
if ( (src == null) || (src.length == 0) )
|
||||
return 0;
|
||||
|
||||
long rv = 0;
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
long cur = src[offset+i] & 0xFF;
|
||||
if (cur < 0) cur = cur+256;
|
||||
cur = (cur << (8*(numBytes-i-1)));
|
||||
rv += cur;
|
||||
}
|
||||
if (rv < 0)
|
||||
throw new IllegalArgumentException("wtf, fromLong got a negative? " + rv + ": offset="+ offset +" numBytes="+numBytes);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
for (int i = 0; i <= 0xFF; i++)
|
||||
testLong(1, i);
|
||||
System.out.println("Test 1byte passed");
|
||||
for (long i = 0; i <= 0xFFFF; i++)
|
||||
testLong(2, i);
|
||||
System.out.println("Test 2byte passed");
|
||||
for (long i = 0; i <= 0xFFFFFF; i++)
|
||||
testLong(3, i);
|
||||
System.out.println("Test 3byte passed");
|
||||
for (long i = 0; i <= 0xFFFFFFFF; i++)
|
||||
testLong(4, i);
|
||||
System.out.println("Test 4byte passed");
|
||||
for (long i = 0; i <= 0xFFFFFFFF; i++)
|
||||
testLong(8, i);
|
||||
System.out.println("Test 8byte passed");
|
||||
}
|
||||
private static void testLong(int numBytes, long value) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(numBytes);
|
||||
writeLong(baos, numBytes, value);
|
||||
byte written[] = baos.toByteArray();
|
||||
byte extract[] = toLong(numBytes, value);
|
||||
if (!eq(written, extract))
|
||||
throw new RuntimeException("testLong("+numBytes+","+value+") FAILED");
|
||||
|
||||
long read = fromLong(extract, 0, extract.length);
|
||||
if (read != value)
|
||||
throw new RuntimeException("testLong("+numBytes+","+value+") FAILED on read (" + read + ")");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** Read in a date from the stream as specified by the I2P data structure spec.
|
||||
* A date is an 8 byte unsigned integer in network byte order specifying the number of
|
||||
* milliseconds since midnight on January 1, 1970 in the GMT timezone. If the number is
|
||||
@@ -272,7 +331,7 @@ public class DataHelper {
|
||||
* @return date read, or null
|
||||
*/
|
||||
public static Date readDate(InputStream in) throws DataFormatException, IOException {
|
||||
long date = readLong(in, 8);
|
||||
long date = readLong(in, DATE_LENGTH);
|
||||
if (date == 0L) return null;
|
||||
|
||||
return new Date(date);
|
||||
@@ -287,10 +346,25 @@ public class DataHelper {
|
||||
public static void writeDate(OutputStream out, Date date)
|
||||
throws DataFormatException, IOException {
|
||||
if (date == null)
|
||||
writeLong(out, 8, 0L);
|
||||
writeLong(out, DATE_LENGTH, 0L);
|
||||
else
|
||||
writeLong(out, 8, date.getTime());
|
||||
writeLong(out, DATE_LENGTH, date.getTime());
|
||||
}
|
||||
public static byte[] toDate(Date date) throws IllegalArgumentException {
|
||||
if (date == null)
|
||||
return toLong(DATE_LENGTH, 0L);
|
||||
else
|
||||
return toLong(DATE_LENGTH, date.getTime());
|
||||
}
|
||||
public static Date fromDate(byte src[], int offset) throws IllegalArgumentException {
|
||||
long when = fromLong(src, offset, DATE_LENGTH);
|
||||
if (when <= 0)
|
||||
return null;
|
||||
else
|
||||
return new Date(when);
|
||||
}
|
||||
|
||||
public static final int DATE_LENGTH = 8;
|
||||
|
||||
/** Read in a string from the stream as specified by the I2P data structure spec.
|
||||
* A string is 1 or more bytes where the first byte is the number of bytes (not characters!)
|
||||
@@ -364,12 +438,16 @@ public class DataHelper {
|
||||
public static void writeBoolean(OutputStream out, Boolean bool)
|
||||
throws DataFormatException, IOException {
|
||||
if (bool == null)
|
||||
writeLong(out, 1, 2);
|
||||
writeLong(out, 1, BOOLEAN_UNKNOWN);
|
||||
else if (Boolean.TRUE.equals(bool))
|
||||
writeLong(out, 1, 1);
|
||||
writeLong(out, 1, BOOLEAN_TRUE);
|
||||
else
|
||||
writeLong(out, 1, 0);
|
||||
writeLong(out, 1, BOOLEAN_FALSE);
|
||||
}
|
||||
|
||||
public static final byte BOOLEAN_TRUE = 0x1;
|
||||
public static final byte BOOLEAN_FALSE = 0x0;
|
||||
public static final byte BOOLEAN_UNKNOWN = 0x2;
|
||||
|
||||
//
|
||||
// The following comparator helpers make it simpler to write consistently comparing
|
||||
@@ -463,12 +541,38 @@ public class DataHelper {
|
||||
|
||||
public final static byte[] xor(byte lhs[], byte rhs[]) {
|
||||
if ((lhs == null) || (rhs == null) || (lhs.length != rhs.length)) return null;
|
||||
byte rv[] = new byte[lhs.length];
|
||||
|
||||
byte diff[] = new byte[lhs.length];
|
||||
for (int i = 0; i < lhs.length; i++)
|
||||
diff[i] = (byte) (lhs[i] ^ rhs[i]);
|
||||
xor(lhs, 0, rhs, 0, diff, 0, lhs.length);
|
||||
return diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* xor the lhs with the rhs, storing the result in out.
|
||||
*
|
||||
* @param lhs one of the source arrays
|
||||
* @param startLeft starting index in the lhs array to begin the xor
|
||||
* @param rhs the other source array
|
||||
* @param startRight starting index in the rhs array to begin the xor
|
||||
* @param out output array
|
||||
* @param startOut starting index in the out array to store the result
|
||||
* @param len how many bytes into the various arrays to xor
|
||||
*/
|
||||
public final static void xor(byte lhs[], int startLeft, byte rhs[], int startRight, byte out[], int startOut, int len) {
|
||||
if ( (lhs == null) || (rhs == null) || (out == null) )
|
||||
throw new NullPointerException("Invalid params to xor (" + lhs + ", " + rhs + ", " + out + ")");
|
||||
if (lhs.length < startLeft + len)
|
||||
throw new IllegalArgumentException("Left hand side is too short");
|
||||
if (rhs.length < startRight + len)
|
||||
throw new IllegalArgumentException("Right hand side is too short");
|
||||
if (out.length < startOut + len)
|
||||
throw new IllegalArgumentException("Result is too short");
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
out[startOut + i] = (byte) (lhs[startLeft + i] ^ rhs[startRight + i]);
|
||||
}
|
||||
|
||||
//
|
||||
// The following hashcode helpers make it simpler to write consistently hashing
|
||||
// functions for objects based on their value, not JVM memory address
|
||||
@@ -594,9 +698,12 @@ public class DataHelper {
|
||||
|
||||
/** decompress the GZIP compressed data (returning null on error) */
|
||||
public static byte[] decompress(byte orig[]) throws IOException {
|
||||
return decompress(orig, 0, orig.length);
|
||||
}
|
||||
public static byte[] decompress(byte orig[], int offset, int length) throws IOException {
|
||||
if ((orig == null) || (orig.length <= 0)) return orig;
|
||||
GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(orig), orig.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(orig.length * 2);
|
||||
GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(orig, offset, length), length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(length * 2);
|
||||
byte buf[] = new byte[4 * 1024];
|
||||
while (true) {
|
||||
int read = in.read(buf);
|
||||
@@ -610,91 +717,4 @@ public class DataHelper {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in the last few lines of a (newline delimited) textfile, or null if
|
||||
* the file doesn't exist.
|
||||
*
|
||||
*/
|
||||
public static String readTextFile(String filename, int maxNumLines) {
|
||||
File f = new File(filename);
|
||||
if (!f.exists()) return null;
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(f);
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
|
||||
List lines = new ArrayList(maxNumLines);
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
lines.add(line);
|
||||
while (lines.size() > maxNumLines)
|
||||
lines.remove(0);
|
||||
}
|
||||
StringBuffer buf = new StringBuffer(lines.size() * 80);
|
||||
for (int i = 0; i < lines.size(); i++)
|
||||
buf.append((String)lines.get(i)).append('\n');
|
||||
return buf.toString();
|
||||
} catch (IOException ioe) {
|
||||
return null;
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean extractZip(File zipfile, File targetDir) {
|
||||
try {
|
||||
byte buf[] = new byte[16*1024];
|
||||
ZipFile zip = new ZipFile(zipfile);
|
||||
Enumeration entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = (ZipEntry)entries.nextElement();
|
||||
if (entry.getName().indexOf("..") != -1) {
|
||||
System.err.println("ERROR: Refusing to extract a zip entry with '..' in it [" + entry.getName() + "]");
|
||||
return false;
|
||||
}
|
||||
File target = new File(targetDir, entry.getName());
|
||||
File parent = target.getParentFile();
|
||||
if ( (parent != null) && (!parent.exists()) ) {
|
||||
boolean parentsOk = parent.mkdirs();
|
||||
if (!parentsOk) {
|
||||
System.err.println("ERROR: Unable to create the parent dir for " + entry.getName() + ": [" + parent.getAbsolutePath() + "]");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
if (!target.exists()) {
|
||||
boolean created = target.mkdirs();
|
||||
if (!created) {
|
||||
System.err.println("ERROR: Unable to create the directory [" + entry.getName() + "]");
|
||||
return false;
|
||||
} else {
|
||||
System.err.println("INFO: Creating directory [" + entry.getName() + "]");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
InputStream in = zip.getInputStream(entry);
|
||||
FileOutputStream fos = new FileOutputStream(target);
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1) {
|
||||
fos.write(buf, 0, read);
|
||||
}
|
||||
fos.close();
|
||||
in.close();
|
||||
|
||||
System.err.println("INFO: File [" + entry.getName() + "] extracted");
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + "]");
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
zip.close();
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("ERROR: Unable to extract the zip file");
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -322,6 +322,22 @@ public class RouterInfo extends DataStructureImpl {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pull the first workable target address for the given transport
|
||||
*
|
||||
*/
|
||||
public RouterAddress getTargetAddress(String transportStyle) {
|
||||
synchronized (_addresses) {
|
||||
for (Iterator iter = _addresses.iterator(); iter.hasNext(); ) {
|
||||
RouterAddress addr = (RouterAddress)iter.next();
|
||||
if (addr.getTransportStyle().equals(transportStyle))
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually validate the signature
|
||||
|
@@ -28,7 +28,10 @@ public class SessionKey extends DataStructureImpl {
|
||||
public final static int KEYSIZE_BYTES = 32;
|
||||
|
||||
public SessionKey() {
|
||||
setData(null);
|
||||
this(null);
|
||||
}
|
||||
public SessionKey(byte data[]) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
|
@@ -33,9 +33,8 @@ public class Signature extends DataStructureImpl {
|
||||
FAKE_SIGNATURE[i] = 0x00;
|
||||
}
|
||||
|
||||
public Signature() {
|
||||
setData(null);
|
||||
}
|
||||
public Signature() { this(null); }
|
||||
public Signature(byte data[]) { setData(data); }
|
||||
|
||||
public byte[] getData() {
|
||||
return _data;
|
||||
|
@@ -29,9 +29,8 @@ public class SigningPrivateKey extends DataStructureImpl {
|
||||
|
||||
public final static int KEYSIZE_BYTES = 20;
|
||||
|
||||
public SigningPrivateKey() {
|
||||
setData(null);
|
||||
}
|
||||
public SigningPrivateKey() { this(null); }
|
||||
public SigningPrivateKey(byte data[]) { setData(data); }
|
||||
|
||||
public byte[] getData() {
|
||||
return _data;
|
||||
|
@@ -29,9 +29,8 @@ public class SigningPublicKey extends DataStructureImpl {
|
||||
|
||||
public final static int KEYSIZE_BYTES = 128;
|
||||
|
||||
public SigningPublicKey() {
|
||||
setData(null);
|
||||
}
|
||||
public SigningPublicKey() { this(null); }
|
||||
public SigningPublicKey(byte data[]) { setData(data); }
|
||||
|
||||
public byte[] getData() {
|
||||
return _data;
|
||||
|
@@ -35,12 +35,25 @@ public class TunnelId extends DataStructureImpl {
|
||||
public final static int TYPE_PARTICIPANT = 3;
|
||||
|
||||
public TunnelId() {
|
||||
setTunnelId(-1);
|
||||
setType(TYPE_UNSPECIFIED);
|
||||
_tunnelId = -1;
|
||||
_type = TYPE_UNSPECIFIED;
|
||||
}
|
||||
public TunnelId(long id) {
|
||||
if (id <= 0) throw new IllegalArgumentException("wtf, tunnelId " + id);
|
||||
_tunnelId = id;
|
||||
_type = TYPE_UNSPECIFIED;
|
||||
}
|
||||
public TunnelId(long id, int type) {
|
||||
if (id <= 0) throw new IllegalArgumentException("wtf, tunnelId " + id);
|
||||
_tunnelId = id;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public long getTunnelId() { return _tunnelId; }
|
||||
public void setTunnelId(long id) { _tunnelId = id; }
|
||||
public void setTunnelId(long id) {
|
||||
_tunnelId = id;
|
||||
if (id <= 0) throw new IllegalArgumentException("wtf, tunnelId " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* is this tunnel inbound, outbound, or a participant (kept in memory only and used only for the router).s
|
||||
|
187
core/java/src/net/i2p/stat/BufferedStatLog.java
Normal file
187
core/java/src/net/i2p/stat/BufferedStatLog.java
Normal file
@@ -0,0 +1,187 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class BufferedStatLog implements StatLog {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private StatEvent _events[];
|
||||
private int _eventNext;
|
||||
private int _lastWrite;
|
||||
/** flush stat events to disk after this many events (or 30s)*/
|
||||
private int _flushFrequency;
|
||||
private List _statFilters;
|
||||
private String _lastFilters;
|
||||
private BufferedWriter _out;
|
||||
private String _outFile;
|
||||
|
||||
public BufferedStatLog(I2PAppContext ctx) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(BufferedStatLog.class);
|
||||
_events = new StatEvent[1000];
|
||||
for (int i = 0; i < 1000; i++)
|
||||
_events[i] = new StatEvent();
|
||||
_eventNext = 0;
|
||||
_lastWrite = _events.length-1;
|
||||
_statFilters = new ArrayList(10);
|
||||
_flushFrequency = 500;
|
||||
I2PThread writer = new I2PThread(new StatLogWriter(), "StatLogWriter");
|
||||
writer.setDaemon(true);
|
||||
writer.start();
|
||||
}
|
||||
|
||||
public void addData(String scope, String stat, long value, long duration) {
|
||||
synchronized (_events) {
|
||||
_events[_eventNext].init(scope, stat, value, duration);
|
||||
_eventNext = (_eventNext + 1) % _events.length;
|
||||
|
||||
if (_eventNext == _lastWrite)
|
||||
_lastWrite = (_lastWrite + 1) % _events.length; // drop an event
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("AddData next=" + _eventNext + " lastWrite=" + _lastWrite);
|
||||
|
||||
if (_eventNext > _lastWrite) {
|
||||
if (_eventNext - _lastWrite >= _flushFrequency)
|
||||
_events.notifyAll();
|
||||
} else {
|
||||
if (_events.length - 1 - _lastWrite + _eventNext >= _flushFrequency)
|
||||
_events.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldLog(String stat) {
|
||||
synchronized (_statFilters) {
|
||||
return _statFilters.contains(stat) || _statFilters.contains("*");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFilters() {
|
||||
String val = _context.getProperty("stat.logFilters");
|
||||
if (val != null) {
|
||||
if ( (_lastFilters != null) && (_lastFilters.equals(val)) ) {
|
||||
// noop
|
||||
} else {
|
||||
StringTokenizer tok = new StringTokenizer(val, ",");
|
||||
synchronized (_statFilters) {
|
||||
_statFilters.clear();
|
||||
while (tok.hasMoreTokens())
|
||||
_statFilters.add(tok.nextToken().trim());
|
||||
}
|
||||
}
|
||||
_lastFilters = val;
|
||||
} else {
|
||||
synchronized (_statFilters) { _statFilters.clear(); }
|
||||
}
|
||||
|
||||
String filename = _context.getProperty("stat.logFile");
|
||||
if (filename == null)
|
||||
filename = "stats.log";
|
||||
if ( (_outFile != null) && (_outFile.equals(filename)) ) {
|
||||
// noop
|
||||
} else {
|
||||
if (_out != null) try { _out.close(); } catch (IOException ioe) {}
|
||||
_outFile = filename;
|
||||
try {
|
||||
_out = new BufferedWriter(new FileWriter(_outFile, true));
|
||||
} catch (IOException ioe) { ioe.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
|
||||
private class StatLogWriter implements Runnable {
|
||||
private SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd HH:mm:ss.SSS");
|
||||
public void run() {
|
||||
int writeStart = -1;
|
||||
int writeEnd = -1;
|
||||
while (true) {
|
||||
synchronized (_events) {
|
||||
if (_eventNext > _lastWrite) {
|
||||
if (_eventNext - _lastWrite < _flushFrequency)
|
||||
try { _events.wait(30*1000); } catch (InterruptedException ie) {}
|
||||
} else {
|
||||
if (_events.length - 1 - _lastWrite + _eventNext < _flushFrequency)
|
||||
try { _events.wait(30*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
writeStart = (_lastWrite + 1) % _events.length;
|
||||
writeEnd = _eventNext;
|
||||
_lastWrite = (writeEnd == 0 ? _events.length-1 : writeEnd - 1);
|
||||
}
|
||||
if (writeStart != writeEnd) {
|
||||
try {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("writing " + writeStart +"->"+ writeEnd);
|
||||
writeEvents(writeStart, writeEnd);
|
||||
} catch (Exception e) {
|
||||
_log.error("error writing " + writeStart +"->"+ writeEnd, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeEvents(int start, int end) {
|
||||
try {
|
||||
updateFilters();
|
||||
int cur = start;
|
||||
while (cur != end) {
|
||||
if (shouldLog(_events[cur].getStat())) {
|
||||
String when = null;
|
||||
synchronized (_fmt) {
|
||||
when = _fmt.format(new Date(_events[cur].getTime()));
|
||||
}
|
||||
_out.write(when);
|
||||
_out.write(" ");
|
||||
if (_events[cur].getScope() == null)
|
||||
_out.write("noScope ");
|
||||
else
|
||||
_out.write(_events[cur].getScope() + " ");
|
||||
_out.write(_events[cur].getStat()+" ");
|
||||
_out.write(_events[cur].getValue()+" ");
|
||||
_out.write(_events[cur].getDuration()+"\n");
|
||||
}
|
||||
cur = (cur + 1) % _events.length;
|
||||
}
|
||||
_out.flush();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error writing out", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StatEvent {
|
||||
private long _time;
|
||||
private String _scope;
|
||||
private String _stat;
|
||||
private long _value;
|
||||
private long _duration;
|
||||
|
||||
public long getTime() { return _time; }
|
||||
public String getScope() { return _scope; }
|
||||
public String getStat() { return _stat; }
|
||||
public long getValue() { return _value; }
|
||||
public long getDuration() { return _duration; }
|
||||
|
||||
public void init(String scope, String stat, long value, long duration) {
|
||||
_scope = scope;
|
||||
_stat = stat;
|
||||
_value = value;
|
||||
_duration = duration;
|
||||
_time = _context.clock().now();
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,6 +19,8 @@ public class RateStat {
|
||||
private String _description;
|
||||
/** actual rate objects for this statistic */
|
||||
private Rate _rates[];
|
||||
/** component we tell about events as they occur */
|
||||
private StatLog _statLog;
|
||||
|
||||
public RateStat(String name, String description, String group, long periods[]) {
|
||||
_statName = name;
|
||||
@@ -28,11 +30,13 @@ public class RateStat {
|
||||
for (int i = 0; i < periods.length; i++)
|
||||
_rates[i] = new Rate(periods[i]);
|
||||
}
|
||||
|
||||
public void setStatLog(StatLog sl) { _statLog = sl; }
|
||||
|
||||
/**
|
||||
* update all of the rates for the various periods with the given value.
|
||||
*/
|
||||
public void addData(long value, long eventDuration) {
|
||||
if (_statLog != null) _statLog.addData(_groupName, _statName, value, eventDuration);
|
||||
for (int i = 0; i < _rates.length; i++)
|
||||
_rates[i].addData(value, eventDuration);
|
||||
}
|
||||
|
8
core/java/src/net/i2p/stat/StatLog.java
Normal file
8
core/java/src/net/i2p/stat/StatLog.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
/**
|
||||
* Component to be notified when a particular event occurs
|
||||
*/
|
||||
public interface StatLog {
|
||||
public void addData(String scope, String stat, long value, long duration);
|
||||
}
|
76
core/java/src/net/i2p/stat/StatLogSplitter.java
Normal file
76
core/java/src/net/i2p/stat/StatLogSplitter.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Simple CLI to splot the stat logs into per-stat files containing
|
||||
* #seconds since beginning and the value (ready for loading into your
|
||||
* favorite plotting tool)
|
||||
*/
|
||||
public class StatLogSplitter {
|
||||
private static final String DATE_FORMAT = "yyyyMMdd HH:mm:ss.SSS";
|
||||
private static SimpleDateFormat _fmt = new SimpleDateFormat(DATE_FORMAT);
|
||||
public static void main(String args[]) {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: StatLogSplitter filename");
|
||||
return;
|
||||
}
|
||||
splitLog(args[0]);
|
||||
}
|
||||
|
||||
private static void splitLog(String filename) {
|
||||
Map outputFiles = new HashMap(4);
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(filename));
|
||||
String line;
|
||||
long first = 0;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
String date = line.substring(0, DATE_FORMAT.length()).trim();
|
||||
int endGroup = line.indexOf(' ', DATE_FORMAT.length()+1);
|
||||
int endStat = line.indexOf(' ', endGroup+1);
|
||||
int endValue = line.indexOf(' ', endStat+1);
|
||||
String group = line.substring(DATE_FORMAT.length()+1, endGroup).trim();
|
||||
String stat = line.substring(endGroup, endStat).trim();
|
||||
String value = line.substring(endStat, endValue).trim();
|
||||
String duration = line.substring(endValue).trim();
|
||||
//System.out.println(date + " " + group + " " + stat + " " + value + " " + duration);
|
||||
|
||||
try {
|
||||
Date when = _fmt.parse(date);
|
||||
if (first <= 0) first = when.getTime();
|
||||
long val = Long.parseLong(value);
|
||||
long time = Long.parseLong(duration);
|
||||
if (!outputFiles.containsKey(stat)) {
|
||||
outputFiles.put(stat, new FileWriter(stat + ".dat"));
|
||||
System.out.println("Including data to " + stat + ".dat");
|
||||
}
|
||||
FileWriter out = (FileWriter)outputFiles.get(stat);
|
||||
double s = (when.getTime()-first)/1000.0;
|
||||
//long s = when.getTime();
|
||||
out.write(s + " " + val + " [" + line + "]\n");
|
||||
out.flush();
|
||||
} catch (ParseException pe) {
|
||||
continue;
|
||||
} catch (NumberFormatException nfe){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
for (Iterator iter = outputFiles.values().iterator(); iter.hasNext(); ) {
|
||||
FileWriter out = (FileWriter)iter.next();
|
||||
try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
@@ -27,6 +27,7 @@ public class StatManager {
|
||||
private Map _frequencyStats;
|
||||
/** stat name to RateStat */
|
||||
private Map _rateStats;
|
||||
private StatLog _statLog;
|
||||
|
||||
/**
|
||||
* The stat manager should only be constructed and accessed through the
|
||||
@@ -39,6 +40,18 @@ public class StatManager {
|
||||
_context = context;
|
||||
_frequencyStats = Collections.synchronizedMap(new HashMap(128));
|
||||
_rateStats = Collections.synchronizedMap(new HashMap(128));
|
||||
_statLog = new BufferedStatLog(context);
|
||||
}
|
||||
|
||||
public StatLog getStatLog() { return _statLog; }
|
||||
public void setStatLog(StatLog log) {
|
||||
_statLog = log;
|
||||
synchronized (_rateStats) {
|
||||
for (Iterator iter = _rateStats.values().iterator(); iter.hasNext(); ) {
|
||||
RateStat rs = (RateStat)iter.next();
|
||||
rs.setStatLog(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +77,9 @@ public class StatManager {
|
||||
*/
|
||||
public void createRateStat(String name, String description, String group, long periods[]) {
|
||||
if (_rateStats.containsKey(name)) return;
|
||||
_rateStats.put(name, new RateStat(name, description, group, periods));
|
||||
RateStat rs = new RateStat(name, description, group, periods);
|
||||
if (_statLog != null) rs.setStatLog(_statLog);
|
||||
_rateStats.put(name, rs);
|
||||
}
|
||||
|
||||
/** update the given frequency statistic, taking note that an event occurred (and recalculating all frequencies) */
|
||||
|
@@ -115,7 +115,7 @@ public class NtpClient {
|
||||
//System.out.println("host: " + serverName + " rtt: " + roundTripDelay + " offset: " + localClockOffset + " seconds");
|
||||
return (long)(System.currentTimeMillis() + localClockOffset*1000);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
//ioe.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@@ -100,6 +100,7 @@ public class Timestamper implements Runnable {
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting up timestamper");
|
||||
boolean alreadyBitched = false;
|
||||
try {
|
||||
while (true) {
|
||||
updateConfig();
|
||||
@@ -118,7 +119,9 @@ public class Timestamper implements Runnable {
|
||||
_log.debug("Stamp time");
|
||||
stampTime(now);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
_log.log(Log.CRIT, "Unable to reach any of the NTP servers - network disconnected?");
|
||||
if (!alreadyBitched)
|
||||
_log.log(Log.CRIT, "Unable to reach any of the NTP servers - network disconnected?");
|
||||
alreadyBitched = true;
|
||||
}
|
||||
}
|
||||
try { Thread.sleep(_queryFrequency); } catch (InterruptedException ie) {}
|
||||
|
171
core/java/src/net/i2p/util/FileUtil.java
Normal file
171
core/java/src/net/i2p/util/FileUtil.java
Normal file
@@ -0,0 +1,171 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* General helper methods for messing with files
|
||||
*
|
||||
*/
|
||||
public class FileUtil {
|
||||
/**
|
||||
* Delete the path as well as any files or directories underneath it.
|
||||
*
|
||||
* @param path path to the directory being deleted
|
||||
* @param failIfNotEmpty if true, do not delete anything if the directory
|
||||
* is not empty (and return false)
|
||||
* @return true if the path no longer exists (aka was removed),
|
||||
* false if it remains
|
||||
*/
|
||||
public static final boolean rmdir(String path, boolean failIfNotEmpty) {
|
||||
return rmdir(new File(path), failIfNotEmpty);
|
||||
}
|
||||
/**
|
||||
* Delete the path as well as any files or directories underneath it.
|
||||
*
|
||||
* @param target the file or directory being deleted
|
||||
* @param failIfNotEmpty if true, do not delete anything if the directory
|
||||
* is not empty (and return false)
|
||||
* @return true if the path no longer exists (aka was removed),
|
||||
* false if it remains
|
||||
*/
|
||||
public static final boolean rmdir(File target, boolean failIfNotEmpty) {
|
||||
if (!target.exists()) {
|
||||
//System.out.println("info: target does not exist [" + target.getPath() + "]");
|
||||
return true;
|
||||
}
|
||||
if (!target.isDirectory()) {
|
||||
//System.out.println("info: target is not a directory [" + target.getPath() + "]");
|
||||
return target.delete();
|
||||
} else {
|
||||
File children[] = target.listFiles();
|
||||
if (children == null) {
|
||||
//System.out.println("info: target null children [" + target.getPath() + "]");
|
||||
return false;
|
||||
}
|
||||
if ( (failIfNotEmpty) && (children.length > 0) ) {
|
||||
//System.out.println("info: target is not emtpy[" + target.getPath() + "]");
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
if (!rmdir(children[i], failIfNotEmpty))
|
||||
return false;
|
||||
|
||||
//System.out.println("info: target removed recursively [" + children[i].getPath() + "]");
|
||||
}
|
||||
return target.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean extractZip(File zipfile, File targetDir) {
|
||||
try {
|
||||
byte buf[] = new byte[16*1024];
|
||||
ZipFile zip = new ZipFile(zipfile);
|
||||
Enumeration entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = (ZipEntry)entries.nextElement();
|
||||
if (entry.getName().indexOf("..") != -1) {
|
||||
System.err.println("ERROR: Refusing to extract a zip entry with '..' in it [" + entry.getName() + "]");
|
||||
return false;
|
||||
}
|
||||
File target = new File(targetDir, entry.getName());
|
||||
File parent = target.getParentFile();
|
||||
if ( (parent != null) && (!parent.exists()) ) {
|
||||
boolean parentsOk = parent.mkdirs();
|
||||
if (!parentsOk) {
|
||||
System.err.println("ERROR: Unable to create the parent dir for " + entry.getName() + ": [" + parent.getAbsolutePath() + "]");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
if (!target.exists()) {
|
||||
boolean created = target.mkdirs();
|
||||
if (!created) {
|
||||
System.err.println("ERROR: Unable to create the directory [" + entry.getName() + "]");
|
||||
return false;
|
||||
} else {
|
||||
System.err.println("INFO: Creating directory [" + entry.getName() + "]");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
InputStream in = zip.getInputStream(entry);
|
||||
FileOutputStream fos = new FileOutputStream(target);
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1) {
|
||||
fos.write(buf, 0, read);
|
||||
}
|
||||
fos.close();
|
||||
in.close();
|
||||
|
||||
System.err.println("INFO: File [" + entry.getName() + "] extracted");
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + "]");
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
zip.close();
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("ERROR: Unable to extract the zip file");
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in the last few lines of a (newline delimited) textfile, or null if
|
||||
* the file doesn't exist.
|
||||
*
|
||||
*/
|
||||
public static String readTextFile(String filename, int maxNumLines) {
|
||||
File f = new File(filename);
|
||||
if (!f.exists()) return null;
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(f);
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
|
||||
List lines = new ArrayList(maxNumLines);
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
lines.add(line);
|
||||
while (lines.size() > maxNumLines)
|
||||
lines.remove(0);
|
||||
}
|
||||
StringBuffer buf = new StringBuffer(lines.size() * 80);
|
||||
for (int i = 0; i < lines.size(); i++)
|
||||
buf.append((String)lines.get(i)).append('\n');
|
||||
return buf.toString();
|
||||
} catch (IOException ioe) {
|
||||
return null;
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
testRmdir();
|
||||
}
|
||||
private static void testRmdir() {
|
||||
File t = new File("rmdirTest/test/subdir/blah");
|
||||
boolean created = t.mkdirs();
|
||||
if (!t.exists()) throw new RuntimeException("Unable to create test");
|
||||
boolean deleted = FileUtil.rmdir("rmdirTest", false);
|
||||
if (!deleted)
|
||||
System.err.println("FAIL: unable to delete rmdirTest");
|
||||
else
|
||||
System.out.println("PASS: rmdirTest deleted");
|
||||
}
|
||||
}
|
@@ -246,8 +246,8 @@ public class LogManager {
|
||||
File cfgFile = new File(_location);
|
||||
if (!cfgFile.exists()) {
|
||||
if (!_alreadyNoticedMissingConfig) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Log file " + _location + " does not exist");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Log file " + _location + " does not exist");
|
||||
System.err.println("Log file " + _location + " does not exist");
|
||||
_alreadyNoticedMissingConfig = true;
|
||||
}
|
||||
@@ -447,19 +447,18 @@ public class LogManager {
|
||||
if (!Character.isDigit(mod)) v = size.substring(0, size.length() - 1);
|
||||
int val = Integer.parseInt(v);
|
||||
switch (mod) {
|
||||
case 'K':
|
||||
val *= 1024;
|
||||
break;
|
||||
case 'M':
|
||||
val *= 1024 * 1024;
|
||||
break;
|
||||
case 'G':
|
||||
val *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 'T':
|
||||
// because we can
|
||||
val *= 1024 * 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 'K':
|
||||
val *= 1024;
|
||||
break;
|
||||
case 'M':
|
||||
val *= 1024 * 1024;
|
||||
break;
|
||||
case 'G':
|
||||
val *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
default:
|
||||
// blah, noop
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
} catch (Throwable t) {
|
||||
|
@@ -104,6 +104,8 @@ public class ShellCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private final static int BUFFER_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* Reads data from a <code>java.io.InputStream</code> and writes it to
|
||||
* <code>STDOUT</code>.
|
||||
@@ -112,8 +114,6 @@ public class ShellCommand {
|
||||
*/
|
||||
private class StreamReader extends Thread {
|
||||
|
||||
final int BUFFER_SIZE = 1024;
|
||||
|
||||
private BufferedReader bufferedReader;
|
||||
private InputStreamReader inputStreamReader;
|
||||
|
||||
|
@@ -72,22 +72,28 @@ public class AES256Bench {
|
||||
iv[x] = (byte)civ[x];
|
||||
}
|
||||
|
||||
byte[] e = _context.AESEngine().encrypt(plain, key, iv);
|
||||
byte[] d = _context.AESEngine().decrypt(e, key, iv);
|
||||
byte[] e = new byte[plain.length];
|
||||
_context.aes().encrypt(plain, 0, e, 0, key, iv, plain.length);
|
||||
byte[] d = new byte[e.length];
|
||||
_context.aes().decrypt(e, 0, d, 0, key, iv, d.length);
|
||||
boolean same = true;
|
||||
for (int x = 0; x < d.length; x++) {
|
||||
if (plain[x] != d[x]) {
|
||||
same = false;
|
||||
throw new RuntimeException("Failed decrypt at " + x);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Standard test D(E(value)) == value? " + same);
|
||||
if (!same) throw new RuntimeException("moo");
|
||||
|
||||
plain = "1234567890123456".getBytes();
|
||||
e = _context.AESEngine().encrypt(plain, key, iv);
|
||||
d = _context.AESEngine().decrypt(e, key, iv);
|
||||
e = new byte[plain.length];
|
||||
_context.aes().encrypt(plain, 0, e, 0, key, iv, plain.length);
|
||||
d = new byte[e.length];
|
||||
_context.aes().decrypt(e, 0, d, 0, key, iv, d.length);
|
||||
same = DataHelper.eq(plain, d);
|
||||
System.out.println("Different value test D(E(value)) == value? " + same);
|
||||
if (!same) throw new RuntimeException("moo");
|
||||
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
@@ -104,9 +110,11 @@ public class AES256Bench {
|
||||
message[i] = (byte)((i%26)+'a');
|
||||
for (int x = 0; x < times; x++) {
|
||||
long startencrypt = System.currentTimeMillis();
|
||||
e = _context.AESEngine().encrypt(message, key, iv);
|
||||
e = new byte[message.length];
|
||||
d = new byte[e.length];
|
||||
_context.aes().encrypt(message, 0, e, 0, key, iv, message.length);
|
||||
long endencryptstartdecrypt = System.currentTimeMillis();
|
||||
d = _context.AESEngine().decrypt(e, key, iv);
|
||||
_context.aes().decrypt(e, 0, d, 0, key, iv, d.length);
|
||||
long enddecrypt = System.currentTimeMillis();
|
||||
System.out.print(".");
|
||||
encrypttime += endencryptstartdecrypt - startencrypt;
|
||||
|
@@ -145,8 +145,10 @@ class ElGamalAESEngineTest {
|
||||
String msg = "Hello world01234012345678901234501234567890123450123456789012345";
|
||||
h = SHA256Generator.getInstance().calculateHash(msg.getBytes());
|
||||
_log.debug("Hash of entire aes block before encryption: \n" + DataHelper.toString(h.getData(), 32));
|
||||
byte aesEncr[] = _context.AESEngine().encrypt(msg.getBytes(), sessionKey, iv);
|
||||
byte aesDecr[] = _context.AESEngine().decrypt(aesEncr, sessionKey, iv);
|
||||
byte aesEncr[] = new byte[msg.getBytes().length];
|
||||
byte aesDecr[] = new byte[aesEncr.length];
|
||||
_context.aes().encrypt(msg.getBytes(), 0, aesEncr, 0, sessionKey, iv, aesEncr.length);
|
||||
_context.aes().decrypt(aesEncr, 0, aesDecr, 0, sessionKey, iv, aesEncr.length);
|
||||
h = SHA256Generator.getInstance().calculateHash(aesDecr);
|
||||
_log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32));
|
||||
if (msg.equals(new String(aesDecr))) {
|
||||
|
166
history.txt
166
history.txt
@@ -1,4 +1,168 @@
|
||||
$Id: history.txt,v 1.15 2004/09/08 17:15:43 hypercubus Exp $
|
||||
$Id: history.txt,v 1.43 2004/10/10 09:57:15 jrandom Exp $
|
||||
|
||||
* 2004-10-10 0.4.1.2 released
|
||||
|
||||
2004-10-10 cervantes
|
||||
* Update the I2PTunnel HTTP proxy to strip out the i2paddresshelper from
|
||||
the request.
|
||||
|
||||
2004-10-09 jrandom
|
||||
* Added a watchdog timer to do some baseline liveliness checking to help
|
||||
debug some odd errors.
|
||||
* Added a pair of summary stats for bandwidth usage, allowing easy export
|
||||
with the other stats ("bw.sendBps" and "bw.receiveBps")
|
||||
* Trimmed another memory allocation on message reception.
|
||||
|
||||
2004-10-08 jrandom
|
||||
* Revamp the AESInputStream so it doesn't allocate any temporary objects
|
||||
during its operation.
|
||||
|
||||
2004-10-08 jrandom
|
||||
* Don't kill the establisher threads during a soft restart.
|
||||
* Attempt to validate the peer's routerInfo earlier during handshaking.
|
||||
* Revamp the AESOutputStream so it doesn't allocate any temporary objects
|
||||
during its operation.
|
||||
|
||||
2004-10-07 jrandom
|
||||
* Reimplement the I2NP reading with less temporary memory allocation.
|
||||
There is still significant GC churn, especially under load, but this
|
||||
should help.
|
||||
* Catch some oddball errors in the transport (message timeout while
|
||||
establishing).
|
||||
|
||||
2004-10-07 jrandom
|
||||
* Expire queued messages even when the writer is blocked.
|
||||
* Reimplement most of the I2NP writing with less temporary memory
|
||||
allocations (I2NP reading still gobbles memory).
|
||||
|
||||
2004-10-06 jrandom
|
||||
* Implement an active queue management scheme on the TCP transports,
|
||||
dropping messages probabalistically as the queue fills up. The
|
||||
estimated queue capacity is determined by the rate at which messages
|
||||
have been sent to the peer (averaged at 1, 5, and 60m periods). As
|
||||
we exceed 1/2 of the estimated capacity, we drop messages throughout
|
||||
the queue probabalistically with regards to their size. This is based
|
||||
on RFC 2309's RED, with the minimum threshold set to 1/2 the
|
||||
estimated connection capacity. We may want to consider using a send
|
||||
rate and queue size measured across all connections, to deal with our
|
||||
own local bandwidth saturation, but we'll try the per-con metrics first.
|
||||
|
||||
2004-10-06 jrandom
|
||||
* Enable explicit disabling of the systray entirely for windows machines
|
||||
with strange configurations: add -Dsystray.disable=true to the java
|
||||
command line. (thanks mihi!)
|
||||
|
||||
2004-10-05 jrandom
|
||||
* Allow peers on the same LAN to communicate with each other safely even
|
||||
when they cannot talk to each other through the external address.
|
||||
|
||||
2004-10-05 jrandom
|
||||
* Display how much time is left before the graceful shutdown is complete.
|
||||
* Debug some improperly failed messages on timeout or disconnection.
|
||||
|
||||
2004-10-05 jrandom
|
||||
* Don't go into a fast busy if an I2PTunnel 'server' is explicitly killed
|
||||
(thanks mule!)
|
||||
* Handle some more error conditions regarding abruptly closing sockets
|
||||
(thanks Jonva!)
|
||||
|
||||
2004-10-04 jrandom
|
||||
* Update the shitlist to reject a peer for an exponentially increasing
|
||||
period of time (with an upper bounds of an hour).
|
||||
* Various minor stat and debugging fixes
|
||||
|
||||
2004-10-03 jrandom
|
||||
* Add a new stat logging component to optionally dump the raw stats to
|
||||
disk as they are generated, rather than rely upon the summarized data.
|
||||
By default, this is off, but the router property "stat.logFilters" can
|
||||
be set to a comma delimited list of stats (e.g. "client.sendAckTime")
|
||||
which will be written to the file "stats.log" (or whatever the property
|
||||
"stat.logFile" is set to). This can also log profile related stats,
|
||||
such as "dbResponseTime" or "tunnelTestResponseTime".
|
||||
|
||||
2004-10-02 jrandom
|
||||
* Assure that we quickly fail messages bound for shitlisted peers.
|
||||
* Address a race on startup where the first peer contacted could hang the
|
||||
router (thanks Romster!)
|
||||
* Only whine about an intermittent inability to query the time server once
|
||||
|
||||
2004-10-02 jrandom
|
||||
* Command line utility to verify a peer's reachability - simply run
|
||||
net.i2p.router.transport.tcp.ConnectionHandler hostname port# and it
|
||||
will print out whether that peer is reachable or not (using a simple
|
||||
verification handshake).
|
||||
|
||||
* 2004-10-01 0.4.1.1 released
|
||||
|
||||
2004-10-01 jrandom
|
||||
* Handle partial reseeds, caused by seeds going away before the download
|
||||
completes (thanks Sugadude!)
|
||||
|
||||
2004-10-01 jrandom
|
||||
* Explicitly refuse IPv6 addresses, since only some peers support
|
||||
them and we want fully reachable peers.
|
||||
|
||||
2004-10-01 jrandom
|
||||
* Additional error handling for a variety of transport layer errors.
|
||||
|
||||
* 2004-09-30 0.4.1 released (not backwards compatible)
|
||||
|
||||
2004-09-30 jrandom
|
||||
* Bundle the configuration necessary to run an eepsite out of the box
|
||||
with Jetty - simply edit ./eepsite/docroot/index.html and give people
|
||||
the key listed on the I2PTunnel configuration page, and its up.
|
||||
* Router console cleanup, and some (off by default) tunnels -
|
||||
smtp.postman.i2p (port 7659), pop.postman.i2p (port 7660), and
|
||||
irc.baffled.i2p (port 7661)
|
||||
|
||||
2004-09-29 jrandom
|
||||
* Always wipe the Jetty work directory on startup, so that web updates
|
||||
are reflected immediately (Jetty does not honor the cache across
|
||||
multiple executions)
|
||||
|
||||
2004-09-27 jrandom
|
||||
* Limit the number of connection tags saved to 10,000. This is a huge
|
||||
limit, but consumes no more than 1MB of RAM. For now, we drop them
|
||||
randomly after reaching that size, forcing those dropped peers to use
|
||||
a full DH negotiation.
|
||||
* HTML cleanup in the console.
|
||||
|
||||
2004-09-26 jrandom
|
||||
* Complete rewrite of the TCP transport with IP autodetection and
|
||||
low CPU overhead reconnections. More concise connectivity errors
|
||||
are listed on the /oldconsole.jsp as well. The IP autodetection works
|
||||
by listening to the first person who tells you what your IP address is
|
||||
when you have not defined one yourself and you have no other TCP
|
||||
connections.
|
||||
* Update to the I2NP message format to add transparent verification at
|
||||
the I2NP level (beyond standard TCP verification).
|
||||
* Remove a potential weakness in our AESEngine's safeEncrypt and safeDecrypt
|
||||
implementation (rather than verifying with E(H(key)), we now verify with
|
||||
E(H(iv))).
|
||||
* The above changes are NOT BACKWARDS COMPATIBLE.
|
||||
* Removed all of the old unused PHTTP code.
|
||||
* Refactor various methods and clean up some javadoc.
|
||||
|
||||
2004-09-21 jrandom
|
||||
* Have two tiers of hosts.txt files - the standard "hosts.txt" and
|
||||
the new "userhosts.txt". Updates to I2P will only overwrite the former,
|
||||
but values stored in the later take precedence. Both are queried on
|
||||
lookup.
|
||||
|
||||
2004-09-16 jrandom
|
||||
* Refactor the TCP transport to deal with changing identities gracefully,
|
||||
and to prevent some wasted effort by keeping track of what host+port
|
||||
combinations we are connected to (rather than just the identities). Also
|
||||
catch a few configuration errors earlier.
|
||||
* Removed no longer relevent methods from the Transport API that were
|
||||
exposing ideas that probably shouldn't be exposed.
|
||||
* Removed the 0.4.0.1 specific files from i2pupdate.zip (relating to script
|
||||
updates)
|
||||
|
||||
2004-09-13 jrandom
|
||||
* Update for the SDK reconnection to deal with overflow.
|
||||
* Web improvements (@ not # on the /logs.jsp [thanks ugha!] and fixed the
|
||||
rounding on lifetime bandwidth used [thanks gott!]).
|
||||
|
||||
* 2004-09-08 0.4.0.1 released
|
||||
|
||||
|
32
hosts.txt
32
hosts.txt
@@ -1,6 +1,18 @@
|
||||
; TC's hosts.txt guaranteed freshness
|
||||
; $Id: hosts.txt,v 1.42 2004/09/08 02:46:21 jrandom Exp $
|
||||
; $Id: hosts.txt,v 1.56 2004/10/05 10:57:08 jrandom Exp $
|
||||
; changelog:
|
||||
; (1.79) updated beyond.i2p's key
|
||||
; (1.78) added b.i2p
|
||||
; (1.77) added tinyurl.i2p
|
||||
; (1.76) added detonate.i2p
|
||||
; (1.75) added identiguy.i2p
|
||||
; (1.74) added jabber-2.i2p
|
||||
; (1.73) added jake.i2p
|
||||
; (1.72) added anonymnet.i2p sasquotch.i2p orz.i2p microbleu.i2p {www,smtp,pop3}.postman.i2p
|
||||
; (1.71) added curiosity.i2p
|
||||
; (1.70) added freeciv.nightblade.i2p
|
||||
; (1.69) added xolotl.i2p
|
||||
; (1.68) added modulus.i2p
|
||||
; (1.67) added eepdot.i2p
|
||||
; (1.66) removed datagram_test.i2p
|
||||
; (1.65) added socks1.tor.i2p
|
||||
@@ -154,4 +166,22 @@ files.i2p=1rI0OWp83VhVRyMiZkPmw~mEo-CVu548n4uJLsHJW4eNzQfQ~k8SSFGCMc0-YmOW8zvB1A
|
||||
sugadude.i2p=PIV8bZaIH4wRqzlzVLX1mDkELhLFdyLlKxcd2nUrJvd0YeTByls6LGFZ7wr0-9MT7cb3Ee23U1BApgm0~jT5bzFGIQOvx7AT8o0uMy~fcP1lhzo4lNwD5bHnf9OXe59FzORC3s79bwFmTtMCrEoYvQXCGherxwFfXywRPrJ2x0AjfjungiwX3vrndMdol1SDWTLdxTSARLPgLmswz47gGm4dOipjHBSGOm5bdgZBD6di8YGxHrB072QfXxBVSGzTgtQNnK4qAsZv1YbETk2CQ1nOKpCj0Zjkcnc1trTFOpUQKeOp6kiGCriAn8Ezbu1yuf2fiDAmPenFf8bDR7fNFR7kMDcKsbiht7fFi0wjPdE4Lx5H2PFyTuiw3~-osNsXFLtjvaeIV4P99vZRof1avADgp5k4pC8fEPKWfwXGPPFJjYEbWPE4VxmxcP93Iq-CMZfSd8fPeZNeBz8qL~n9IXJoXjO0G3nouQ7d1ZF4okVRO8FmZ91Umpy79v2I4sYFAAAA
|
||||
socks1.tor.i2p=sl3oda7CJe3TN1JVoALIuoRAe--qYgDwo0A8PrUGaaWQ2xXiWYaTV7~FQOmv13JRCtbO-8rhOfGWnV-qia4CtRxH6nR6fytW~uJKRP4hbjhfvBuS1QdX2GwWlbgJdV8VT3OpJAe5iuKYCFnnSbVG2VZajtsoKJxHY748h1zhIh4YaMBGqoodQJrnvYWd4HJJ-ZauE-s-K2zWOTJ-EKZNp9UZr5DWDV3P5JTSruc7vyKiDVFra~-JT8mjnWBE9GKy1HiJKAe2UyKHBVjvJ9iL4bJ3HLH-z3oIP5KmW7s4czTq2fdO7yhssLMKxaGqhzsNViWv8FtvLJtHkTsprVQBeS2Eeqiw3iwcC4DGP4dUkj2Ex7DPqvxlA58Df0INgNz-kUPuURf0ZSK45v-s7F0f03BbwIu5eErLZhQckxs9tX6twSPXk2RaceOMA0-eKlbCh3FcpbFbfcimjOTcmpeUN7s-7C-XfM1vazIaIpTADwzZ9Ocs5TV~CU8TPyxZkx8FAAAA
|
||||
eepdot.i2p=IXWmPK6689w4d2j-B-zQRdgG6md6UdvDZz9e3MnEWaoU7SiHk8Yrw4-2MSavhycFDkQNdpdJgYVhK0Ve8aF4TNf88KdI5SY4nl079CrjhTaNoQiUxOTJIUzTWGrDmNITfoV7PAjGWoMjw5dOcbK~PMpMTlOx9w8CtFEHU2cG4Gdcpu5NFpv6a5FWZNO-GRYrWfW1laZBviaE1Twwva-thbY~G5un9JFAoQZ88mS2JRKrxFuy1P1xCEEEiLvJfOcHVdL-0ebQV5q5Cwlyvrkki1se4URzlgF-FjQjTiaS0kbtHv6NkG-R19poUQu-ktMdMdDf2RLFBJPtyTvbyteyeXnI4LjGxSzQ8eH3txelIZKXwCRPYFNqutAmoQMqLf~NLDPtIq3QGp798sBbt3nooOKGEk3RVcJDwEzx~t3Qj6DWEA0xwSm56YYG84EYT2itIYGH8J4epFjGdV3zfWiME~QHLKfAwwkY-JdCiaDTk7RPfY1jkBw~SyI1jTYrX-PgAAAA
|
||||
modulus.i2p=HL47CwJWiovjoHMTK~2tK6~sYEghJapUNkeqOdnkWFsf985N8eCpRUQtz7fFJZrHCTHjqeO5hxvcFye~Jjtf~id7pFlaotkpmbnx75x5HCiTIBLTUfbPurjhTXNK3A0JFxQ5lmYd8S5WqNykdaZGHjhfDSC~PUcfJA398S611e2D5se1LKAp0qFFhbNi69Unovj7HdXYJLiATDhewt7tY6mMa-p3BeTcvu26MhET4itYBhzp12AKiqWrEQM-4tpCmK5K7gxECHOTuMtZu7SEVc4CYAgBIsILtT0YA84441o8h0kpsKGDPFuszMWtz5XSIFlO7mwpu6PCmBx6FZbaZFSQ8CghxqhrWGnGIno-Lr9vKeTpD-AT7rqwuUrZHfd3yhGhOA7i0nM6Uh~qXbvFkzK83kyyxbX4InjAZ4g897LixiCc2qj6~eeh1c9oNcZ01-ho5U7lXUo5WrfG1-N7DeH2xkWGzFrjlZ3dXP8w~f7osxtth596Jz~cY8xNacMuAAAA
|
||||
xolotl.i2p=byBX2FzIeKKRoUStOzidJ6jni4dkWBNK4x3khxgNo8NlJ8HqLl2MlgxlRsvhTHQy5L1GvTC9DYpnW0tE22Kl9QkPIGPikBLvwePT82gsRCxXOJ6CF8JiK0h9~giTOrRmguIo7d8DpDF3Sw7a9VVJf~9Dxs4IMCMPre36rPdmqkYSTZcfITfWCG1M1xnxQz9OuB6YKnnYcLvccSAcOTrWFEeiPHC0CsAo1EmJekmEGCK3lkNBRomfw05uhLqA4mFQgZbvHfSDhDv1eEUeQq8YBk4-vi4AsRjdmgLL4yduqoYnLgTYL6OvWuJ60EdxPkuZUzW8~5MGZfwKQLc4G0YmAjgLlQi1sdXT4HFFLNRvG2GO956Eay9Z3eLO2K7EvxY0C9MQ5n0LullF5NJD-V509h7kBPuItUC0haicVHXXwcXW-Lx36biz8apA9D24vMWvq4KLystsrtMetH1q1oyS4jA5BXWf~6FA~eCoZrX4lgnHJ6MHPCEmlUcQPrEvApIyAAAA
|
||||
freeciv.nightblade.i2p=mDlAeW1BD7ictjta8G0YwebMBmATFIWVXrVF6gpm3A13NMi1LIaq5da~zuQBWD3BLYmblE-3-U4snRHttVJBr-e9jAvy7ZBskGqie30JbzPbTBzLJWqdpaKzahI-eiezoDgVyhOstCBbjFc3CW~ckiLfj4MVS2nCV7qgujSWHho8mspb8lS0uJJk0XQImYx4QWY7KFCz2CaHY8JX~m05~81hTdJLZUjhDVBXsjj0wW-lE8mDZckiCn7ZaRSASBhFHiZnB6aGdY32Ltad6SjH0LngOcVbR43DYSHODabD6igb90c00wruQRMFarQSBBAk31uWnjftggllcA0X77NILD0PKG8RGa2fRcqyyVveGgYWhsl8vInVI-q-xI1PWairamHkzd-du58cmxzkqYZQR~XX5tPR3lQ-avScr0HgxHkMuTZSxEh72BcQP-qw2m0mPDrE445EPw3ipk8pRQi6H8lS0kCfDi8DBEygnqoLIqu35wrpEICCyog1buvppZTfAAAA
|
||||
curiosity.i2p=pka8sWaYxpm1U9gX6F7WJ56Kl12Y~Fks1w0O3DnpE2bfRUZldWpFdtnB6mHhqyinZKJWJVwVR92uFpQPdLtwjfCQtVzw7zXpndXG05QeRk4viRd6mxRua8xBgc2IFhXRXUDP3sSZT6aKFyP6S-R8yGkXID5fxrO~um5aBmHGalDohXHdPxbqrBbSWqjKHr35f7zSiJkCCRxDMGqWkrVuzoZIhJIVeRZxYaubKW9R-oJdmDqhtQeP7Au7IFzno66-fa9gsGWCWAyoJe0dk4tKGZA~Q-qlwW1I3esAnp2LPwlkrqPL-A5xqw1Gdwgh93rKGtUV41wKlhubfEiUXbkDgw6RLcpxXKbQxkJPUGum2-B9QVraAanVB1NDsW2nJvK0lb7SGgEHrENHW~Z5X8CANURb5PHR4CRcp~xwrbS3DPYAoiah7Rd7-PqcbXHxSu5jl4sVm3pZYKbo8V-PLKxIYzSWUhrmj1wGRTizeml0xvl5ysoDc5p2srCT-T4ihrKrAAAA
|
||||
anonymnet.i2p=Iku15m2pHtAfphzLKbhptluZuJ2FSst-b6WaiP-DWLue579sGChPuZEVxnbriFouidM4hw2Kvud1AeAYm632kDZZzIBf5EyCEdAPwc9R6cfBqe2N4hcvAXyWH9jevGMNe~NMOnjNvl8rKm2bGcEprvo1FPXKA1Ene2ATPViBVg-2xQyuZs9ZcU8rSi9~PrtG05zepAwfAGM2kIhNdF4biECXT-SLSxkU9An3GtAZjNkRMdiMPSY94mZWEalFbscuL8mlhl4xFg7XsnA1TEn6KaMnBjuf3FV9XSlXZ7pUD87BrRZYFHA0ujw5FqGu~-qLuIkbUpyhYz2rIHxNNJHm9l3T8yvumCanwr39xvganMLAD4nw~i0PKqQ5tLx0WBo64-GMz8Rbhfkhhj4a09qeR6OmDMwiyHoBgv9NDM6TCYBbLFMjf6X3wbcap4oOTNXvO3RG5T7kF-1RJ2IH6V3SwL9JpdH51fTo2WgBL9cESCvGntRM9g~EFyGyMoBAcmilAAAA
|
||||
sasquotch.i2p=6Hv24DvlxKauUfLHN4cPJd13cRyFq1wqaCb95r7fCYvhdFzluuZLDBYCM3w9GM3EVyAXS8uz0BCy9ZYncWXCsFQYejkTj~pTJEo5QjM1DszuUAGvDrqlm21e-ZwzEY817dIQCp9dQShfSnP41J~jVktE3ryMmtzAnCIZ~nMUejc9wManQG4muxuyUADdIiBIp-MXOAdXeEaaP0~5WPZhf0okm6uJd~fvO4h1Sy-CQuuJzWKYzDOvHFu-~9ONYQV8EdP4wovC15uHgX79YwAd8bpNTcfzJN9ypr9cQ0zGxYzDuK9LHaSD5MXQ8Hu2RgIrKUfb~osG4MQuYalBkUr3dpLzXLEokNIPk~BI~fI9AuG27wLI47fvOUB8Zbu1J9rSgz-J-~x8Tp4UFvRKDJ2N~5rj9mMdm9iO~U8DJvkOjjRraXhwqh3YcrnhHLPia10jvu72dAGi~S4bxiHuEcDn1JZIj64Jb6TC6xfhwEn-uoE~dqXdbr0MMoVcDsOP5dPjAAAA
|
||||
orz.i2p=GALU66G3Deh71g1COXAWKQvwVB2ULbf6ALTvc-vNHfZ~jkLhGpxmXOlVOu17hfWhB~whwj-~Hn7dxLgbXO1WXb-xmvKKIgxUssDosoSbM2v~LgzJq~iIkeoN9VQe4tz2pMql1-f3kV8-AHZIILR7tY61TjDLQbZSVhT0S7FIcTQulbct8wjP-p4Dvp4XUUFXJDRqIpZB9beNALEO-SYpFuadDeavDY4iUhNcERDXlj38ginXceHm5SXaiUNTr~qXzNNuR0r5FsAgjHLuy3UgnxM2aL~j7PXBieNL~mLs~YcYRYvZVtG~SXKQjUqw5iUJYYutgqHsiT7IrQKZ~FgvIYJWaZBgF-84WsfHgCw6jECkiiLgUxh676iNqMSfTkp0KMgjt~ekU9aWpZdiaD5KV2-phiuVMdEVbXCGfLnwSqWIQIrSAAXvsjL8ew7sCbtBOriGKUzeL~rBBltL6gSVdxn92fVdSz2XWGExvaT856ahgOtD8RFqCQTAUm~63xuSAAAA
|
||||
microbleu.i2p=V-3EgQik4jTtYyE4OXHBNl2kslSh-1g7SvtKvt-xzm32Q0zt07meIq2Brj1tkv~xll8t1gyfvy0Wn1n7Pcf4tlSEQ2KfJm6oHv-ZIovxewn420yl8cLgbB-dtoiY84fRxl8pS2GTHL~SOFOzussSSocKIBay71ODyhe4mJdtFA76LY6ycgsFIxK4U~Hb5YcIbenO3-94Oc7PXaRt4XmQ-7C9ZKAJXhLdlQGF3407gituMrhnppwQMSQP2ULJEBiLNtB7h1KasNn0Ao~HNf7bsJyCB29YGgIESIIAZxrBFNsjOpYg4WE3iWfzU-C0ohOCIvQhMXS0jPitke9R7Oor8TmJNagfZVnE2zg2oIPP8uKqf~kFTugeI3dUrlfdSYr-rvzEGzRMOFIT9GBEXnuNPnX3tUHD0LNewP-D3VvnT6Pu~0kc7s8gyjc5~gI3vj8gn8gQnnFnz6BTYfqLufF7UQnJtEKrCi1eAG8Dnbc6vaoA9qoAEXAtN5SFXiprqwBvAAAA
|
||||
www.postman.i2p=r8Ti6CtRJtSNAhxaoJuHZnbhAhjrbHIzMAVsuCNmLA7NO78mHvqLMk0HjQXou5fpnE40rCz5mxg-Zfz6J6B0rpE-UiqiozIC1cM-H-XM09Ftu6Ta97BeQ5MdrjtzJlagwXNM1Cn8k35UAdJQR2CfHQfJv0BUGVmkU8-D42fLqAVuRU9WpmA44YNMXJMT7kSqiZxKPdnXbpfst2h6ERLqGbqgCEToaH6NOyA8Lu4FJbOfkzfhrVIWHCiqn1FaAUK2Ie1POhfo8blfhQ1NdgkxGnTeaD1MJolI1qatpBWpsuiPlfMy7rxzTmP2dwpi-QQEdISi8U2eag3jsKGopQXwyn7Rx4zPQd82e9LCpiXWg2HVco1QV4H9z2alSHVJkWU-jC7jzQkDe-Iws-ZfEhKENRDps9Ev93KU-5-fohZZ614Ia0iDUs9RxP3mOM-RTiers~2B7Iq5-6hNMEoIzPzGbMKrrLs1Bos6LoZmIwGRS5pvlAis7usHjmBCy2hwqvi8AAAA
|
||||
smtp.postman.i2p=AUVlGWmbU0qNUBGvu1ls5OQcdZNjq7k1OPzqkhheGlc3HoQFi97-3BZevo4ThjL0WxHoBIMagAfXjAEm7EegzYqkfGtQ5TpEVAxg01eIGO-Lqq46MqbOFX~edpgi9StZIAPaXJps0MPtSfh0FsL-N5PTW2nqkITrMPxOuhyl8CvAdR~TxHSImMI5nNzCW39xkDrEBx5Mkn1s~xm2XdhyttG2z~g6~nec4X3rpV0sO1Fq2T1sgaKcHWUvJofzUV1y~bKnltJEB~KZpkkOxjz3SdcJzn8SPblyWAm3SUiAVY8ev2XwSaLl7-xe2bQtrnjbPfpHZ50yhGY-00wTcXEfSgt20DkibP7xg3cSAcVFla2IiGeJc~4WTCP3vkBipTnSFdNr3Ez2kCEa50kMiRfDkIk4S2E64~JBrgyNURXL4YNC~FV7qaK2gqHUJkhRiRQP2Hbq2lDygJGFjr2vIi0TBoZ0lWaX6cu8Jywhp-jZgrvun-F~n87iRvnNjkjuG6BYAAAA
|
||||
pop.postman.i2p=W4ZehJpFv9HnM4qnWb6c305H1vWRoghgSz~UXVVl7AM6cNYPU~DHzI0ezxyYIcsywhDvRdSvN5QQSyb2t-waFRaoMxmub9Z68uvcNPjAyG1Hc-igVbcmiGKo1RwXXO1JTzaAFE8NB2mvZmpksPDks0ugcd3AzBrrkxsqt8KLYSXBc7hDM59YUGl0j59NUZoE3tJgZlQ~fYr4P4P9VetBgVQ5mJFpwF~RvM2frx9zQ2SonCSTNFR88MEUJ6EoZUTDG-iz6mUVv2qOanAD1ZfSmmMZpbtFLovqvUGv8JLxFhFdkNmt3AmIZzPjmvrAu2X~VnAhX80Wrvba8df9w0qtplH5LYBykmN~wndjcQxOH7~LbGeJ-8q4DHf-DSDPFyn6L4uCk35kCSGXjEf1f44DSHU338Wiagn9ut7twiFSf8NLXvKV2-uWmx~twDLTd9cEjCEBm7ZXMaqWTK1kOGj0nlybm~mgMW-~IRnb6alnR0GMxAE-6fnWS52PJtmWU0ToAAAA
|
||||
jake.i2p=BzdF-Ib~jWRj9i1hypIasw67yv0YDEdCqloJr4Qq2Wvkt56slqzd0Qri6FQnWsGfTpmilvGI1H-7WAyU5KXc~nQ7F7KB~Im9cI1mIeMKeGK4Yzb6jV5SHctDZw2j1hqMpdjU76r45WiOgiAaNFin10SJ8IriNqce9VehnOupB53tpvoj1GnEIyxxaOsSDmxIakFZ8MsLW~s9wyxnlfvP-iOXLMpM6Achhcmxj-DWDcjwK-6rvLYoG6SY5vmpPNzhuyAa-8di8N3zBxL6WTf1Ox9UQrpXXZ1luYDUNxpFfPjzl9ZPpv4Ax6QzJvWn8B85GYs9ZkS1bpbtbbmQ1DTlOpwFMmidr0vaf68hNGvVY5yUgPZy28s8jvrz4AMEfAGlsozRkxr2JRwm3Oj3dqeW6ICKRwnThkjnXnGhQiIDV~bDfkgBzWvh4TyIYm5NBwAYFZdSx81Eno4sthfElFTeSDj0TjCKegNmAd6t4D82JMk8abws0MC-pIqaNLZRU1YVAAAA
|
||||
jabber-2.i2p=62UDEWG936i-w144HMYX~1aiRnvIkRg2Rbjor3KXUPfKaPXx6A6R54nhLYVI0Zt3Y6bquRIlvZd1KKb6VnQ~GbPhDKvOIzrSP~G7IajZOdncG4QlsuJYwOVVOSVAkR55pxdwwVHXkoR4~4hlahYGvGAayvvDxxWojr-dWg-IIUnEv8hjjstUfphSy~Jx17de0G~8n0DSZ~YKu83Cnu9sSydoXqqczq3KChFDjfUYtohNiZA8lXfrfv5K3pEeTOCemE1rDflPGu~5fawk3G1xNetuZQCKdkFNSxtkRpj3Vm2ej1ApLUi92zog3ekBbxEwfiP0DfC4BvdwgAimVGH8MpXS4BijlDNNbCWak6Pdr24OqVwLJXzWfqb11WFH-mc2JYJCPhJCvESYs~iK3JOZ0QzbW9F-495oB6RD-9guK9bBQHC1lMsNVhaj3Mh8gohKghvy2MrTNbirHKDjyyiAj5RrT1OjWoZNBMvXPEZEtEowuzZptP-tTf19mhGfPFOjAAAA
|
||||
identiguy.i2p=EhDXPsItHi7Dfx8~~0iHPzkjiK1568wqEifARTr-ngIznwVaBmeEnSHXfLkA-7F~Nrqw95yQLlZpja6N1DyQNtJXPx-Db3apXuKwsuTNSGgZme2kFHXPh7PCsfzARwxn4d2-Nx75V4BSCgQr0gRjDa~L~JmtxPRUpZX2NyBvD0w5MSaD~9t4RuCRQ2gVDpUUDcTh2jkm2bX-R9vRIHhCZLasHxDR7rJC9-38uMsQ6ywd4ulQQYIs0kB1sEofdXUypyqphQU9xIxz7azgzKJp~dHnJpJ6SpaH7UrDN-YfOkAvGFBbk9k-u3NGl571Y205dQF~l3XHvVKf6NS9~JvtVh0JibwQ2qLVPy3Y~TtViffvpunNGOrfnVrT5-1c3lWNHx8gTalY3R-vU5rDd8Bz3AhNM6KWktZq8LiHHhJUxIkebXZsid-f2g~QgRRywxG7ksIlKsCMEn076f03L-oWJIlrAg5MdQd-qlg1Bs1IhrR8YT8jNYrX1bGdlmPrJDpiAAAA
|
||||
detonate.i2p=6swCa-wAcpBdiCnMdObQlQ15isZTpAV8rlArR54Q5dZkALb5iMCjt0hYMoz89R9ycmtxcTNkgdNX37JsuAjeBFk~nUI11EGSyu-T3AOJg0sxUkoESuxqyLajqDSx8WVziI95LM8zOg~Gv0hpObbziMzu8hzLML2fTWF681sBA6gFzVSnjK9zA3cbWX7f0zGo4crruXsjrmJqWfS2~fNt5RYwHth57u-rZ8a4vl58uyv1Gb1~FAlyjyGMcr7eaQq3UJdEgHOHtXZSoGXZSAerpFreeHqC6Mu~-~-T7iph3jlfNyJYxLOBD8QKMPW~hGW9l6ips5zcc0KFjX2PWH5y4nbttb1LNvI6zn-q1F5t-ITP7UIovWcINfSzy5YoiuT1K6ZSay9DQSeuldBt9ajXDCkJKxOiZlB9C0RAmd9WDyAIKt~HhdnlpA~yOUuthBzrAe7iXt7lUqY3Rwqiby1CgqPKY941ChVY57AwWyxG4clM-a2MB8GuBImfqhp2LDFWAAAA
|
||||
tinyurl.i2p=mfjh9H8RPkh6vYTSpFoghxSnrOzwBeE8ri3mIKwQOak0v0382ZawEDavYKcjIGg6xqzC0KA8KcOu0h151HzHZgCq2Qbzb6VGGSyyXqtsPGxSIjifIveSkIqNZE~ThySOiWXJ9Qp1EmFe9zA2m6Ey~lZL~yD8ackLzB6VY32xQN7y8kvPSt39Boty0mPXSvS5faVAd0UkbuEHOCP~~Z-E~WB2L2-ZWUD~P3zrZK560fa9-aU8g6pCjIJ8Vqx19tbkvYA~IUPtgXsgmjX6hWLpxN1oHE18jsj1IcAu0TCfldWyOtqcGOeBo20BVLZnx7-AqS0TiZhoIj7nog3x3xoOH2w6JomdJ9AT~4Z08pz0HvymVud0PXKOU7yP~QBj1~Us05-k0F-W6SmU6906l5YfNoXACurwy0VtgTmv7oJyOWpPdhFkZ98PwPL16W4iYsvZx6lDxvCxViAkYLw-fAkmueKrn2ZBau6TlhksvZt-Fqyjs~iZ4yme1243d87IZNb5AAAA
|
||||
b.i2p=b2Ol9hg3uAOK3mB7sK~ydOZQlZIcc0Cixh~M89i71VgzxsK6NYCvFuiW8YeDZ9p3e-cNQrGTxrV6405km0F~pfKKyu09E-~-zAM19SHFmVWbT-XLEpfo9krLQu7416VMRPsPfLISzRU2wAptW2N6CuQmOEp8telmilhUiEqYTC7GBzmo-XNIKs9XSs3-6wSLkZ0haRJtS7YDdmjrDE-UXhu55E7VhUnm7TAxSH4bdUtM5tDUU7Q8lq~t7y9qSu0EWwvMBnkR9-p8SlcVBr-Zy4aG10OUcvnA07TA~Y8OKtEzJZ1PvzuZVIKerAQXuLK~SMB-9Xni7v7pbGW6Lok6dG9KJjrLORTpURAFgC~mux096li0VcotR6eMfBwGH9zLWgBruknix3TCrmUoafzCP4vyuDrugN8-0k54HZemGb601~9PJQYwyP-V4b33LJdq1d-tKDvgFqR3mm-YrEgZbUQ22BSsI3Jx~tWc3hft8KHkfF3zV6Op4TB04XeQ-WupAAAA
|
||||
beyond.i2p=WNtBKmOowfzhsCX7dWwddaKVZttpm6aSYDiXzExh2ABPS7Ts9WBZxkqWS8CdEHq6ZSOUGzT6kyQYRGmF9~uTZ~nkI-UG8Hqh6uibT0H6-NOR0k2Qjp5y49VB9VRHJ6I2Vxg1uo09edWYKUatMgl7GESInmhZPDF4NOAq1SD6TQpLfAvVxPWglISZWg2Br3K-u9cHqH3Q0fvyy-Cka9ALZiBkXlZ5vccy5B2KE2JXdI1fAn1TLx8dKuR11Xsd-aNjPofis1Ak-cTia9YjKYSiO4v0A7uguQwBZCmTwI-uXLzUeOZjg69NuIhFUi2hN3tuNvCqAg73ct0lAMnfZ1d3oT9BGW6Aqh4fMTXr8MPT0Qpq9te7KF7L5q-LJ-9JFnYVvjx0P-6YUe-mH89HwyL4nip-ET8jzgIRyYE-WNzc1Q5KOGcrQVZJl7Vv5lziCCMxYoSKqiThps1vv-lC1uEyPbMYANkJVJdx9bnTqlQ8r9rlmFFQEmBCojc7LeRZpslTAAAA
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
$Id: install-headless.txt,v 1.1 2004/09/01 21:20:03 jrandom Exp $
|
||||
$Id: install-headless.txt,v 1.2 2004/09/02 01:54:37 jrandom Exp $
|
||||
Headless I2P installation instructions
|
||||
|
||||
1) tar xjf i2p.tar.bz2 (you've already done this)
|
||||
@@ -9,9 +9,6 @@ Headless I2P installation instructions
|
||||
If you're having trouble, swing by http://forum.i2p.net/, check the
|
||||
website at http://www.i2p.net/, or get on irc://irc.freenode.net/#i2p
|
||||
|
||||
To have I2P run on startup as a daemon, after the above, run:
|
||||
sh install_i2p_service_unix
|
||||
|
||||
To run I2P explicitly:
|
||||
sh i2prouter start
|
||||
|
||||
@@ -24,9 +21,6 @@ To stop the router (immediately):
|
||||
To uninstall I2P:
|
||||
rm -rf $i2pInstallDir
|
||||
|
||||
To remove the daemon setup, run:
|
||||
sh uninstall_i2p_service_unix
|
||||
|
||||
Supported JVMs:
|
||||
Windows: Latest available from http://java.sun.com/ (1.3+ supported)
|
||||
Linux: Latest available from http://java.sun.com/ (1.3+ supported)
|
||||
|
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
|
||||
<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
|
@@ -13,3 +13,8 @@ clientApp.1.args=sam.keys 127.0.0.1 7656 i2cp.tcp.host=localhost i2cp.tcp.port=7
|
||||
clientApp.2.main=net.i2p.i2ptunnel.TunnelControllerGroup
|
||||
clientApp.2.name=Tunnels
|
||||
clientApp.2.args=i2ptunnel.config
|
||||
|
||||
# run our own eepsite with a seperate jetty instance
|
||||
clientApp.3.main=org.mortbay.jetty.Server
|
||||
clientApp.3.name=eepsite
|
||||
clientApp.3.args=eepsite/jetty.xml
|
24
installer/resources/eepsite_index.html
Normal file
24
installer/resources/eepsite_index.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to your eepsite</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to your eepsite</h1>
|
||||
|
||||
<p>This is your eepsite - simply edit the files under ./eepsite/docroot/
|
||||
and they'll be reachable. The 'key' to your eepsite that you need to
|
||||
give to other people is shown on the I2PTunnel configuration
|
||||
<a href="http://localhost:7657/i2ptunnel/">configuration page</a>). </p>
|
||||
<p>
|
||||
If you have any standard java web applications (.war files) such as
|
||||
<a href="http://wiki.blojsom.com/wiki/display/blojsom/About%2Bblojsom">blojsom</a>
|
||||
or <a href="http://snipsnap.org/space/start">SnipSnap</a>, simply drop their .war
|
||||
file into ./eepsite/webapps/ and they'll be reachable at
|
||||
http://$yourEeepsite/warFileName/</p>
|
||||
|
||||
<p>You can also reach your eepsite locally through
|
||||
<a href="http://localhost:7658/">http://localhost:7658/</a>. If you
|
||||
want to change the port number, edit the file ./eepsite/jetty.xml and
|
||||
update the I2PTunnel configuration accordingly.</p>
|
||||
</body>
|
||||
</html>
|
@@ -38,14 +38,53 @@ tunnel.2.option.tunnels.numInbound=2
|
||||
tunnel.2.startOnLoad=false
|
||||
|
||||
# local eepserver
|
||||
#tunnel.3.name=eepsite
|
||||
#tunnel.3.description=My eepsite
|
||||
#tunnel.3.type=server
|
||||
#tunnel.3.targetHost=localhost
|
||||
#tunnel.3.targetPort=8000
|
||||
#tunnel.3.privKeyFile=eepPriv.dat
|
||||
#tunnel.3.i2cpHost=localhost
|
||||
#tunnel.3.i2cpPort=7654
|
||||
#tunnel.3.option.tunnels.depthInbound=2
|
||||
#tunnel.3.option.tunnels.numInbound=2
|
||||
#tunnel.3.startOnLoad=true
|
||||
tunnel.3.name=eepsite
|
||||
tunnel.3.description=My eepsite
|
||||
tunnel.3.type=server
|
||||
tunnel.3.targetHost=localhost
|
||||
tunnel.3.targetPort=7658
|
||||
tunnel.3.privKeyFile=eepsite/eepPriv.dat
|
||||
tunnel.3.i2cpHost=localhost
|
||||
tunnel.3.i2cpPort=7654
|
||||
tunnel.3.option.tunnels.depthInbound=2
|
||||
tunnel.3.option.tunnels.numInbound=2
|
||||
tunnel.3.startOnLoad=true
|
||||
|
||||
# postman's SMTP server - see www.postman.i2p
|
||||
tunnel.4.description=smtp server
|
||||
tunnel.4.i2cpHost=localhost
|
||||
tunnel.4.i2cpPort=7654
|
||||
tunnel.4.interface=127.0.0.1
|
||||
tunnel.4.listenPort=7659
|
||||
tunnel.4.name=smtp.postman.i2p
|
||||
tunnel.4.option.tunnels.depthInbound=2
|
||||
tunnel.4.option.tunnels.numInbound=2
|
||||
tunnel.4.startOnLoad=false
|
||||
tunnel.4.targetDestination=smtp.postman.i2p
|
||||
tunnel.4.type=client
|
||||
|
||||
# postman's POP3 server - see www.postman.i2p
|
||||
tunnel.5.name=pop3.postman.i2p
|
||||
tunnel.5.description=pop3 server
|
||||
tunnel.5.i2cpHost=localhost
|
||||
tunnel.5.i2cpPort=7654
|
||||
tunnel.5.interface=127.0.0.1
|
||||
tunnel.5.listenPort=7660
|
||||
tunnel.5.option.tunnels.depthInbound=2
|
||||
tunnel.5.option.tunnels.numInbound=2
|
||||
tunnel.5.startOnLoad=false
|
||||
tunnel.5.targetDestination=pop.postman.i2p
|
||||
tunnel.5.type=client
|
||||
|
||||
# another irc server, linked with irc.duck.i2p and IIP
|
||||
tunnel.6.description=irc.baffled.i2p
|
||||
tunnel.6.i2cpHost=localhost
|
||||
tunnel.6.i2cpPort=7654
|
||||
tunnel.6.interface=localhost
|
||||
tunnel.6.listenPort=7661
|
||||
tunnel.6.name=irc.baffled.i2p
|
||||
tunnel.6.option.tunnels.depthInbound=2
|
||||
tunnel.6.option.tunnels.numInbound=2
|
||||
tunnel.6.startOnLoad=false
|
||||
tunnel.6.targetDestination=irc.baffled.i2p
|
||||
tunnel.6.type=client
|
||||
|
160
installer/resources/jetty.xml
Normal file
160
installer/resources/jetty.xml
Normal file
@@ -0,0 +1,160 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
|
||||
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Jetty Server -->
|
||||
<!-- =============================================================== -->
|
||||
<Configure class="org.mortbay.jetty.Server">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Request Listeners -->
|
||||
<!-- =============================================================== -->
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add and configure a HTTP listener to port 8080 -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<Call name="addListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.SocketListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.util.InetAddrPort">
|
||||
<Set name="host">127.0.0.1</Set>
|
||||
<Set name="port">7658</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
<Set name="MinThreads">3</Set>
|
||||
<Set name="MaxThreads">10</Set>
|
||||
<Set name="MaxIdleTimeMs">30000</Set>
|
||||
<Set name="LowResourcePersistTimeMs">1000</Set>
|
||||
<Set name="ConfidentialPort">8443</Set>
|
||||
<Set name="IntegralPort">8443</Set>
|
||||
<Set name="PoolName">main</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add a HTTPS SSL listener on port 8443 -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- UNCOMMENT TO ACTIVATE
|
||||
<Call name="addListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.SunJsseListener">
|
||||
<Set name="Port">8443</Set>
|
||||
<Set name="PoolName">main</Set>
|
||||
<Set name="Keystore"><SystemProperty name="jetty.home" default="."/>/etc/demokeystore</Set>
|
||||
<Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
|
||||
<Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
|
||||
<Set name="NonPersistentUserAgent">MSIE 5</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
-->
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add a AJP13 listener on port 8009 -->
|
||||
<!-- This protocol can be used with mod_jk in apache, IIS etc. -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!--
|
||||
<Call name="addListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.ajp.AJP13Listener">
|
||||
<Set name="PoolName">ajp</Set>
|
||||
<Set name="Port">8009</Set>
|
||||
<Set name="MinThreads">3</Set>
|
||||
<Set name="MaxThreads">20</Set>
|
||||
<Set name="MaxIdleTimeMs">0</Set>
|
||||
<Set name="confidentialPort">443</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
-->
|
||||
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Contexts -->
|
||||
<!-- =============================================================== -->
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add a all web application within the webapps directory. -->
|
||||
<!-- + No virtual host specified -->
|
||||
<!-- + Look in the webapps directory relative to jetty.home or . -->
|
||||
<!-- + Use the default webdefault.xml in jetty's install -->
|
||||
<!-- + Upack the war file -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<Set name="rootWebApp">root</Set>
|
||||
<Call name="addWebApplications">
|
||||
<Arg></Arg>
|
||||
<Arg>./eepsite/webapps/</Arg>
|
||||
<Arg></Arg>
|
||||
<Arg type="boolean">true</Arg>
|
||||
</Call>
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add and configure a specific web application -->
|
||||
<!-- + Set Unpack WAR files -->
|
||||
<!-- + Set Default Descriptor. Resource, file or URL -->
|
||||
<!-- + Set Virtual Hosts. A Null host or empty array means all hosts -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- UNCOMMENT TO ACTIVATE
|
||||
<Call name="addWebApplication">
|
||||
<Arg>/context</Arg>
|
||||
<Arg>./webapps/root</Arg>
|
||||
|
||||
<Set name="extractWAR">false</Set>
|
||||
|
||||
<Set name="defaultsDescriptor">org/mortbay/jetty/servlet/webdefault.xml</Set>
|
||||
|
||||
<Set name="virtualHosts">
|
||||
<Array type="java.lang.String">
|
||||
<Item></Item>
|
||||
<Item>127.0.0.1</Item>
|
||||
<Item>localhost</Item>
|
||||
<Item>www.acme.com</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
</Call>
|
||||
-->
|
||||
|
||||
<Call name="addContext">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.HttpContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="resourceBase">./eepsite/docroot</Set>
|
||||
<Call name="addHandler">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.handler.ResourceHandler">
|
||||
<Set name="redirectWelcome">FALSE</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Request Log -->
|
||||
<!-- =============================================================== -->
|
||||
<Set name="RequestLog">
|
||||
<New class="org.mortbay.http.NCSARequestLog">
|
||||
<Arg>./eepsite/logs/yyyy_mm_dd.request.log</Arg>
|
||||
<Set name="retainDays">90</Set>
|
||||
<Set name="append">true</Set>
|
||||
<Set name="extended">false</Set>
|
||||
<Set name="buffered">false</Set>
|
||||
<Set name="LogTimeZone">GMT</Set>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Other Server Options -->
|
||||
<!-- =============================================================== -->
|
||||
<Set name="requestsPerGC">2000</Set>
|
||||
<Set name="statsOn">false</Set>
|
||||
|
||||
</Configure>
|
@@ -39,6 +39,7 @@ wrapper.java.library.path.2=lib
|
||||
|
||||
# Java Additional Parameters
|
||||
wrapper.java.additional.1=-DloggerFilenameOverride=logs/log-router-@.txt
|
||||
wrapper.java.additional.2=-Dorg.mortbay.http.Version.paranoid=true
|
||||
|
||||
# Initial Java Heap Size (in MB)
|
||||
#wrapper.java.initmemory=4
|
||||
|
135
projectplan.xml
Normal file
135
projectplan.xml
Normal file
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="i2p" company="i2p" webLink="http://www.i2p.net/" view-date="1/9/2004" view-zoom="6" version="1.10">
|
||||
<!-- --> <description> </description>
|
||||
|
||||
<tasks color="#8cb6ce">
|
||||
<task id="0" name="TCP transport revamp" color="#8cb6ce" meeting="false" start="13/9/2004" duration="13" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="6" type="2"/>
|
||||
<task id="1" name="Refactor transport.tcp.*" color="#8cb6ce" meeting="false" start="13/9/2004" duration="4" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="2" type="2"/>
|
||||
</task>
|
||||
<task id="2" name="Session tags" color="#8cb6ce" meeting="false" start="17/9/2004" duration="2" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="4" type="2"/>
|
||||
</task>
|
||||
<task id="4" name="Autodetect IP on connect" color="#8cb6ce" meeting="false" start="19/9/2004" duration="2" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="5" type="2"/>
|
||||
</task>
|
||||
<task id="5" name="Web UI updates to notify errors" color="#8cb6ce" meeting="false" start="21/9/2004" duration="2" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="12" type="2"/>
|
||||
</task>
|
||||
<task id="12" name="QA/support" color="#8cb6ce" meeting="false" start="23/9/2004" duration="3" complete="0" fixed-start="false" priority="1" expand="true"/>
|
||||
</task>
|
||||
<task id="6" name="0.4.1" color="#8cb6ce" meeting="true" start="26/9/2004" duration="1" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="7" type="2"/>
|
||||
<depend id="8" type="2"/>
|
||||
</task>
|
||||
<task id="7" name="Tunnel revamp" color="#8cb6ce" meeting="false" start="27/9/2004" duration="15" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="11" type="2"/>
|
||||
<task id="8" name="Spec structures" color="#8cb6ce" meeting="false" start="27/9/2004" duration="2" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="10" type="2"/>
|
||||
</task>
|
||||
<task id="10" name="Tunnel length randomization and ordering" color="#8cb6ce" meeting="false" start="29/9/2004" duration="3" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="9" type="2"/>
|
||||
</task>
|
||||
<task id="9" name="Implement tunnel processing and building" color="#8cb6ce" meeting="false" start="2/10/2004" duration="5" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="13" type="2"/>
|
||||
</task>
|
||||
<task id="13" name="QA/support" color="#8cb6ce" meeting="false" start="7/10/2004" duration="5" complete="0" fixed-start="false" priority="1" expand="true"/>
|
||||
</task>
|
||||
<task id="11" name="0.4.2" color="#8cb6ce" meeting="true" start="12/10/2004" duration="1" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="63" type="2"/>
|
||||
</task>
|
||||
<task id="62" name="Streaming lib" color="#8cb6ce" meeting="false" start="13/10/2004" duration="18" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<task id="63" name="Packet spec" color="#8cb6ce" meeting="false" start="13/10/2004" duration="3" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="64" type="2"/>
|
||||
</task>
|
||||
<task id="64" name="Implementation" color="#8cb6ce" meeting="false" start="16/10/2004" duration="10" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="65" type="2"/>
|
||||
</task>
|
||||
<task id="65" name="QA/support" color="#8cb6ce" meeting="false" start="26/10/2004" duration="5" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="66" type="2"/>
|
||||
</task>
|
||||
</task>
|
||||
<task id="66" name="0.4.3" color="#8cb6ce" meeting="true" start="31/10/2004" duration="1" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="69" type="2"/>
|
||||
</task>
|
||||
<task id="68" name="UDP transport" color="#8cb6ce" meeting="false" start="31/10/2004" duration="19" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<task id="69" name="Packet spec" color="#8cb6ce" meeting="false" start="31/10/2004" duration="3" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="70" type="2"/>
|
||||
</task>
|
||||
<task id="70" name="Implementation" color="#8cb6ce" meeting="false" start="2/11/2004" duration="10" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="71" type="2"/>
|
||||
</task>
|
||||
<task id="71" name="QA/support" color="#8cb6ce" meeting="false" start="12/11/2004" duration="5" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="72" type="2"/>
|
||||
<depend id="170" type="2"/>
|
||||
</task>
|
||||
</task>
|
||||
<task id="170" name="0.4.4" color="#8cb6ce" meeting="true" start="17/11/2004" duration="1" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="122" type="2"/>
|
||||
</task>
|
||||
<task id="55" name="Cleanup" color="#8cb6ce" meeting="false" start="18/11/2004" duration="21" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<task id="122" name="Code refactoring" color="#8cb6ce" meeting="false" start="18/11/2004" duration="7" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="56" type="2"/>
|
||||
</task>
|
||||
<task id="56" name="Site docs" color="#8cb6ce" meeting="false" start="25/11/2004" duration="7" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="57" type="2"/>
|
||||
</task>
|
||||
<task id="57" name="Code docs" color="#8cb6ce" meeting="false" start="2/12/2004" duration="7" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="54" type="2"/>
|
||||
</task>
|
||||
</task>
|
||||
<task id="54" name="1.0" color="#8cb6ce" meeting="true" start="9/12/2004" duration="2" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="67" type="2"/>
|
||||
</task>
|
||||
<task id="67" name="Support" color="#8cb6ce" meeting="false" start="11/12/2004" duration="10" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="110" type="2"/>
|
||||
</task>
|
||||
<task id="109" name="Restricted routes" color="#8cb6ce" meeting="false" start="21/12/2004" duration="25" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<task id="110" name="Basic restricted routes" color="#8cb6ce" meeting="false" start="21/12/2004" duration="10" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="111" type="2"/>
|
||||
</task>
|
||||
<task id="111" name="Trusted links" color="#8cb6ce" meeting="false" start="31/12/2004" duration="5" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="112" type="2"/>
|
||||
</task>
|
||||
<task id="112" name="QA/support" color="#8cb6ce" meeting="false" start="5/1/2005" duration="10" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="113" type="2"/>
|
||||
</task>
|
||||
</task>
|
||||
<task id="113" name="2.0" color="#8cb6ce" meeting="true" start="15/1/2005" duration="1" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="120" type="2"/>
|
||||
</task>
|
||||
<task id="120" name="Support" color="#8cb6ce" meeting="false" start="16/1/2005" duration="10" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="115" type="2"/>
|
||||
</task>
|
||||
<task id="114" name="Mixing" color="#8cb6ce" meeting="false" start="26/1/2005" duration="26" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<task id="115" name="Tunnel throttles" color="#8cb6ce" meeting="false" start="26/1/2005" duration="3" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="116" type="2"/>
|
||||
</task>
|
||||
<task id="116" name="Tunnel pooling" color="#8cb6ce" meeting="false" start="29/1/2005" duration="5" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="117" type="2"/>
|
||||
</task>
|
||||
<task id="117" name="Tunnel chaffing" color="#8cb6ce" meeting="false" start="3/2/2005" duration="3" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="118" type="2"/>
|
||||
</task>
|
||||
<task id="118" name="Garlic delays" color="#8cb6ce" meeting="false" start="6/2/2005" duration="5" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="119" type="2"/>
|
||||
</task>
|
||||
<task id="119" name="QA/support" color="#8cb6ce" meeting="false" start="11/2/2005" duration="10" complete="0" fixed-start="false" priority="1" expand="true">
|
||||
<depend id="121" type="2"/>
|
||||
</task>
|
||||
</task>
|
||||
<task id="121" name="3.0" color="#8cb6ce" meeting="true" start="21/2/2005" duration="1" complete="0" fixed-start="false" priority="1" expand="true"/>
|
||||
</tasks>
|
||||
|
||||
<resources>
|
||||
<resource id="0" name="jrandom" function="SoftwareDevelopment:2" contacts="" phone="" />
|
||||
</resources>
|
||||
|
||||
<allocations>
|
||||
</allocations>
|
||||
|
||||
|
||||
<roles roleset-name="Default"/>
|
||||
<roles roleset-name="SoftwareDevelopment"/>
|
||||
</project>
|
19
readme.html
19
readme.html
@@ -43,9 +43,11 @@ to reach some of the following sites:</p>
|
||||
<ul>
|
||||
<li><a href="http://duck.i2p/">duck.i2p</a>: duck's eepsite, with links to other active sites</li>
|
||||
<li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li>
|
||||
<li><a href="http://forum.i2p/">forum.i2p</a>: an anonymous gateway to <a href="http://forum.i2p.net/">forum.i2p.net</a></li>
|
||||
<li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li>
|
||||
<li><a href="http://www.i2p/">www.i2p</a>: a secure and anonymous connection to <a href="http://www.i2p.net/">www.i2p.net</a></li>
|
||||
<li><a href="http://dev.i2p/">dev.i2p</a>: a secure and anonymous connection to <a href="http://dev.i2p.net/">dev.i2p.net</a></li>
|
||||
<li><a href="http://fproxy.i2p/">fproxy.i2p</a> and <a href="http://fproxy2.i2p/">fproxy2.i2p</a>:
|
||||
public gateways into two different freenet nodes</li>
|
||||
a secure and anonymous connection to two different freenet nodes</li>
|
||||
</ul>
|
||||
|
||||
<p>The IRC proxy is a gateway to duck's anonymously hosted IRC server
|
||||
@@ -60,4 +62,17 @@ the <a href="/i2ptunnel/" target="_blank">I2PTunnel configuration interface</a>
|
||||
You can also go to that page if you want to add a new tunnel, such as if you want to run
|
||||
your own eepsite.</p>
|
||||
|
||||
<h2>Want your own eepsite?</h2>
|
||||
<p>In addition, we've configured some software to let you run your own eepsite - a
|
||||
<a href="http://jetty.mortbay.org/">Jetty</a> instance listening on
|
||||
<a href="http://localhost:7658/">http://localhost:7658/</a>. Simply place your files in
|
||||
the <code>eepsite/docroot/</code> directory (or any standard JSP/Servlet <code>.war</code>
|
||||
files under <code>eepsite/webapps</code>) and they'll show up. Your eepsite's
|
||||
<i>destination</i> (which uniquely and securly identifies it) is shown on the I2PTunnel
|
||||
<a href="/i2ptunnel/">configuration page</a> - if you want other people to see your eepsite,
|
||||
you need to give them that really huge string. Just paste it into the
|
||||
<a href="http://forum.i2p/viewforum.php?f=16">Eepsite announce</a> forum, add it to
|
||||
ugha's <a href="http://ugha.i2p/I2pLinks">wiki</a>, or paste it in the #i2p or #i2p-chat channels on
|
||||
IRC (be sure to split it into two lines, as its too long for one).</p>
|
||||
|
||||
<p><b>As a note, you can change this page by editing the file "docs/readme.html"</b></p>
|
@@ -39,30 +39,39 @@ public class DataMessage extends I2NPMessageImpl {
|
||||
|
||||
public int getSize() { return _data.length; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
int size = (int)DataHelper.readLong(in, 4);
|
||||
if ( (size <= 0) || (size > MAX_SIZE) )
|
||||
throw new I2NPMessageException("wtf, size out of range? " + size);
|
||||
_data = new byte[size];
|
||||
int read = read(in, _data);
|
||||
if (read != size)
|
||||
throw new DataFormatException("Not enough bytes to read (read = " + read + ", expected = " + size + ")");
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
int curIndex = offset;
|
||||
long size = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
if (size > 64*1024)
|
||||
throw new I2NPMessageException("wtf, size=" + size);
|
||||
_data = new byte[(int)size];
|
||||
System.arraycopy(data, curIndex, _data, 0, (int)size);
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream((_data != null ? _data.length + 4 : 4));
|
||||
try {
|
||||
DataHelper.writeLong(os, 4, (_data != null ? _data.length : 0));
|
||||
os.write(_data);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
if (_data == null)
|
||||
return 4;
|
||||
else
|
||||
return 4 + _data.length;
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) {
|
||||
if (_data == null) {
|
||||
out[curIndex++] = 0x0;
|
||||
out[curIndex++] = 0x0;
|
||||
out[curIndex++] = 0x0;
|
||||
out[curIndex++] = 0x0;
|
||||
} else {
|
||||
byte len[] = DataHelper.toLong(4, _data.length);
|
||||
System.arraycopy(len, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
System.arraycopy(_data, 0, out, curIndex, _data.length);
|
||||
curIndex += _data.length;
|
||||
}
|
||||
return os.toByteArray();
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -124,63 +124,96 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
|
||||
_dontIncludePeers = null;
|
||||
}
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
_key = new Hash();
|
||||
_key.readBytes(in);
|
||||
_fromHash = new Hash();
|
||||
_fromHash.readBytes(in);
|
||||
Boolean val = DataHelper.readBoolean(in);
|
||||
if (val == null)
|
||||
int curIndex = offset;
|
||||
|
||||
byte keyData[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_key = new Hash(keyData);
|
||||
|
||||
byte fromData[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, fromData, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_fromHash = new Hash(fromData);
|
||||
|
||||
boolean tunnelSpecified = false;
|
||||
switch (data[curIndex]) {
|
||||
case DataHelper.BOOLEAN_TRUE:
|
||||
tunnelSpecified = true;
|
||||
break;
|
||||
case DataHelper.BOOLEAN_FALSE:
|
||||
tunnelSpecified = false;
|
||||
break;
|
||||
default:
|
||||
throw new I2NPMessageException("Tunnel must be explicitly specified (or not)");
|
||||
boolean tunnelSpecified = val.booleanValue();
|
||||
if (tunnelSpecified) {
|
||||
_replyTunnel = new TunnelId();
|
||||
_replyTunnel.readBytes(in);
|
||||
}
|
||||
int numPeers = (int)DataHelper.readLong(in, 2);
|
||||
if ( (numPeers < 0) || (numPeers >= (1<<16) ) )
|
||||
throw new DataFormatException("Invalid number of peers - " + numPeers);
|
||||
Set peers = new HashSet(numPeers);
|
||||
for (int i = 0; i < numPeers; i++) {
|
||||
Hash peer = new Hash();
|
||||
peer.readBytes(in);
|
||||
peers.add(peer);
|
||||
}
|
||||
_dontIncludePeers = peers;
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
if (tunnelSpecified) {
|
||||
_replyTunnel = new TunnelId(DataHelper.fromLong(data, curIndex, 4));
|
||||
curIndex += 4;
|
||||
}
|
||||
|
||||
int numPeers = (int)DataHelper.fromLong(data, curIndex, 2);
|
||||
curIndex += 2;
|
||||
|
||||
if ( (numPeers < 0) || (numPeers >= (1<<16) ) )
|
||||
throw new I2NPMessageException("Invalid number of peers - " + numPeers);
|
||||
Set peers = new HashSet(numPeers);
|
||||
for (int i = 0; i < numPeers; i++) {
|
||||
byte peer[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
peers.add(new Hash(peer));
|
||||
}
|
||||
_dontIncludePeers = peers;
|
||||
}
|
||||
|
||||
|
||||
protected int calculateWrittenLength() {
|
||||
int totalLength = 0;
|
||||
totalLength += Hash.HASH_LENGTH*2; // key+fromHash
|
||||
totalLength += 1; // hasTunnel?
|
||||
if (_replyTunnel != null)
|
||||
totalLength += 4;
|
||||
totalLength += 2; // numPeers
|
||||
if (_dontIncludePeers != null)
|
||||
totalLength += Hash.HASH_LENGTH * _dontIncludePeers.size();
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
if (_key == null) throw new I2NPMessageException("Key being searched for not specified");
|
||||
if (_fromHash == null) throw new I2NPMessageException("From address not specified");
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
|
||||
try {
|
||||
_key.writeBytes(os);
|
||||
_fromHash.writeBytes(os);
|
||||
if (_replyTunnel != null) {
|
||||
DataHelper.writeBoolean(os, Boolean.TRUE);
|
||||
_replyTunnel.writeBytes(os);
|
||||
} else {
|
||||
DataHelper.writeBoolean(os, Boolean.FALSE);
|
||||
}
|
||||
if ( (_dontIncludePeers == null) || (_dontIncludePeers.size() <= 0) ) {
|
||||
DataHelper.writeLong(os, 2, 0);
|
||||
} else {
|
||||
DataHelper.writeLong(os, 2, _dontIncludePeers.size());
|
||||
for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) {
|
||||
Hash peer = (Hash)iter.next();
|
||||
peer.writeBytes(os);
|
||||
}
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
System.arraycopy(_key.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
System.arraycopy(_fromHash.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
if (_replyTunnel != null) {
|
||||
out[curIndex++] = DataHelper.BOOLEAN_TRUE;
|
||||
byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId());
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
} else {
|
||||
out[curIndex++] = DataHelper.BOOLEAN_FALSE;
|
||||
}
|
||||
return os.toByteArray();
|
||||
if ( (_dontIncludePeers == null) || (_dontIncludePeers.size() <= 0) ) {
|
||||
out[curIndex++] = 0x0;
|
||||
out[curIndex++] = 0x0;
|
||||
} else {
|
||||
byte len[] = DataHelper.toLong(2, _dontIncludePeers.size());
|
||||
out[curIndex++] = len[0];
|
||||
out[curIndex++] = len[1];
|
||||
for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) {
|
||||
Hash peer = (Hash)iter.next();
|
||||
System.arraycopy(peer.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
}
|
||||
}
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -57,56 +57,58 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
|
||||
public Hash getFromHash() { return _from; }
|
||||
public void setFromHash(Hash from) { _from = from; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
_key = new Hash();
|
||||
_key.readBytes(in);
|
||||
|
||||
int num = (int)DataHelper.readLong(in, 1);
|
||||
_peerHashes.clear();
|
||||
for (int i = 0; i < num; i++) {
|
||||
Hash peer = new Hash();
|
||||
peer.readBytes(in);
|
||||
addReply(peer);
|
||||
}
|
||||
|
||||
_from = new Hash();
|
||||
_from.readBytes(in);
|
||||
|
||||
_context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
int curIndex = offset;
|
||||
|
||||
byte keyData[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_key = new Hash(keyData);
|
||||
|
||||
int num = (int)DataHelper.fromLong(data, curIndex, 1);
|
||||
curIndex++;
|
||||
|
||||
_peerHashes.clear();
|
||||
for (int i = 0; i < num; i++) {
|
||||
byte peer[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
addReply(new Hash(peer));
|
||||
}
|
||||
|
||||
byte from[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, from, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_from = new Hash(from);
|
||||
|
||||
_context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1);
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
return Hash.HASH_LENGTH + 1 + getNumReplies()*Hash.HASH_LENGTH + Hash.HASH_LENGTH;
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
if (_key == null)
|
||||
throw new I2NPMessageException("Key in reply to not specified");
|
||||
if (_peerHashes == null)
|
||||
throw new I2NPMessageException("Peer replies are null");
|
||||
if (_from == null)
|
||||
throw new I2NPMessageException("No 'from' address specified!");
|
||||
|
||||
byte rv[] = null;
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
|
||||
try {
|
||||
_key.writeBytes(os);
|
||||
|
||||
DataHelper.writeLong(os, 1, _peerHashes.size());
|
||||
for (int i = 0; i < getNumReplies(); i++) {
|
||||
Hash peer = getReply(i);
|
||||
peer.writeBytes(os);
|
||||
}
|
||||
|
||||
_from.writeBytes(os);
|
||||
|
||||
rv = os.toByteArray();
|
||||
_context.statManager().addRateData("netDb.searchReplyMessageSendSize", rv.length, 1);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
System.arraycopy(_key.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
byte len[] = DataHelper.toLong(1, _peerHashes.size());
|
||||
out[curIndex++] = len[0];
|
||||
for (int i = 0; i < getNumReplies(); i++) {
|
||||
System.arraycopy(getReply(i).getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
}
|
||||
return rv;
|
||||
System.arraycopy(_from.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -35,6 +35,8 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
|
||||
private int _type;
|
||||
private LeaseSet _leaseSet;
|
||||
private RouterInfo _info;
|
||||
private byte[] _leaseSetCache;
|
||||
private byte[] _routerInfoCache;
|
||||
private long _replyToken;
|
||||
private TunnelId _replyTunnel;
|
||||
private Hash _replyGateway;
|
||||
@@ -117,76 +119,109 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
|
||||
public Hash getReplyGateway() { return _replyGateway; }
|
||||
public void setReplyGateway(Hash peer) { _replyGateway = peer; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
_key = new Hash();
|
||||
_key.readBytes(in);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Hash read: " + _key.toBase64());
|
||||
_type = (int)DataHelper.readLong(in, 1);
|
||||
_replyToken = DataHelper.readLong(in, 4);
|
||||
if (_replyToken > 0) {
|
||||
_replyTunnel = new TunnelId();
|
||||
_replyTunnel.readBytes(in);
|
||||
_replyGateway = new Hash();
|
||||
_replyGateway.readBytes(in);
|
||||
} else {
|
||||
_replyTunnel = null;
|
||||
_replyGateway = null;
|
||||
int curIndex = offset;
|
||||
|
||||
byte keyData[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_key = new Hash(keyData);
|
||||
|
||||
_type = (int)DataHelper.fromLong(data, curIndex, 1);
|
||||
curIndex++;
|
||||
|
||||
_replyToken = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
|
||||
if (_replyToken > 0) {
|
||||
_replyTunnel = new TunnelId(DataHelper.fromLong(data, curIndex, 4));
|
||||
curIndex += 4;
|
||||
|
||||
byte gw[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, gw, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_replyGateway = new Hash(gw);
|
||||
} else {
|
||||
_replyTunnel = null;
|
||||
_replyGateway = null;
|
||||
}
|
||||
|
||||
if (_type == KEY_TYPE_LEASESET) {
|
||||
_leaseSet = new LeaseSet();
|
||||
try {
|
||||
_leaseSet.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex));
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error reading the leaseSet", dfe);
|
||||
}
|
||||
if (_type == KEY_TYPE_LEASESET) {
|
||||
_leaseSet = new LeaseSet();
|
||||
_leaseSet.readBytes(in);
|
||||
} else if (_type == KEY_TYPE_ROUTERINFO) {
|
||||
_info = new RouterInfo();
|
||||
int compressedSize = (int)DataHelper.readLong(in, 2);
|
||||
byte compressed[] = new byte[compressedSize];
|
||||
int read = DataHelper.read(in, compressed);
|
||||
if (read != compressedSize)
|
||||
throw new I2NPMessageException("Invalid compressed data size (expected "
|
||||
+ compressedSize + " read " + read + ")");
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed));
|
||||
_info.readBytes(bais);
|
||||
} else {
|
||||
throw new I2NPMessageException("Invalid type of key read from the structure - " + _type);
|
||||
} else if (_type == KEY_TYPE_ROUTERINFO) {
|
||||
_info = new RouterInfo();
|
||||
int compressedSize = (int)DataHelper.fromLong(data, curIndex, 2);
|
||||
curIndex += 2;
|
||||
|
||||
byte decompressed[] = DataHelper.decompress(data, curIndex, compressedSize);
|
||||
try {
|
||||
_info.readBytes(new ByteArrayInputStream(decompressed));
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error reading the routerInfo", dfe);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
} else {
|
||||
throw new I2NPMessageException("Invalid type of key read from the structure - " + _type);
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
int len = Hash.HASH_LENGTH + 1 + 4; // key+type+replyToken
|
||||
if (_replyToken > 0)
|
||||
len += 4 + Hash.HASH_LENGTH; // replyTunnel+replyGateway
|
||||
if (_type == KEY_TYPE_LEASESET) {
|
||||
_leaseSetCache = _leaseSet.toByteArray();
|
||||
len += _leaseSetCache.length;
|
||||
} else if (_type == KEY_TYPE_ROUTERINFO) {
|
||||
byte uncompressed[] = _info.toByteArray();
|
||||
byte compressed[] = DataHelper.compress(uncompressed);
|
||||
_routerInfoCache = compressed;
|
||||
len += compressed.length + 2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
if (_key == null) throw new I2NPMessageException("Invalid key");
|
||||
if ( (_type != KEY_TYPE_LEASESET) && (_type != KEY_TYPE_ROUTERINFO) ) throw new I2NPMessageException("Invalid key type");
|
||||
if ( (_type == KEY_TYPE_LEASESET) && (_leaseSet == null) ) throw new I2NPMessageException("Missing lease set");
|
||||
if ( (_type == KEY_TYPE_ROUTERINFO) && (_info == null) ) throw new I2NPMessageException("Missing router info");
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(256);
|
||||
try {
|
||||
_key.writeBytes(os);
|
||||
DataHelper.writeLong(os, 1, _type);
|
||||
DataHelper.writeLong(os, 4, _replyToken);
|
||||
if (_replyToken > 0) {
|
||||
_replyTunnel.writeBytes(os);
|
||||
_replyGateway.writeBytes(os);
|
||||
} else {
|
||||
// noop
|
||||
}
|
||||
if (_type == KEY_TYPE_LEASESET) {
|
||||
_leaseSet.writeBytes(os);
|
||||
} else if (_type == KEY_TYPE_ROUTERINFO) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
||||
_info.writeBytes(baos);
|
||||
byte uncompressed[] = baos.toByteArray();
|
||||
byte compressed[] = DataHelper.compress(uncompressed);
|
||||
DataHelper.writeLong(os, 2, compressed.length);
|
||||
os.write(compressed);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
System.arraycopy(_key.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
byte type[] = DataHelper.toLong(1, _type);
|
||||
out[curIndex++] = type[0];
|
||||
byte tok[] = DataHelper.toLong(4, _replyToken);
|
||||
System.arraycopy(tok, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
|
||||
if (_replyToken > 0) {
|
||||
byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId());
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
System.arraycopy(_replyGateway.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
}
|
||||
return os.toByteArray();
|
||||
|
||||
if (_type == KEY_TYPE_LEASESET) {
|
||||
// initialized in calculateWrittenLength
|
||||
System.arraycopy(_leaseSetCache, 0, out, curIndex, _leaseSetCache.length);
|
||||
curIndex += _leaseSetCache.length;
|
||||
} else if (_type == KEY_TYPE_ROUTERINFO) {
|
||||
byte len[] = DataHelper.toLong(2, _routerInfoCache.length);
|
||||
out[curIndex++] = len[0];
|
||||
out[curIndex++] = len[1];
|
||||
System.arraycopy(_routerInfoCache, 0, out, curIndex, _routerInfoCache.length);
|
||||
curIndex += _routerInfoCache.length;
|
||||
}
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -42,27 +42,30 @@ public class DeliveryStatusMessage extends I2NPMessageImpl {
|
||||
public Date getArrival() { return _arrival; }
|
||||
public void setArrival(Date arrival) { _arrival = arrival; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
_id = DataHelper.readLong(in, 4);
|
||||
_arrival = DataHelper.readDate(in);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
int curIndex = offset;
|
||||
|
||||
_id = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
_arrival = DataHelper.fromDate(data, curIndex);
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
return 4 + DataHelper.DATE_LENGTH; // id + arrival
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
if ( (_id < 0) || (_arrival == null) ) throw new I2NPMessageException("Not enough data to write out");
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
|
||||
try {
|
||||
DataHelper.writeLong(os, 4, _id);
|
||||
DataHelper.writeDate(os, _arrival);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
}
|
||||
return os.toByteArray();
|
||||
byte id[] = DataHelper.toLong(4, _id);
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
byte date[] = DataHelper.toDate(_arrival);
|
||||
System.arraycopy(date, 0, out, curIndex, DataHelper.DATE_LENGTH);
|
||||
curIndex += DataHelper.DATE_LENGTH;
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -98,7 +98,7 @@ public class GarlicClove extends DataStructureImpl {
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Wrote instructions: " + _instructions);
|
||||
_msg.writeBytes(out);
|
||||
out.write(_msg.toByteArray());
|
||||
DataHelper.writeLong(out, 4, _cloveId);
|
||||
DataHelper.writeDate(out, _expiration);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
|
@@ -35,30 +35,29 @@ public class GarlicMessage extends I2NPMessageImpl {
|
||||
public byte[] getData() { return _data; }
|
||||
public void setData(byte[] data) { _data = data; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
long len = DataHelper.readLong(in, 4);
|
||||
_data = new byte[(int)len];
|
||||
int read = read(in, _data);
|
||||
if (read != len)
|
||||
throw new I2NPMessageException("Incorrect size read [" + read + " read, expected " + len + "]");
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
int curIndex = offset;
|
||||
|
||||
long len = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
if ( (len <= 0) || (len > 64*1024) ) throw new I2NPMessageException("size="+len);
|
||||
_data = new byte[(int)len];
|
||||
System.arraycopy(data, curIndex, _data, 0, (int)len);
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
if ( (_data == null) || (_data.length <= 0) ) throw new I2NPMessageException("Not enough data to write out");
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
|
||||
try {
|
||||
DataHelper.writeLong(os, 4, _data.length);
|
||||
os.write(_data);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
}
|
||||
return os.toByteArray();
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
return 4 + _data.length;
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
byte len[] = DataHelper.toLong(4, _data.length);
|
||||
System.arraycopy(len, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
System.arraycopy(_data, 0, out, curIndex, _data.length);
|
||||
curIndex += _data.length;
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -28,11 +28,28 @@ public interface I2NPMessage extends DataStructure {
|
||||
*
|
||||
* @param in stream to read from
|
||||
* @param type I2NP message type
|
||||
* @param buffer scratch buffer to be used when reading and parsing
|
||||
* @return size of the message read (including headers)
|
||||
* @throws I2NPMessageException if the stream doesn't contain a valid message
|
||||
* that this class can read.
|
||||
* @throws IOException if there is a problem reading from the stream
|
||||
*/
|
||||
public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException;
|
||||
public int readBytes(InputStream in, int type, byte buffer[]) throws I2NPMessageException, IOException;
|
||||
|
||||
/**
|
||||
* Read the body into the data structures, after the initial type byte and
|
||||
* the uniqueId / expiration, using the current class's format as defined by
|
||||
* the I2NP specification
|
||||
*
|
||||
* @param data data to read from
|
||||
* @param offset where to start in the data array
|
||||
* @param dataSize how long into the data to read
|
||||
* @param type I2NP message type
|
||||
* @throws I2NPMessageException if the stream doesn't contain a valid message
|
||||
* that this class can read.
|
||||
* @throws IOException if there is a problem reading from the stream
|
||||
*/
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException;
|
||||
|
||||
/**
|
||||
* Return the unique identifier for this type of I2NP message, as defined in
|
||||
@@ -50,4 +67,10 @@ public interface I2NPMessage extends DataStructure {
|
||||
*
|
||||
*/
|
||||
public Date getMessageExpiration();
|
||||
|
||||
/** How large the message is, including any checksums */
|
||||
public int getMessageSize();
|
||||
|
||||
/** write the message to the buffer, returning the number of bytes written */
|
||||
public int toByteArray(byte buffer[]);
|
||||
}
|
||||
|
@@ -26,9 +26,13 @@ public class I2NPMessageHandler {
|
||||
private I2PAppContext _context;
|
||||
private long _lastReadBegin;
|
||||
private long _lastReadEnd;
|
||||
private int _lastSize;
|
||||
private byte _messageBuffer[];
|
||||
public I2NPMessageHandler(I2PAppContext context) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(I2NPMessageHandler.class);
|
||||
_messageBuffer = null;
|
||||
_lastSize = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,25 +43,39 @@ public class I2NPMessageHandler {
|
||||
* message - if it is an unknown type or has improper formatting, etc.
|
||||
*/
|
||||
public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException {
|
||||
if (_messageBuffer == null) _messageBuffer = new byte[38*1024]; // more than necessary
|
||||
try {
|
||||
int type = (int)DataHelper.readLong(in, 1);
|
||||
_lastReadBegin = System.currentTimeMillis();
|
||||
I2NPMessage msg = createMessage(in, type);
|
||||
msg.readBytes(in, type);
|
||||
I2NPMessage msg = createMessage(type);
|
||||
if (msg == null)
|
||||
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
|
||||
try {
|
||||
_lastSize = msg.readBytes(in, type, _messageBuffer);
|
||||
} catch (IOException ioe) {
|
||||
throw ioe;
|
||||
} catch (I2NPMessageException ime) {
|
||||
throw ime;
|
||||
} catch (Exception e) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error reading the stream", e);
|
||||
throw new IOException("Unknown error reading the " + msg.getClass().getName()
|
||||
+ ": " + e.getMessage());
|
||||
}
|
||||
_lastReadEnd = System.currentTimeMillis();
|
||||
return msg;
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error reading the message", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; }
|
||||
public int getLastSize() { return _lastSize; }
|
||||
|
||||
/**
|
||||
* Yes, this is fairly ugly, but its the only place it ever happens.
|
||||
*
|
||||
*/
|
||||
private I2NPMessage createMessage(InputStream in, int type) throws IOException, I2NPMessageException {
|
||||
private I2NPMessage createMessage(int type) throws I2NPMessageException {
|
||||
switch (type) {
|
||||
case DatabaseStoreMessage.MESSAGE_TYPE:
|
||||
return new DatabaseStoreMessage(_context);
|
||||
@@ -78,7 +96,7 @@ public class I2NPMessageHandler {
|
||||
case TunnelCreateStatusMessage.MESSAGE_TYPE:
|
||||
return new TunnelCreateStatusMessage(_context);
|
||||
default:
|
||||
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ package net.i2p.data.i2np;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -17,6 +18,7 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.DataStructureImpl;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -29,6 +31,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
|
||||
protected I2PAppContext _context;
|
||||
private Date _expiration;
|
||||
private long _uniqueId;
|
||||
private byte _data[];
|
||||
|
||||
public final static long DEFAULT_EXPIRATION_MS = 1*60*1000; // 1 minute by default
|
||||
|
||||
@@ -37,60 +40,63 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
|
||||
_log = context.logManager().getLog(I2NPMessageImpl.class);
|
||||
_expiration = new Date(_context.clock().now() + DEFAULT_EXPIRATION_MS);
|
||||
_uniqueId = _context.random().nextLong(MAX_ID_VALUE);
|
||||
_context.statManager().createRateStat("i2np.writeTime", "How long it takes to write an I2NP message", "I2NP", new long[] { 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2np.readTime", "How long it takes to read an I2NP message", "I2NP", new long[] { 10*60*1000, 60*60*1000 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the payload part of the message (not including the initial
|
||||
* 1 byte type)
|
||||
*
|
||||
*/
|
||||
protected abstract byte[] writeMessage() throws I2NPMessageException, IOException;
|
||||
|
||||
/**
|
||||
* Read the body into the data structures, after the initial type byte and
|
||||
* the uniqueId / expiration, using the current class's format as defined by
|
||||
* the I2NP specification
|
||||
*
|
||||
* @param in stream to read from
|
||||
* @param type I2NP message type
|
||||
* @throws I2NPMessageException if the stream doesn't contain a valid message
|
||||
* that this class can read.
|
||||
* @throws IOException if there is a problem reading from the stream
|
||||
*/
|
||||
protected abstract void readMessage(InputStream in, int type) throws I2NPMessageException, IOException;
|
||||
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
try {
|
||||
readBytes(in, -1);
|
||||
readBytes(in, -1, new byte[1024]);
|
||||
} catch (I2NPMessageException ime) {
|
||||
throw new DataFormatException("Bad bytes", ime);
|
||||
}
|
||||
}
|
||||
public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public int readBytes(InputStream in, int type, byte buffer[]) throws I2NPMessageException, IOException {
|
||||
try {
|
||||
if (type < 0)
|
||||
type = (int)DataHelper.readLong(in, 1);
|
||||
_uniqueId = DataHelper.readLong(in, 4);
|
||||
_expiration = DataHelper.readDate(in);
|
||||
int size = (int)DataHelper.readLong(in, 2);
|
||||
Hash h = new Hash();
|
||||
h.readBytes(in);
|
||||
if (buffer.length < size) {
|
||||
if (size > 64*1024) throw new I2NPMessageException("size=" + size);
|
||||
buffer = new byte[size];
|
||||
}
|
||||
|
||||
int cur = 0;
|
||||
while (cur < size) {
|
||||
int numRead = in.read(buffer, cur, size- cur);
|
||||
if (numRead == -1) {
|
||||
throw new I2NPMessageException("Payload is too short [" + numRead + ", wanted " + size + "]");
|
||||
}
|
||||
cur += numRead;
|
||||
}
|
||||
|
||||
Hash calc = _context.sha().calculateHash(buffer, 0, size);
|
||||
if (!calc.equals(h))
|
||||
throw new I2NPMessageException("Hash does not match");
|
||||
|
||||
long start = _context.clock().now();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration);
|
||||
readMessage(buffer, 0, size, type);
|
||||
long time = _context.clock().now() - start;
|
||||
if (time > 50)
|
||||
_context.statManager().addRateData("i2np.readTime", time, time);
|
||||
return size + Hash.HASH_LENGTH + 1 + 4 + DataHelper.DATE_LENGTH;
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error reading the message header", dfe);
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration);
|
||||
readMessage(in, type);
|
||||
}
|
||||
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||
try {
|
||||
DataHelper.writeLong(out, 1, getType());
|
||||
DataHelper.writeLong(out, 4, _uniqueId);
|
||||
DataHelper.writeDate(out, _expiration);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Writing bytes: type = " + getType() + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration);
|
||||
byte[] data = writeMessage();
|
||||
out.write(data);
|
||||
} catch (I2NPMessageException ime) {
|
||||
throw new DataFormatException("Error writing out the I2NP message data", ime);
|
||||
}
|
||||
int size = getMessageSize();
|
||||
if (size < 47) throw new DataFormatException("Unable to build the message");
|
||||
byte buf[] = new byte[size];
|
||||
int read = toByteArray(buf);
|
||||
if (read < 0)
|
||||
out.write(buf, 0, read);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,4 +111,77 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
|
||||
*/
|
||||
public Date getMessageExpiration() { return _expiration; }
|
||||
public void setMessageExpiration(Date exp) { _expiration = exp; }
|
||||
|
||||
public synchronized int getMessageSize() {
|
||||
return calculateWrittenLength()+47; // 47 bytes in the header
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
byte data[] = new byte[getMessageSize()];
|
||||
int written = toByteArray(data);
|
||||
if (written != data.length) {
|
||||
_log.error("Error writing out " + data.length + " for " + getClass().getName());
|
||||
return null;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public int toByteArray(byte buffer[]) {
|
||||
long start = _context.clock().now();
|
||||
|
||||
byte prefix[][] = new byte[][] { DataHelper.toLong(1, getType()),
|
||||
DataHelper.toLong(4, _uniqueId),
|
||||
DataHelper.toDate(_expiration),
|
||||
new byte[2],
|
||||
new byte[Hash.HASH_LENGTH]};
|
||||
byte suffix[][] = new byte[][] { };
|
||||
try {
|
||||
int writtenLen = toByteArray(buffer, prefix, suffix);
|
||||
|
||||
int prefixLen = 1+4+8+2+Hash.HASH_LENGTH;
|
||||
int suffixLen = 0;
|
||||
int payloadLen = writtenLen - prefixLen - suffixLen;
|
||||
Hash h = _context.sha().calculateHash(buffer, prefixLen, payloadLen);
|
||||
|
||||
byte len[] = DataHelper.toLong(2, payloadLen);
|
||||
buffer[1+4+8] = len[0];
|
||||
buffer[1+4+8+1] = len[1];
|
||||
for (int i = 0; i < Hash.HASH_LENGTH; i++)
|
||||
System.arraycopy(h.getData(), 0, buffer, 1+4+8+2, Hash.HASH_LENGTH);
|
||||
|
||||
long time = _context.clock().now() - start;
|
||||
if (time > 50)
|
||||
_context.statManager().addRateData("i2np.writeTime", time, time);
|
||||
|
||||
return writtenLen;
|
||||
} catch (I2NPMessageException ime) {
|
||||
_context.logManager().getLog(getClass()).error("Error writing", ime);
|
||||
throw new IllegalStateException("Unable to serialize the message: " + ime.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected abstract int calculateWrittenLength();
|
||||
/**
|
||||
* write the message body to the output array, starting at the given index.
|
||||
* @return the index into the array after the last byte written
|
||||
*/
|
||||
protected abstract int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException;
|
||||
|
||||
protected int toByteArray(byte out[], byte[][] prefix, byte[][] suffix) throws I2NPMessageException {
|
||||
int curIndex = 0;
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
System.arraycopy(prefix[i], 0, out, curIndex, prefix[i].length);
|
||||
curIndex += prefix[i].length;
|
||||
}
|
||||
|
||||
curIndex = writeMessageBody(out, curIndex);
|
||||
|
||||
for (int i = 0; i < suffix.length; i++) {
|
||||
System.arraycopy(suffix[i], 0, out, curIndex, suffix[i].length);
|
||||
curIndex += suffix[i].length;
|
||||
}
|
||||
|
||||
return curIndex;
|
||||
}
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ public class I2NPMessageReader {
|
||||
* reader
|
||||
*
|
||||
*/
|
||||
public void messageReceived(I2NPMessageReader reader, I2NPMessage message, long msToRead);
|
||||
public void messageReceived(I2NPMessageReader reader, I2NPMessage message, long msToRead, int bytesRead);
|
||||
/**
|
||||
* Notify the listener that an exception was thrown while reading from the given
|
||||
* reader
|
||||
@@ -122,7 +122,8 @@ public class I2NPMessageReader {
|
||||
I2NPMessage msg = _handler.readMessage(_stream);
|
||||
if (msg != null) {
|
||||
long msToRead = _handler.getLastReadTime();
|
||||
_listener.messageReceived(I2NPMessageReader.this, msg, msToRead);
|
||||
int bytesRead = _handler.getLastSize();
|
||||
_listener.messageReceived(I2NPMessageReader.this, msg, msToRead, bytesRead);
|
||||
}
|
||||
} catch (I2NPMessageException ime) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
|
@@ -28,7 +28,8 @@ public class TunnelConfigurationSessionKey extends DataStructureImpl {
|
||||
private final static Log _log = new Log(TunnelConfigurationSessionKey.class);
|
||||
private SessionKey _key;
|
||||
|
||||
public TunnelConfigurationSessionKey() { setKey(null); }
|
||||
public TunnelConfigurationSessionKey() { this(null); }
|
||||
public TunnelConfigurationSessionKey(SessionKey key) { setKey(key); }
|
||||
|
||||
public SessionKey getKey() { return _key; }
|
||||
public void setKey(SessionKey key) { _key= key; }
|
||||
|
@@ -19,6 +19,8 @@ import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.SessionTag;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.SigningPublicKey;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -52,6 +54,8 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
|
||||
private TunnelId _replyTunnel;
|
||||
private Hash _replyPeer;
|
||||
|
||||
private byte[] _certificateCache;
|
||||
|
||||
public static final int PARTICIPANT_TYPE_GATEWAY = 1;
|
||||
public static final int PARTICIPANT_TYPE_ENDPOINT = 2;
|
||||
public static final int PARTICIPANT_TYPE_OTHER = 3;
|
||||
@@ -124,91 +128,190 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
|
||||
public void setReplyPeer(Hash peer) { _replyPeer = peer; }
|
||||
public Hash getReplyPeer() { return _replyPeer; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
_participantType = (int)DataHelper.readLong(in, 1);
|
||||
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
|
||||
_nextRouter = new Hash();
|
||||
_nextRouter.readBytes(in);
|
||||
_nextTunnelId = new TunnelId();
|
||||
_nextTunnelId.readBytes(in);
|
||||
}
|
||||
_tunnelId = new TunnelId();
|
||||
_tunnelId.readBytes(in);
|
||||
_tunnelDuration = DataHelper.readLong(in, 4);
|
||||
_configKey = new TunnelConfigurationSessionKey();
|
||||
_configKey.readBytes(in);
|
||||
_maxPeakMessagesPerMin = DataHelper.readLong(in, 4);
|
||||
_maxAvgMessagesPerMin = DataHelper.readLong(in, 4);
|
||||
_maxPeakBytesPerMin = DataHelper.readLong(in, 4);
|
||||
_maxAvgBytesPerMin = DataHelper.readLong(in, 4);
|
||||
int curIndex = offset;
|
||||
|
||||
_participantType = (int)DataHelper.fromLong(data, curIndex, 1);
|
||||
curIndex++;
|
||||
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
|
||||
byte peer[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_nextRouter = new Hash(peer);
|
||||
|
||||
int flags = (int)DataHelper.readLong(in, 1);
|
||||
_includeDummyTraffic = flagsIncludeDummy(flags);
|
||||
_reorderMessages = flagsReorder(flags);
|
||||
|
||||
_verificationPubKey = new TunnelSigningPublicKey();
|
||||
_verificationPubKey.readBytes(in);
|
||||
if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
|
||||
_verificationPrivKey = new TunnelSigningPrivateKey();
|
||||
_verificationPrivKey.readBytes(in);
|
||||
}
|
||||
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
|
||||
_tunnelKey = new TunnelSessionKey();
|
||||
_tunnelKey.readBytes(in);
|
||||
}
|
||||
_certificate = new Certificate();
|
||||
_certificate.readBytes(in);
|
||||
_replyTag = new SessionTag();
|
||||
_replyTag.readBytes(in);
|
||||
_replyKey = new SessionKey();
|
||||
_replyKey.readBytes(in);
|
||||
_replyTunnel = new TunnelId();
|
||||
_replyTunnel.readBytes(in);
|
||||
_replyPeer = new Hash();
|
||||
_replyPeer.readBytes(in);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
_nextTunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4));
|
||||
curIndex += 4;
|
||||
}
|
||||
|
||||
_tunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4));
|
||||
curIndex += 4;
|
||||
if (_tunnelId.getTunnelId() <= 0)
|
||||
throw new I2NPMessageException("wtf, tunnelId == " + _tunnelId);
|
||||
|
||||
_tunnelDuration = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
|
||||
byte key[] = new byte[SessionKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(data, curIndex, key, 0, SessionKey.KEYSIZE_BYTES);
|
||||
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||
_configKey = new TunnelConfigurationSessionKey(new SessionKey(key));
|
||||
|
||||
_maxPeakMessagesPerMin = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
_maxAvgMessagesPerMin = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
_maxPeakBytesPerMin = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
_maxAvgBytesPerMin = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
|
||||
int flags = (int)DataHelper.fromLong(data, curIndex, 1);
|
||||
curIndex++;
|
||||
_includeDummyTraffic = flagsIncludeDummy(flags);
|
||||
_reorderMessages = flagsReorder(flags);
|
||||
|
||||
key = new byte[SigningPublicKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(data, curIndex, key, 0, SigningPublicKey.KEYSIZE_BYTES);
|
||||
curIndex += SigningPublicKey.KEYSIZE_BYTES;
|
||||
_verificationPubKey = new TunnelSigningPublicKey(new SigningPublicKey(key));
|
||||
|
||||
if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
|
||||
key = new byte[SigningPrivateKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(data, curIndex, key, 0, SigningPrivateKey.KEYSIZE_BYTES);
|
||||
curIndex += SigningPrivateKey.KEYSIZE_BYTES;
|
||||
_verificationPrivKey = new TunnelSigningPrivateKey(new SigningPrivateKey(key));
|
||||
}
|
||||
|
||||
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
|
||||
key = new byte[SessionKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(data, curIndex, key, 0, SessionKey.KEYSIZE_BYTES);
|
||||
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||
_tunnelKey = new TunnelSessionKey(new SessionKey(key));
|
||||
}
|
||||
|
||||
int certType = (int) DataHelper.fromLong(data, curIndex, 1);
|
||||
curIndex++;
|
||||
int certLength = (int) DataHelper.fromLong(data, curIndex, 2);
|
||||
curIndex += 2;
|
||||
if (certLength <= 0) {
|
||||
_certificate = new Certificate(certType, null);
|
||||
} else {
|
||||
if (certLength > 16*1024) throw new I2NPMessageException("cert size " + certLength);
|
||||
byte certPayload[] = new byte[certLength];
|
||||
System.arraycopy(data, curIndex, certPayload, 0, certLength);
|
||||
curIndex += certLength;
|
||||
_certificate = new Certificate(certType, certPayload);
|
||||
}
|
||||
|
||||
byte tag[] = new byte[SessionTag.BYTE_LENGTH];
|
||||
System.arraycopy(data, curIndex, tag, 0, SessionTag.BYTE_LENGTH);
|
||||
curIndex += SessionTag.BYTE_LENGTH;
|
||||
_replyTag = new SessionTag(tag);
|
||||
|
||||
key = new byte[SessionKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(data, curIndex, key, 0, SessionKey.KEYSIZE_BYTES);
|
||||
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||
_replyKey = new SessionKey(key);
|
||||
|
||||
_replyTunnel = new TunnelId(DataHelper.fromLong(data, curIndex, 4));
|
||||
curIndex += 4;
|
||||
|
||||
byte peer[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_replyPeer = new Hash(peer);
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
|
||||
try {
|
||||
DataHelper.writeLong(os, 1, _participantType);
|
||||
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
|
||||
_nextRouter.writeBytes(os);
|
||||
_nextTunnelId.writeBytes(os);
|
||||
}
|
||||
_tunnelId.writeBytes(os);
|
||||
DataHelper.writeLong(os, 4, _tunnelDuration);
|
||||
_configKey.writeBytes(os);
|
||||
|
||||
DataHelper.writeLong(os, 4, _maxPeakMessagesPerMin);
|
||||
DataHelper.writeLong(os, 4, _maxAvgMessagesPerMin);
|
||||
DataHelper.writeLong(os, 4, _maxPeakBytesPerMin);
|
||||
DataHelper.writeLong(os, 4, _maxAvgBytesPerMin);
|
||||
|
||||
long flags = getFlags();
|
||||
DataHelper.writeLong(os, 1, flags);
|
||||
|
||||
_verificationPubKey.writeBytes(os);
|
||||
if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
|
||||
_verificationPrivKey.writeBytes(os);
|
||||
}
|
||||
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
|
||||
_tunnelKey.writeBytes(os);
|
||||
}
|
||||
_certificate.writeBytes(os);
|
||||
_replyTag.writeBytes(os);
|
||||
_replyKey.writeBytes(os);
|
||||
_replyTunnel.writeBytes(os);
|
||||
_replyPeer.writeBytes(os);
|
||||
} catch (Throwable t) {
|
||||
throw new I2NPMessageException("Error writing out the message data", t);
|
||||
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
int length = 0;
|
||||
length += 1; // participantType
|
||||
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
|
||||
length += Hash.HASH_LENGTH;
|
||||
length += 4; // nextTunnelId
|
||||
}
|
||||
return os.toByteArray();
|
||||
length += 4; // tunnelId
|
||||
length += 4; // duration;
|
||||
length += SessionKey.KEYSIZE_BYTES;
|
||||
length += 4*4; // max limits
|
||||
length += 1; // flags
|
||||
length += SigningPublicKey.KEYSIZE_BYTES;
|
||||
if (_participantType == PARTICIPANT_TYPE_GATEWAY)
|
||||
length += SigningPrivateKey.KEYSIZE_BYTES;
|
||||
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT)
|
||||
|| (_participantType == PARTICIPANT_TYPE_GATEWAY) )
|
||||
length += SessionKey.KEYSIZE_BYTES;
|
||||
_certificateCache = _certificate.toByteArray();
|
||||
length += _certificateCache.length;
|
||||
length += SessionTag.BYTE_LENGTH;
|
||||
length += SessionKey.KEYSIZE_BYTES;
|
||||
length += 4; // replyTunnel
|
||||
length += Hash.HASH_LENGTH; // replyPeer
|
||||
return length;
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
byte type[] = DataHelper.toLong(1, _participantType);
|
||||
out[curIndex++] = type[0];
|
||||
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
|
||||
System.arraycopy(_nextRouter.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
byte id[] = DataHelper.toLong(4, _nextTunnelId.getTunnelId());
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
}
|
||||
byte id[] = DataHelper.toLong(4, _tunnelId.getTunnelId());
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
byte duration[] = DataHelper.toLong(4, _tunnelDuration);
|
||||
System.arraycopy(duration, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
System.arraycopy(_configKey.getKey().getData(), 0, out, curIndex, SessionKey.KEYSIZE_BYTES);
|
||||
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||
|
||||
byte val[] = DataHelper.toLong(4, _maxPeakMessagesPerMin);
|
||||
System.arraycopy(val, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
val = DataHelper.toLong(4, _maxAvgMessagesPerMin);
|
||||
System.arraycopy(val, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
val = DataHelper.toLong(4, _maxPeakBytesPerMin);
|
||||
System.arraycopy(val, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
val = DataHelper.toLong(4, _maxAvgBytesPerMin);
|
||||
System.arraycopy(val, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
|
||||
long flags = getFlags();
|
||||
byte flag[] = DataHelper.toLong(1, flags);
|
||||
out[curIndex++] = flag[0];
|
||||
|
||||
System.arraycopy(_verificationPubKey.getKey().getData(), 0, out, curIndex, SigningPublicKey.KEYSIZE_BYTES);
|
||||
curIndex += SigningPublicKey.KEYSIZE_BYTES;
|
||||
|
||||
if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
|
||||
System.arraycopy(_verificationPrivKey.getKey().getData(), 0, out, curIndex, SigningPrivateKey.KEYSIZE_BYTES);
|
||||
curIndex += SigningPrivateKey.KEYSIZE_BYTES;
|
||||
}
|
||||
|
||||
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
|
||||
System.arraycopy(_tunnelKey.getKey().getData(), 0, out, curIndex, SessionKey.KEYSIZE_BYTES);
|
||||
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||
}
|
||||
System.arraycopy(_certificateCache, 0, out, curIndex, _certificateCache.length);
|
||||
curIndex += _certificateCache.length;
|
||||
System.arraycopy(_replyTag.getData(), 0, out, curIndex, SessionTag.BYTE_LENGTH);
|
||||
curIndex += SessionTag.BYTE_LENGTH;
|
||||
System.arraycopy(_replyKey.getData(), 0, out, curIndex, SessionKey.KEYSIZE_BYTES);
|
||||
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||
id = DataHelper.toLong(4, _replyTunnel.getTunnelId());
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
System.arraycopy(_replyPeer.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
private boolean flagsIncludeDummy(long flags) {
|
||||
@@ -304,4 +407,5 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -46,7 +46,11 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl {
|
||||
}
|
||||
|
||||
public TunnelId getTunnelId() { return _tunnelId; }
|
||||
public void setTunnelId(TunnelId id) { _tunnelId = id; }
|
||||
public void setTunnelId(TunnelId id) {
|
||||
_tunnelId = id;
|
||||
if ( (id != null) && (id.getTunnelId() <= 0) )
|
||||
throw new IllegalArgumentException("wtf, tunnelId " + id);
|
||||
}
|
||||
|
||||
public int getStatus() { return _status; }
|
||||
public void setStatus(int status) { _status = status; }
|
||||
@@ -57,31 +61,42 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl {
|
||||
public Hash getFromHash() { return _from; }
|
||||
public void setFromHash(Hash from) { _from = from; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
_tunnelId = new TunnelId();
|
||||
_tunnelId.readBytes(in);
|
||||
_status = (int)DataHelper.readLong(in, 1);
|
||||
_from = new Hash();
|
||||
_from.readBytes(in);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
int curIndex = offset;
|
||||
|
||||
_tunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4));
|
||||
curIndex += 4;
|
||||
|
||||
if (_tunnelId.getTunnelId() <= 0)
|
||||
throw new I2NPMessageException("wtf, negative tunnelId? " + _tunnelId);
|
||||
|
||||
_status = (int)DataHelper.fromLong(data, curIndex, 1);
|
||||
curIndex++;
|
||||
byte peer[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
_from = new Hash(peer);
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
if ( (_tunnelId == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out");
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
|
||||
try {
|
||||
_tunnelId.writeBytes(os);
|
||||
DataHelper.writeLong(os, 1, (_status < 0 ? 255 : _status));
|
||||
_from.writeBytes(os);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
}
|
||||
return os.toByteArray();
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
return 4 + 1 + Hash.HASH_LENGTH; // id + status + from
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
if ( (_tunnelId == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out");
|
||||
if (_tunnelId.getTunnelId() < 0) throw new I2NPMessageException("Negative tunnelId!? " + _tunnelId);
|
||||
|
||||
byte id[] = DataHelper.toLong(4, _tunnelId.getTunnelId());
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
byte status[] = DataHelper.toLong(1, _status);
|
||||
out[curIndex++] = status[0];
|
||||
System.arraycopy(_from.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -15,6 +15,8 @@ import java.io.InputStream;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -44,10 +46,16 @@ public class TunnelMessage extends I2NPMessageImpl {
|
||||
}
|
||||
|
||||
public TunnelId getTunnelId() { return _tunnelId; }
|
||||
public void setTunnelId(TunnelId id) { _tunnelId = id; }
|
||||
public void setTunnelId(TunnelId id) {
|
||||
_tunnelId = id;
|
||||
}
|
||||
|
||||
public byte[] getData() { return _data; }
|
||||
public void setData(byte data[]) { _data = data; }
|
||||
public void setData(byte data[]) {
|
||||
_data = data;
|
||||
if ( (data != null) && (_data.length <= 0) )
|
||||
throw new IllegalArgumentException("Empty tunnel payload?");
|
||||
}
|
||||
|
||||
public TunnelVerificationStructure getVerificationStructure() { return _verification; }
|
||||
public void setVerificationStructure(TunnelVerificationStructure verification) { _verification = verification; }
|
||||
@@ -55,71 +63,93 @@ public class TunnelMessage extends I2NPMessageImpl {
|
||||
public byte[] getEncryptedDeliveryInstructions() { return _encryptedInstructions; }
|
||||
public void setEncryptedDeliveryInstructions(byte instructions[]) { _encryptedInstructions = instructions; }
|
||||
|
||||
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
|
||||
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
|
||||
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
try {
|
||||
_tunnelId = new TunnelId();
|
||||
_tunnelId.readBytes(in);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read tunnel message for tunnel " + _tunnelId);
|
||||
_size = DataHelper.readLong(in, 4);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read tunnel message size: " + _size);
|
||||
if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size);
|
||||
_data = new byte[(int)_size];
|
||||
int read = read(in, _data);
|
||||
if (read != _size)
|
||||
throw new I2NPMessageException("Incorrect number of bytes read (" + read + ", expected " + _size);
|
||||
int includeVerification = (int)DataHelper.readLong(in, 1);
|
||||
if (includeVerification == FLAG_INCLUDESTRUCTURE) {
|
||||
_verification = new TunnelVerificationStructure();
|
||||
_verification.readBytes(in);
|
||||
int len = (int)DataHelper.readLong(in, 2);
|
||||
_encryptedInstructions = new byte[len];
|
||||
read = read(in, _encryptedInstructions);
|
||||
if (read != len)
|
||||
throw new I2NPMessageException("Incorrect number of bytes read for instructions (" + read + ", expected " + len + ")");
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Unable to load the message data", dfe);
|
||||
int curIndex = offset;
|
||||
|
||||
_tunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4));
|
||||
curIndex += 4;
|
||||
|
||||
if (_tunnelId.getTunnelId() <= 0)
|
||||
throw new I2NPMessageException("Invalid tunnel Id " + _tunnelId);
|
||||
|
||||
_size = DataHelper.fromLong(data, curIndex, 4);
|
||||
curIndex += 4;
|
||||
|
||||
if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size);
|
||||
if (_size > 64*1024) throw new I2NPMessageException("Invalid size in the structure: " + _size);
|
||||
_data = new byte[(int)_size];
|
||||
System.arraycopy(data, curIndex, _data, 0, (int)_size);
|
||||
curIndex += _size;
|
||||
|
||||
int includeVerification = (int)DataHelper.fromLong(data, curIndex, 1);
|
||||
curIndex++;
|
||||
if (includeVerification == FLAG_INCLUDESTRUCTURE) {
|
||||
byte vHash[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(data, curIndex, vHash, 0, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
byte vSig[] = new byte[Signature.SIGNATURE_BYTES];
|
||||
System.arraycopy(data, curIndex, vSig, 0, Signature.SIGNATURE_BYTES);
|
||||
curIndex += Signature.SIGNATURE_BYTES;
|
||||
_verification = new TunnelVerificationStructure(new Hash(vHash), new Signature(vSig));
|
||||
|
||||
int len = (int)DataHelper.fromLong(data, curIndex, 2);
|
||||
curIndex += 2;
|
||||
if ( (len <= 0) || (len > 4*1024) ) throw new I2NPMessageException("wtf, size of instructions: " + len);
|
||||
_encryptedInstructions = new byte[len];
|
||||
System.arraycopy(data, curIndex, _encryptedInstructions, 0, len);
|
||||
curIndex += len;
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] writeMessage() throws I2NPMessageException, IOException {
|
||||
if ( (_tunnelId == null) || (_data == null) || (_data.length <= 0) )
|
||||
throw new I2NPMessageException("Not enough data to write out");
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(4096);
|
||||
try {
|
||||
_tunnelId.writeBytes(os);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Writing tunnel message for tunnel " + _tunnelId);
|
||||
DataHelper.writeLong(os, 4, _data.length);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Writing tunnel message length: " + _data.length);
|
||||
os.write(_data);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Writing tunnel message data");
|
||||
if ( (_verification == null) || (_encryptedInstructions == null) ) {
|
||||
DataHelper.writeLong(os, 1, FLAG_DONT_INCLUDESTRUCTURE);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Writing DontIncludeStructure flag");
|
||||
} else {
|
||||
DataHelper.writeLong(os, 1, FLAG_INCLUDESTRUCTURE);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Writing IncludeStructure flag, then the verification structure, then the " +
|
||||
"E(instr).length [" + _encryptedInstructions.length + "], then the E(instr)");
|
||||
_verification.writeBytes(os);
|
||||
DataHelper.writeLong(os, 2, _encryptedInstructions.length);
|
||||
os.write(_encryptedInstructions);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2NPMessageException("Error writing out the message data", dfe);
|
||||
/** calculate the message body's length (not including the header and footer */
|
||||
protected int calculateWrittenLength() {
|
||||
int length = 0;
|
||||
length += 4; // tunnelId
|
||||
length += 4; // data length
|
||||
length += _data.length;
|
||||
if ( (_verification == null) || (_encryptedInstructions == null) ) {
|
||||
length += 1; // include verification?
|
||||
} else {
|
||||
length += 1; // include verification?
|
||||
length += Hash.HASH_LENGTH + Signature.SIGNATURE_BYTES;
|
||||
length += 2; // instructions length
|
||||
length += _encryptedInstructions.length;
|
||||
}
|
||||
byte rv[] = os.toByteArray();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Overall data being written: " + rv.length);
|
||||
return rv;
|
||||
return length;
|
||||
}
|
||||
/** write the message body to the output array, starting at the given index */
|
||||
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
|
||||
if ( (_tunnelId == null) || (_data == null) )
|
||||
throw new I2NPMessageException("Not enough data to write out (id=" + _tunnelId + " data=" + _data + ")");
|
||||
if (_data.length <= 0)
|
||||
throw new I2NPMessageException("Not enough data to write out (data.length=" + _data.length + ")");
|
||||
|
||||
byte id[] = DataHelper.toLong(4, _tunnelId.getTunnelId());
|
||||
System.arraycopy(id, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
byte len[] = DataHelper.toLong(4, _data.length);
|
||||
System.arraycopy(len, 0, out, curIndex, 4);
|
||||
curIndex += 4;
|
||||
System.arraycopy(_data, 0, out, curIndex, _data.length);
|
||||
curIndex += _data.length;
|
||||
if ( (_verification == null) || (_encryptedInstructions == null) ) {
|
||||
byte flag[] = DataHelper.toLong(1, FLAG_DONT_INCLUDESTRUCTURE);
|
||||
out[curIndex++] = flag[0];
|
||||
} else {
|
||||
byte flag[] = DataHelper.toLong(1, FLAG_INCLUDESTRUCTURE);
|
||||
out[curIndex++] = flag[0];
|
||||
System.arraycopy(_verification.getMessageHash().getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||
curIndex += Hash.HASH_LENGTH;
|
||||
System.arraycopy(_verification.getAuthorizationSignature().getData(), 0, out, curIndex, Signature.SIGNATURE_BYTES);
|
||||
curIndex += Signature.SIGNATURE_BYTES;
|
||||
len = DataHelper.toLong(2, _encryptedInstructions.length);
|
||||
System.arraycopy(len, 0, out, curIndex, 2);
|
||||
curIndex += 2;
|
||||
System.arraycopy(_encryptedInstructions, 0, out, curIndex, _encryptedInstructions.length);
|
||||
curIndex += _encryptedInstructions.length;
|
||||
}
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
@@ -28,7 +28,8 @@ public class TunnelSessionKey extends DataStructureImpl {
|
||||
private final static Log _log = new Log(TunnelSessionKey.class);
|
||||
private SessionKey _key;
|
||||
|
||||
public TunnelSessionKey() { setKey(null); }
|
||||
public TunnelSessionKey() { this(null); }
|
||||
public TunnelSessionKey(SessionKey key) { setKey(key); }
|
||||
|
||||
public SessionKey getKey() { return _key; }
|
||||
public void setKey(SessionKey key) { _key= key; }
|
||||
|
@@ -29,7 +29,8 @@ public class TunnelSigningPrivateKey extends DataStructureImpl {
|
||||
private final static Log _log = new Log(EndPointPrivateKey.class);
|
||||
private SigningPrivateKey _key;
|
||||
|
||||
public TunnelSigningPrivateKey() { setKey(null); }
|
||||
public TunnelSigningPrivateKey() { this(null); }
|
||||
public TunnelSigningPrivateKey(SigningPrivateKey key) { setKey(key); }
|
||||
|
||||
public SigningPrivateKey getKey() { return _key; }
|
||||
public void setKey(SigningPrivateKey key) { _key= key; }
|
||||
|
@@ -28,7 +28,8 @@ public class TunnelSigningPublicKey extends DataStructureImpl {
|
||||
private final static Log _log = new Log(TunnelSigningPublicKey.class);
|
||||
private SigningPublicKey _key;
|
||||
|
||||
public TunnelSigningPublicKey() { setKey(null); }
|
||||
public TunnelSigningPublicKey() { this(null); }
|
||||
public TunnelSigningPublicKey(SigningPublicKey key) { setKey(key); }
|
||||
|
||||
public SigningPublicKey getKey() { return _key; }
|
||||
public void setKey(SigningPublicKey key) { _key= key; }
|
||||
|
@@ -29,9 +29,10 @@ public class TunnelVerificationStructure extends DataStructureImpl {
|
||||
private Hash _msgHash;
|
||||
private Signature _authSignature;
|
||||
|
||||
public TunnelVerificationStructure() {
|
||||
setMessageHash(null);
|
||||
setAuthorizationSignature(null);
|
||||
public TunnelVerificationStructure() { this(null, null); }
|
||||
public TunnelVerificationStructure(Hash messageHash, Signature authSig) {
|
||||
setMessageHash(messageHash);
|
||||
setAuthorizationSignature(authSig);
|
||||
}
|
||||
|
||||
public Hash getMessageHash() { return _msgHash; }
|
||||
|
@@ -9,7 +9,7 @@ package net.i2p.router;
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
@@ -65,12 +65,14 @@ public abstract class ClientManagerFacade implements Service {
|
||||
|
||||
public abstract void messageReceived(ClientMessage msg);
|
||||
|
||||
public boolean verifyClientLiveliness() { return true; }
|
||||
|
||||
/**
|
||||
* Return the client's current config, or null if not connected
|
||||
*
|
||||
*/
|
||||
public abstract SessionConfig getClientSessionConfig(Destination dest);
|
||||
public void renderStatusHTML(OutputStream out) throws IOException { }
|
||||
public void renderStatusHTML(Writer out) throws IOException { }
|
||||
}
|
||||
|
||||
class DummyClientManagerFacade extends ClientManagerFacade {
|
||||
|
@@ -9,8 +9,10 @@ package net.i2p.router;
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -21,12 +23,13 @@ import java.util.Set;
|
||||
public abstract class CommSystemFacade implements Service {
|
||||
public abstract void processMessage(OutNetMessage msg);
|
||||
|
||||
public void renderStatusHTML(OutputStream out) throws IOException { }
|
||||
public void renderStatusHTML(Writer out) throws IOException { }
|
||||
|
||||
/** Create the set of RouterAddress structures based on the router's config */
|
||||
public Set createAddresses() { return new HashSet(); }
|
||||
|
||||
public int countActivePeers() { return 0; }
|
||||
public List getMostRecentErrorMessages() { return Collections.EMPTY_LIST; }
|
||||
}
|
||||
|
||||
class DummyCommSystemFacade extends CommSystemFacade {
|
||||
|
@@ -60,6 +60,13 @@ public class InNetMessagePool {
|
||||
I2NPMessage messageBody = msg.getMessage();
|
||||
msg.processingComplete();
|
||||
Date exp = messageBody.getMessageExpiration();
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Received inbound "
|
||||
+ " with id " + messageBody.getUniqueId()
|
||||
+ " expiring on " + exp
|
||||
+ " of type " + messageBody.getClass().getName());
|
||||
|
||||
boolean valid = _context.messageValidator().validateMessage(messageBody.getUniqueId(), exp.getTime());
|
||||
if (!valid) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
|
@@ -9,7 +9,7 @@ package net.i2p.router;
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -289,6 +289,37 @@ public class JobQueue {
|
||||
}
|
||||
boolean isAlive() { return _alive; }
|
||||
|
||||
/**
|
||||
* When did the most recently begin job start?
|
||||
*/
|
||||
public long getLastJobBegin() {
|
||||
long when = -1;
|
||||
// not synchronized, so might b0rk if the runners are changed
|
||||
for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext(); ) {
|
||||
long cur = ((JobQueueRunner)iter.next()).getLastBegin();
|
||||
if (cur > when)
|
||||
cur = when;
|
||||
}
|
||||
return when;
|
||||
}
|
||||
/**
|
||||
* retrieve the most recently begin and still currently active job, or null if
|
||||
* no jobs are running
|
||||
*/
|
||||
public Job getLastJob() {
|
||||
Job j = null;
|
||||
long when = -1;
|
||||
// not synchronized, so might b0rk if the runners are changed
|
||||
for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext(); ) {
|
||||
JobQueueRunner cur = (JobQueueRunner)iter.next();
|
||||
if (cur.getLastBegin() > when) {
|
||||
j = cur.getCurrentJob();
|
||||
when = cur.getLastBegin();
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking call to retrieve the next ready job
|
||||
*
|
||||
@@ -558,18 +589,18 @@ public class JobQueue {
|
||||
// the remainder are utility methods for dumping status info
|
||||
////
|
||||
|
||||
public void renderStatusHTML(OutputStream out) throws IOException {
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
ArrayList readyJobs = null;
|
||||
ArrayList timedJobs = null;
|
||||
ArrayList activeJobs = new ArrayList(1);
|
||||
ArrayList justFinishedJobs = new ArrayList(4);
|
||||
out.write("<!-- jobQueue rendering -->\n".getBytes());
|
||||
out.write("<!-- jobQueue rendering -->\n");
|
||||
out.flush();
|
||||
synchronized (_readyJobs) { readyJobs = new ArrayList(_readyJobs); }
|
||||
out.write("<!-- jobQueue rendering: after readyJobs sync -->\n".getBytes());
|
||||
out.write("<!-- jobQueue rendering: after readyJobs sync -->\n");
|
||||
out.flush();
|
||||
synchronized (_timedJobs) { timedJobs = new ArrayList(_timedJobs); }
|
||||
out.write("<!-- jobQueue rendering: after timedJobs sync -->\n".getBytes());
|
||||
out.write("<!-- jobQueue rendering: after timedJobs sync -->\n");
|
||||
out.flush();
|
||||
int numRunners = 0;
|
||||
synchronized (_queueRunners) {
|
||||
@@ -586,7 +617,7 @@ public class JobQueue {
|
||||
numRunners = _queueRunners.size();
|
||||
}
|
||||
|
||||
out.write("<!-- jobQueue rendering: after queueRunners sync -->\n".getBytes());
|
||||
out.write("<!-- jobQueue rendering: after queueRunners sync -->\n");
|
||||
out.flush();
|
||||
|
||||
StringBuffer buf = new StringBuffer(32*1024);
|
||||
@@ -617,6 +648,7 @@ public class JobQueue {
|
||||
buf.append(j.toString()).append("</li>\n");
|
||||
}
|
||||
buf.append("</ol>\n");
|
||||
out.flush();
|
||||
|
||||
buf.append("# timed jobs: ").append(timedJobs.size()).append("<ol>\n");
|
||||
TreeMap ordered = new TreeMap();
|
||||
@@ -631,15 +663,15 @@ public class JobQueue {
|
||||
}
|
||||
buf.append("</ol>\n");
|
||||
|
||||
out.write("<!-- jobQueue rendering: after main buffer, before stats -->\n".getBytes());
|
||||
out.write("<!-- jobQueue rendering: after main buffer, before stats -->\n");
|
||||
out.flush();
|
||||
|
||||
getJobStats(buf);
|
||||
|
||||
out.write("<!-- jobQueue rendering: after stats -->\n".getBytes());
|
||||
out.write("<!-- jobQueue rendering: after stats -->\n");
|
||||
out.flush();
|
||||
|
||||
out.write(buf.toString().getBytes());
|
||||
out.write(buf.toString());
|
||||
}
|
||||
|
||||
/** render the HTML for the job stats */
|
||||
|
@@ -11,6 +11,7 @@ class JobQueueRunner implements Runnable {
|
||||
private long _numJobs;
|
||||
private Job _currentJob;
|
||||
private Job _lastJob;
|
||||
private long _lastBegin;
|
||||
|
||||
public JobQueueRunner(RouterContext context, int id) {
|
||||
_context = context;
|
||||
@@ -31,6 +32,7 @@ class JobQueueRunner implements Runnable {
|
||||
public int getRunnerId() { return _id; }
|
||||
public void stopRunning() { _keepRunning = false; }
|
||||
public void startRunning() { _keepRunning = true; }
|
||||
public long getLastBegin() { return _lastBegin; }
|
||||
public void run() {
|
||||
long lastActive = _context.clock().now();
|
||||
long jobNum = 0;
|
||||
@@ -103,6 +105,7 @@ class JobQueueRunner implements Runnable {
|
||||
|
||||
private void runCurrentJob() {
|
||||
try {
|
||||
_lastBegin = _context.clock().now();
|
||||
_currentJob.runJob();
|
||||
} catch (OutOfMemoryError oom) {
|
||||
try {
|
||||
|
@@ -9,7 +9,7 @@ package net.i2p.router;
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@@ -95,5 +95,5 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
|
||||
public Set findNearestRouters(Hash key, int maxNumRouters, Set peersToIgnore) { return new HashSet(_routers.values()); }
|
||||
|
||||
public void renderStatusHTML(OutputStream out) throws IOException {}
|
||||
public void renderStatusHTML(Writer out) throws IOException {}
|
||||
}
|
||||
|
@@ -139,37 +139,18 @@ public class OutNetMessage {
|
||||
|
||||
public long getMessageSize() {
|
||||
if (_messageSize <= 0) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); // large enough to hold most messages
|
||||
_message.writeBytes(baos);
|
||||
long sz = baos.size();
|
||||
baos.reset();
|
||||
_messageSize = sz;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe);
|
||||
}
|
||||
_messageSize = _message.getMessageSize();
|
||||
}
|
||||
return _messageSize;
|
||||
}
|
||||
public byte[] getMessageData() {
|
||||
|
||||
public int getMessageData(byte outBuffer[]) {
|
||||
if (_message == null) {
|
||||
return null;
|
||||
return -1;
|
||||
} else {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); // large enough to hold most messages
|
||||
_message.writeBytes(baos);
|
||||
byte data[] = baos.toByteArray();
|
||||
_messageSize = data.length;
|
||||
return data;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe);
|
||||
}
|
||||
|
||||
return null;
|
||||
int len = _message.toByteArray(outBuffer);
|
||||
_messageSize = len;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -41,8 +41,18 @@ public class OutNetMessagePool {
|
||||
*
|
||||
*/
|
||||
public void add(OutNetMessage msg) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Adding outbound message to "
|
||||
+ msg.getTarget().getIdentity().getHash().toBase64().substring(0,6)
|
||||
+ " with id " + msg.getMessage().getUniqueId()
|
||||
+ " expiring on " + msg.getMessage().getMessageExpiration()
|
||||
+ " of type " + msg.getMessageType());
|
||||
|
||||
boolean valid = validate(msg);
|
||||
if (!valid) return;
|
||||
if (!valid) {
|
||||
_context.messageRegistry().unregisterPending(msg);
|
||||
return;
|
||||
}
|
||||
MessageSelector selector = msg.getReplySelector();
|
||||
if (selector != null) {
|
||||
_context.messageRegistry().registerPending(msg);
|
||||
|
@@ -8,7 +8,7 @@ package net.i2p.router;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -31,6 +31,6 @@ class DummyPeerManagerFacade implements PeerManagerFacade {
|
||||
public void shutdown() {}
|
||||
public void startup() {}
|
||||
public void restart() {}
|
||||
public void renderStatusHTML(OutputStream out) { }
|
||||
public void renderStatusHTML(Writer out) { }
|
||||
public List selectPeers(PeerSelectionCriteria criteria) { return null; }
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@@ -30,6 +30,7 @@ import net.i2p.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.RouterInfo;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.i2np.GarlicMessage;
|
||||
import net.i2p.data.i2np.TunnelMessage;
|
||||
import net.i2p.router.message.GarlicMessageHandler;
|
||||
@@ -37,6 +38,7 @@ import net.i2p.router.message.TunnelMessageHandler;
|
||||
import net.i2p.router.startup.StartupJob;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -125,6 +127,11 @@ public class Router {
|
||||
_gracefulShutdownDetector.setName("Graceful shutdown hook");
|
||||
_gracefulShutdownDetector.start();
|
||||
|
||||
I2PThread watchdog = new I2PThread(new RouterWatchdog(_context));
|
||||
watchdog.setName("RouterWatchdog");
|
||||
watchdog.setDaemon(true);
|
||||
watchdog.start();
|
||||
|
||||
_shutdownTasks = new HashSet(0);
|
||||
}
|
||||
|
||||
@@ -220,16 +227,73 @@ public class Router {
|
||||
}
|
||||
|
||||
public boolean isAlive() { return _isAlive; }
|
||||
|
||||
/**
|
||||
* Rebuild and republish our routerInfo since something significant
|
||||
* has changed.
|
||||
*/
|
||||
public void rebuildRouterInfo() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Rebuilding new routerInfo");
|
||||
|
||||
RouterInfo ri = null;
|
||||
if (_routerInfo != null)
|
||||
ri = new RouterInfo(_routerInfo);
|
||||
else
|
||||
ri = new RouterInfo();
|
||||
|
||||
try {
|
||||
ri.setPublished(_context.clock().now());
|
||||
Properties stats = _context.statPublisher().publishStatistics();
|
||||
ri.setOptions(stats);
|
||||
ri.setAddresses(_context.commSystem().createAddresses());
|
||||
SigningPrivateKey key = _context.keyManager().getSigningPrivateKey();
|
||||
if (key == null) {
|
||||
_log.log(Log.CRIT, "Internal error - signing private key not known? wtf");
|
||||
return;
|
||||
}
|
||||
ri.sign(key);
|
||||
setRouterInfo(ri);
|
||||
_context.netDb().publish(ri);
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.log(Log.CRIT, "Internal error - unable to sign our own address?!", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* coallesce the stats framework every minute
|
||||
*
|
||||
*/
|
||||
private final class CoallesceStatsJob extends JobImpl {
|
||||
public CoallesceStatsJob() { super(Router.this._context); }
|
||||
public CoallesceStatsJob() {
|
||||
super(Router.this._context);
|
||||
Router.this._context.statManager().createRateStat("bw.receiveBps", "How fast we receive data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
||||
Router.this._context.statManager().createRateStat("bw.sendBps", "How fast we send data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
||||
}
|
||||
public String getName() { return "Coallesce stats"; }
|
||||
public void runJob() {
|
||||
Router.this._context.statManager().coallesceStats();
|
||||
|
||||
RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
|
||||
if (receiveRate != null) {
|
||||
Rate rate = receiveRate.getRate(60*1000);
|
||||
if (rate != null) {
|
||||
double bytes = rate.getLastTotalValue();
|
||||
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
|
||||
Router.this._context.statManager().addRateData("bw.receiveBps", (long)bps, 60*1000);
|
||||
}
|
||||
}
|
||||
|
||||
RateStat sendRate = _context.statManager().getRate("transport.sendMessageSize");
|
||||
if (sendRate != null) {
|
||||
Rate rate = receiveRate.getRate(60*1000);
|
||||
if (rate != null) {
|
||||
double bytes = rate.getLastTotalValue();
|
||||
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
|
||||
Router.this._context.statManager().addRateData("bw.sendBps", (long)bps, 60*1000);
|
||||
}
|
||||
}
|
||||
|
||||
requeue(60*1000);
|
||||
}
|
||||
}
|
||||
@@ -281,8 +345,8 @@ public class Router {
|
||||
_context.inNetMessagePool().registerHandlerJobBuilder(TunnelMessage.MESSAGE_TYPE, new TunnelMessageHandler(_context));
|
||||
}
|
||||
|
||||
public void renderStatusHTML(OutputStream out) throws IOException {
|
||||
out.write(("<h1>Router console</h1>\n" +
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
out.write("<h1>Router console</h1>\n" +
|
||||
"<i><a href=\"/oldconsole.jsp\">console</a> | <a href=\"/oldstats.jsp\">stats</a></i><br>\n" +
|
||||
"<form action=\"/oldconsole.jsp\">" +
|
||||
"<select name=\"go\" onChange='location.href=this.value'>" +
|
||||
@@ -297,7 +361,7 @@ public class Router {
|
||||
"<option value=\"/oldconsole.jsp#netdb\">Network Database</option>\n" +
|
||||
"<option value=\"/oldconsole.jsp#logs\">Log messages</option>\n" +
|
||||
"</select> <input type=\"submit\" value=\"GO\" /> </form>" +
|
||||
"<hr />\n").getBytes());
|
||||
"<hr />\n");
|
||||
|
||||
StringBuffer buf = new StringBuffer(32*1024);
|
||||
|
||||
@@ -419,39 +483,39 @@ public class Router {
|
||||
buf.append("trying to transfer data. Lifetime averages count how many elephants there are on the moon [like anyone reads this text]</i>");
|
||||
buf.append("\n");
|
||||
|
||||
out.write(buf.toString().getBytes());
|
||||
out.write(buf.toString());
|
||||
|
||||
_context.bandwidthLimiter().renderStatusHTML(out);
|
||||
|
||||
out.write("<hr /><a name=\"clients\"> </a>\n".getBytes());
|
||||
out.write("<hr /><a name=\"clients\"> </a>\n");
|
||||
|
||||
_context.clientManager().renderStatusHTML(out);
|
||||
|
||||
out.write("\n<hr /><a name=\"transports\"> </a>\n".getBytes());
|
||||
out.write("\n<hr /><a name=\"transports\"> </a>\n");
|
||||
|
||||
_context.commSystem().renderStatusHTML(out);
|
||||
|
||||
out.write("\n<hr /><a name=\"profiles\"> </a>\n".getBytes());
|
||||
out.write("\n<hr /><a name=\"profiles\"> </a>\n");
|
||||
|
||||
_context.peerManager().renderStatusHTML(out);
|
||||
|
||||
out.write("\n<hr /><a name=\"tunnels\"> </a>\n".getBytes());
|
||||
out.write("\n<hr /><a name=\"tunnels\"> </a>\n");
|
||||
|
||||
_context.tunnelManager().renderStatusHTML(out);
|
||||
|
||||
out.write("\n<hr /><a name=\"jobs\"> </a>\n".getBytes());
|
||||
out.write("\n<hr /><a name=\"jobs\"> </a>\n");
|
||||
|
||||
_context.jobQueue().renderStatusHTML(out);
|
||||
|
||||
out.write("\n<hr /><a name=\"shitlist\"> </a>\n".getBytes());
|
||||
out.write("\n<hr /><a name=\"shitlist\"> </a>\n");
|
||||
|
||||
_context.shitlist().renderStatusHTML(out);
|
||||
|
||||
out.write("\n<hr /><a name=\"pending\"> </a>\n".getBytes());
|
||||
out.write("\n<hr /><a name=\"pending\"> </a>\n");
|
||||
|
||||
_context.messageRegistry().renderStatusHTML(out);
|
||||
|
||||
out.write("\n<hr /><a name=\"netdb\"> </a>\n".getBytes());
|
||||
out.write("\n<hr /><a name=\"netdb\"> </a>\n");
|
||||
|
||||
_context.netDb().renderStatusHTML(out);
|
||||
|
||||
@@ -466,7 +530,8 @@ public class Router {
|
||||
buf.append("</pre></td></tr>\n");
|
||||
}
|
||||
buf.append("</table>\n");
|
||||
out.write(buf.toString().getBytes());
|
||||
out.write(buf.toString());
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private static int MAX_MSG_LENGTH = 120;
|
||||
@@ -571,7 +636,7 @@ public class Router {
|
||||
try { _context.messageRegistry().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message registry", t); }
|
||||
try { _context.messageValidator().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message validator", t); }
|
||||
try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
|
||||
_context.listContexts().remove(_context);
|
||||
RouterContext.listContexts().remove(_context);
|
||||
dumpStats();
|
||||
try {
|
||||
for (Iterator iter = _shutdownTasks.iterator(); iter.hasNext(); ) {
|
||||
@@ -625,6 +690,14 @@ public class Router {
|
||||
public boolean gracefulShutdownInProgress() {
|
||||
return (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS));
|
||||
}
|
||||
/** How long until the graceful shutdown will kill us? */
|
||||
public long getShutdownTimeRemaining() {
|
||||
long exp = _context.tunnelManager().getLastParticipatingExpiration();
|
||||
if (exp < 0)
|
||||
return -1;
|
||||
else
|
||||
return exp + 2*CLOCK_FUDGE_FACTOR - _context.clock().now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple thread that sits and waits forever, managing the
|
||||
@@ -727,7 +800,7 @@ public class Router {
|
||||
File updateFile = new File(UPDATE_FILE);
|
||||
if (updateFile.exists()) {
|
||||
System.out.println("INFO: Update file exists [" + UPDATE_FILE + "] - installing");
|
||||
boolean ok = DataHelper.extractZip(updateFile, new File("."));
|
||||
boolean ok = FileUtil.extractZip(updateFile, new File("."));
|
||||
if (ok)
|
||||
System.out.println("INFO: Update installed");
|
||||
else
|
||||
|
@@ -31,4 +31,15 @@ public interface RouterThrottle {
|
||||
*
|
||||
*/
|
||||
public boolean acceptNetDbLookupRequest(Hash key);
|
||||
|
||||
/** How backed up we are at the moment processing messages (in milliseconds) */
|
||||
public long getMessageDelay();
|
||||
/** How backed up our tunnels are at the moment (in milliseconds) */
|
||||
public long getTunnelLag();
|
||||
/**
|
||||
* How much faster (or if negative, slower) we are receiving data as
|
||||
* opposed to our longer term averages?
|
||||
*
|
||||
*/
|
||||
public double getInboundRateDelta();
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user