forked from I2P_Developers/i2p.i2p
Compare commits
97 Commits
i2p_0_4_0_
...
i2p_0_4_1_
Author | SHA1 | Date | |
---|---|---|---|
a95a968fa8 | |||
6c08941d8b | |||
e13a5b3865 | |||
9011d5604a | |||
78aa4ca137 | |||
93111842df | |||
88693f8adc | |||
f904b012e9 | |||
cebe0a151f | |||
8fffad0891 | |||
fb1263dad7 | |||
28c5d6c10d | |||
e7a6f6836e | |||
f8ffe016d1 | |||
ec322f0966 | |||
0674709fc6 | |||
d91ac7ef21 | |||
2f0c3c7baf | |||
be68407707 | |||
f799a25aeb | |||
8329d045f1 | |||
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)
|
||||
*
|
||||
*/
|
||||
@ -63,7 +63,7 @@ class WebEditPageFormGenerator {
|
||||
addOptions(buf, controller);
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\">\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
|
||||
buf.append(" <i>confirm</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append(" <i>confirm removal:</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append("</form>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
@ -83,7 +83,7 @@ class WebEditPageFormGenerator {
|
||||
addOptions(buf, controller);
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\"><br />\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
|
||||
buf.append(" <i>confirm</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append(" <i>confirm removal:</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append("</form>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
@ -118,7 +118,7 @@ class WebEditPageFormGenerator {
|
||||
addOptions(buf, controller);
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\">\n");
|
||||
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
|
||||
buf.append(" <i>confirm</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append(" <i>confirm removal:</i> <input type=\"checkbox\" name=\"removeConfirm\" value=\"true\" />\n");
|
||||
buf.append("</form>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -0,0 +1,216 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.data.ByteArray;
|
||||
|
||||
/**
|
||||
* Stream that can be given messages out of order
|
||||
* yet present them in order.
|
||||
*
|
||||
*/
|
||||
public class MessageInputStream extends InputStream {
|
||||
/**
|
||||
* List of ByteArray objects of data ready to be read,
|
||||
* with the first ByteArray at index 0, and the next
|
||||
* actual byte to be read at _readyDataBlockIndex of
|
||||
* that array.
|
||||
*
|
||||
*/
|
||||
private List _readyDataBlocks;
|
||||
private int _readyDataBlockIndex;
|
||||
/** highest message ID used in the readyDataBlocks */
|
||||
private long _highestReadyBlockId;
|
||||
/**
|
||||
* Message ID (Long) to ByteArray for blocks received
|
||||
* out of order when there are lower IDs not yet
|
||||
* received
|
||||
*/
|
||||
private Map _notYetReadyBlocks;
|
||||
/**
|
||||
* if we have received a flag saying there won't be later messages, EOF
|
||||
* after we have cleared what we have received.
|
||||
*/
|
||||
private boolean _closeReceived;
|
||||
/** if we don't want any more data, ignore the data */
|
||||
private boolean _locallyClosed;
|
||||
private int _readTimeout;
|
||||
|
||||
private Object _dataLock;
|
||||
|
||||
public MessageInputStream() {
|
||||
_readyDataBlocks = new ArrayList(4);
|
||||
_readyDataBlockIndex = 0;
|
||||
_highestReadyBlockId = -1;
|
||||
_readTimeout = -1;
|
||||
_notYetReadyBlocks = new HashMap(4);
|
||||
_dataLock = new Object();
|
||||
_closeReceived = false;
|
||||
_locallyClosed = false;
|
||||
}
|
||||
|
||||
/** What is the highest block ID we've completely received through? */
|
||||
public long getHighestReadyBockId() {
|
||||
synchronized (_dataLock) {
|
||||
return _highestReadyBlockId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascending list of block IDs greater than the highest
|
||||
* ready block ID, or null if there aren't any.
|
||||
*
|
||||
*/
|
||||
public long[] getOutOfOrderBlocks() {
|
||||
long blocks[] = null;
|
||||
synchronized (_dataLock) {
|
||||
int num = _notYetReadyBlocks.size();
|
||||
if (num <= 0) return null;
|
||||
blocks = new long[num];
|
||||
int i = 0;
|
||||
for (Iterator iter = _notYetReadyBlocks.keySet().iterator(); iter.hasNext(); ) {
|
||||
Long id = (Long)iter.next();
|
||||
blocks[i] = id.longValue();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
Arrays.sort(blocks);
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/** how many blocks have we received that we still have holes before? */
|
||||
public int getOutOfOrderBlockCount() {
|
||||
synchronized (_dataLock) {
|
||||
return _notYetReadyBlocks.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* how long a read() call should block (if less than 0, block indefinitely,
|
||||
* but if it is 0, do not block at all)
|
||||
*/
|
||||
public int getReadTimeout() { return _readTimeout; }
|
||||
public void setReadTimeout(int timeout) { _readTimeout = timeout; }
|
||||
|
||||
/**
|
||||
* A new message has arrived - toss it on the appropriate queue (moving
|
||||
* previously pending messages to the ready queue if it fills the gap, etc)
|
||||
*
|
||||
*/
|
||||
public void messageReceived(long messageId, byte payload[]) {
|
||||
synchronized (_dataLock) {
|
||||
if (messageId <= _highestReadyBlockId) return; // already received
|
||||
if (_highestReadyBlockId + 1 == messageId) {
|
||||
if (!_locallyClosed)
|
||||
_readyDataBlocks.add(new ByteArray(payload));
|
||||
_highestReadyBlockId = messageId;
|
||||
// now pull in any previously pending blocks
|
||||
while (_notYetReadyBlocks.containsKey(new Long(_highestReadyBlockId + 1))) {
|
||||
_readyDataBlocks.add(_notYetReadyBlocks.get(new Long(_highestReadyBlockId + 1)));
|
||||
_highestReadyBlockId++;
|
||||
}
|
||||
_dataLock.notifyAll();
|
||||
} else {
|
||||
if (_locallyClosed) // dont need the payload, just the msgId in order
|
||||
_notYetReadyBlocks.put(new Long(messageId), new ByteArray(null));
|
||||
else
|
||||
_notYetReadyBlocks.put(new Long(messageId), new ByteArray(payload));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if (_locallyClosed) throw new IOException("Already locally closed");
|
||||
synchronized (_dataLock) {
|
||||
if (_readyDataBlocks.size() <= 0) {
|
||||
if ( (_notYetReadyBlocks.size() <= 0) && (_closeReceived) ) {
|
||||
return -1;
|
||||
} else {
|
||||
if (_readTimeout < 0) {
|
||||
try { _dataLock.wait(); } catch (InterruptedException ie) { }
|
||||
} else if (_readTimeout > 0) {
|
||||
try { _dataLock.wait(_readTimeout); } catch (InterruptedException ie) { }
|
||||
} else { // readTimeout == 0
|
||||
// noop, don't block
|
||||
}
|
||||
if (_readyDataBlocks.size() <= 0) {
|
||||
throw new InterruptedIOException("Timeout reading");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// either was already ready, or we wait()ed and it arrived
|
||||
ByteArray cur = (ByteArray)_readyDataBlocks.get(0);
|
||||
byte rv = cur.getData()[_readyDataBlockIndex++];
|
||||
if (cur.getData().length <= _readyDataBlockIndex) {
|
||||
_readyDataBlockIndex = 0;
|
||||
_readyDataBlocks.remove(0);
|
||||
}
|
||||
return (rv < 0 ? rv + 256 : rv);
|
||||
}
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
if (_locallyClosed) throw new IOException("Already closed, you wanker");
|
||||
synchronized (_dataLock) {
|
||||
if (_readyDataBlocks.size() <= 0)
|
||||
return 0;
|
||||
int numBytes = 0;
|
||||
for (int i = 0; i < _readyDataBlocks.size(); i++) {
|
||||
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
|
||||
if (i == 0)
|
||||
numBytes += cur.getData().length - _readyDataBlockIndex;
|
||||
else
|
||||
numBytes += cur.getData().length;
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* How many bytes are queued up for reading (or sitting in the out-of-order
|
||||
* buffer)?
|
||||
*
|
||||
*/
|
||||
public int getTotalQueuedSize() {
|
||||
synchronized (_dataLock) {
|
||||
if (_locallyClosed) return 0;
|
||||
int numBytes = 0;
|
||||
for (int i = 0; i < _readyDataBlocks.size(); i++) {
|
||||
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
|
||||
if (i == 0)
|
||||
numBytes += cur.getData().length - _readyDataBlockIndex;
|
||||
else
|
||||
numBytes += cur.getData().length;
|
||||
}
|
||||
for (Iterator iter = _notYetReadyBlocks.values().iterator(); iter.hasNext(); ) {
|
||||
ByteArray cur = (ByteArray)iter.next();
|
||||
numBytes += cur.getData().length;
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
synchronized (_dataLock) {
|
||||
_readyDataBlocks.clear();
|
||||
|
||||
// we don't need the data, but we do need to keep track of the messageIds
|
||||
// received, so we can ACK accordingly
|
||||
for (Iterator iter = _notYetReadyBlocks.values().iterator(); iter.hasNext(); ) {
|
||||
ByteArray ba = (ByteArray)iter.next();
|
||||
ba.setData(null);
|
||||
}
|
||||
_locallyClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class MessageOutputStream extends OutputStream {
|
||||
private byte _buf[];
|
||||
private int _valid;
|
||||
private Object _dataLock;
|
||||
private DataReceiver _dataReceiver;
|
||||
private IOException _streamError;
|
||||
|
||||
public MessageOutputStream(DataReceiver receiver) {
|
||||
this(receiver, 64*1024);
|
||||
}
|
||||
public MessageOutputStream(DataReceiver receiver, int bufSize) {
|
||||
super();
|
||||
_buf = new byte[bufSize];
|
||||
_dataReceiver = receiver;
|
||||
_dataLock = new Object();
|
||||
}
|
||||
|
||||
public void write(byte b[]) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
synchronized (_dataLock) {
|
||||
int remaining = len;
|
||||
while (remaining > 0) {
|
||||
if (_valid + remaining < _buf.length) {
|
||||
// simply buffer the data, no flush
|
||||
System.arraycopy(b, off, _buf, _valid, remaining);
|
||||
remaining = 0;
|
||||
} else {
|
||||
// buffer whatever we can fit then flush,
|
||||
// repeating until we've pushed all of the
|
||||
// data through
|
||||
int toWrite = _buf.length - _valid;
|
||||
System.arraycopy(b, off, _buf, _valid, toWrite);
|
||||
remaining -= toWrite;
|
||||
_valid = _buf.length;
|
||||
_dataReceiver.writeData(_buf, 0, _valid);
|
||||
_valid = 0;
|
||||
throwAnyError();
|
||||
}
|
||||
}
|
||||
}
|
||||
throwAnyError();
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
write(new byte[] { (byte)b }, 0, 1);
|
||||
throwAnyError();
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
synchronized (_dataLock) {
|
||||
_dataReceiver.writeData(_buf, 0, _valid);
|
||||
_valid = 0;
|
||||
}
|
||||
throwAnyError();
|
||||
}
|
||||
|
||||
private void throwAnyError() throws IOException {
|
||||
if (_streamError != null) {
|
||||
IOException ioe = _streamError;
|
||||
_streamError = null;
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
void streamErrorOccurred(IOException ioe) {
|
||||
_streamError = ioe;
|
||||
}
|
||||
|
||||
/**
|
||||
* called whenever the engine wants to push more data to the
|
||||
* peer
|
||||
*
|
||||
*/
|
||||
void flushAvailable(DataReceiver target) {
|
||||
synchronized (_dataLock) {
|
||||
target.writeData(_buf, 0, _valid);
|
||||
_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public interface DataReceiver {
|
||||
public void writeData(byte buf[], int off, int size);
|
||||
}
|
||||
}
|
389
apps/streaming/java/src/net/i2p/client/streaming/Packet.java
Normal file
389
apps/streaming/java/src/net/i2p/client/streaming/Packet.java
Normal file
@ -0,0 +1,389 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
|
||||
/**
|
||||
* Contain a single packet transferred as part of a streaming connection.
|
||||
* The data format is as follows:<ul>
|
||||
* <li>{@see #getSendStreamId sendStreamId} [4 byte value]</li>
|
||||
* <li>{@see #getReceiveStreamId receiveStreamId} [4 byte value]</li>
|
||||
* <li>{@see #getSequenceNum sequenceNum} [4 byte unsigned integer]</li>
|
||||
* <li>{@see #getAckThrough ackThrough} [4 byte unsigned integer]</li>
|
||||
* <li>number of NACKs [1 byte unsigned integer]</li>
|
||||
* <li>that many {@see #getNacks NACKs}</li>
|
||||
* <li>{@see #getResendDelay resendDelay} [1 byte integer]</li>
|
||||
* <li>flags [2 byte value]</li>
|
||||
* <li>option data size [2 byte integer]</li>
|
||||
* <li>option data specified by those flags [0 or more bytes]</li>
|
||||
* <li>payload [remaining packet size]</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>The flags field above specifies some metadata about the packet, and in
|
||||
* turn may require certain additional data to be included. The flags are
|
||||
* as follows (with any data structures specified added to the options area
|
||||
* in the given order):</p><ol>
|
||||
* <li>{@see #FLAG_SYNCHRONIZE}: no option data</li>
|
||||
* <li>{@see #FLAG_CLOSE}: no option data</li>
|
||||
* <li>{@see #FLAG_RESET}: no option data</li>
|
||||
* <li>{@see #FLAG_SIGNATURE_INCLUDED}: {@see net.i2p.data.Signature}</li>
|
||||
* <li>{@see #FLAG_SIGNATURE_REQUESTED}: no option data</li>
|
||||
* <li>{@see #FLAG_FROM_INCLUDED}: {@see net.i2p.data.Destination}</li>
|
||||
* <li>{@see #FLAG_DELAY_REQUESTED}: 1 byte integer</li>
|
||||
* <li>{@see #FLAG_MAX_PACKET_SIZE_INCLUDED}: 2 byte integer</li>
|
||||
* <li>{@see #FLAG_PROFILE_INTERACTIVE}: no option data</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>If the signature is included, it uses the Destination's DSA key
|
||||
* to sign the entire header and payload with the space in the options
|
||||
* for the signature being set to all zeroes.</p>
|
||||
*
|
||||
*/
|
||||
public class Packet {
|
||||
private byte _sendStreamId[];
|
||||
private byte _receiveStreamId[];
|
||||
private long _sequenceNum;
|
||||
private long _ackThrough;
|
||||
private long _nacks[];
|
||||
private int _resendDelay;
|
||||
private int _flags;
|
||||
private byte _payload[];
|
||||
// the next four are set only if the flags say so
|
||||
private Signature _optionSignature;
|
||||
private Destination _optionFrom;
|
||||
private int _optionDelay;
|
||||
private int _optionMaxSize;
|
||||
|
||||
/**
|
||||
* The receiveStreamId will be set to this when the packet doesn't know
|
||||
* what ID will be assigned by the remote peer (aka this is the initial
|
||||
* synchronize packet)
|
||||
*
|
||||
*/
|
||||
public static final byte RECEIVE_STREAM_ID_UNKNOWN[] = new byte[] { 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
/**
|
||||
* This packet is creating a new socket connection (if the receiveStreamId
|
||||
* is RECEIVE_STREAM_ID_UNKNOWN) or it is acknowledging a request to
|
||||
* create a connection and in turn is accepting the socket.
|
||||
*
|
||||
*/
|
||||
public static final int FLAG_SYNCHRONIZE = (1 << 0);
|
||||
/**
|
||||
* The sender of this packet will not be sending any more payload data.
|
||||
*/
|
||||
public static final int FLAG_CLOSE = (1 << 1);
|
||||
/**
|
||||
* This packet is being sent to signify that the socket does not exist
|
||||
* (or, if in response to an initial synchronize packet, that the
|
||||
* connection was refused).
|
||||
*
|
||||
*/
|
||||
public static final int FLAG_RESET = (1 << 2);
|
||||
/**
|
||||
* This packet contains a DSA signature from the packet's sender. This
|
||||
* signature is within the packet options. All synchronize packets must
|
||||
* have this flag set.
|
||||
*
|
||||
*/
|
||||
public static final int FLAG_SIGNATURE_INCLUDED = (1 << 3);
|
||||
/**
|
||||
* This packet wants the recipient to include signatures on subsequent
|
||||
* packets sent to the creator of this packet.
|
||||
*/
|
||||
public static final int FLAG_SIGNATURE_REQUESTED = (1 << 4);
|
||||
/**
|
||||
* This packet includes the full I2P destination of the packet's sender.
|
||||
* The initial synchronize packet must have this flag set.
|
||||
*/
|
||||
public static final int FLAG_FROM_INCLUDED = (1 << 5);
|
||||
/**
|
||||
* This packet includes an explicit request for the recipient to delay
|
||||
* sending any packets with data for a given amount of time.
|
||||
*
|
||||
*/
|
||||
public static final int FLAG_DELAY_REQUESTED = (1 << 6);
|
||||
/**
|
||||
* This packet includes a request that the recipient not send any
|
||||
* subsequent packets with payloads greater than a specific size.
|
||||
* If not set and no prior value was delivered, the maximum value
|
||||
* will be assumed (approximately 32KB).
|
||||
*
|
||||
*/
|
||||
public static final int FLAG_MAX_PACKET_SIZE_INCLUDED = (1 << 7);
|
||||
/**
|
||||
* If set, this packet is travelling as part of an interactive flow,
|
||||
* meaning it is more lag sensitive than throughput sensitive. aka
|
||||
* send data ASAP rather than waiting around to send full packets.
|
||||
*
|
||||
*/
|
||||
public static final int FLAG_PROFILE_INTERACTIVE = (1 << 8);
|
||||
|
||||
/** what stream is this packet a part of? */
|
||||
public byte[] getSendStreamId() { return _sendStreamId; }
|
||||
public void setSendStreamId(byte[] id) { _sendStreamId = id; }
|
||||
|
||||
/**
|
||||
* what is the stream replies should be sent on? if the
|
||||
* connection is still being built, this should be
|
||||
* {@see #RECEIVE_STREAM_ID_UNKNOWN}.
|
||||
*
|
||||
*/
|
||||
public byte[] getReceiveStreamId() { return _receiveStreamId; }
|
||||
public void setReceiveStreamId(byte[] id) { _receiveStreamId = id; }
|
||||
|
||||
/** 0-indexed sequence number for this Packet in the sendStream */
|
||||
public long getSequenceNum() { return _sequenceNum; }
|
||||
public void setSequenceNum(long num) { _sequenceNum = num; }
|
||||
|
||||
/**
|
||||
* what is the highest packet sequence number that received
|
||||
* on the receiveStreamId? This field is ignored on the initial
|
||||
* connection packet (where receiveStreamId is the unknown id).
|
||||
*
|
||||
*/
|
||||
public long getAckThrough() { return _ackThrough; }
|
||||
public void setAckThrough(long id) { _ackThrough = id; }
|
||||
|
||||
/**
|
||||
* What packet sequence numbers below the getAckThrough() value
|
||||
* have not been received? this may be null.
|
||||
*
|
||||
*/
|
||||
public long[] getNacks() { return _nacks; }
|
||||
public void setNacks(long nacks[]) { _nacks = nacks; }
|
||||
|
||||
/**
|
||||
* How long is the creator of this packet going to wait before
|
||||
* resending this packet (if it hasn't yet been ACKed). The
|
||||
* value is seconds since the packet was created.
|
||||
*
|
||||
*/
|
||||
public int getResendDelay() { return _resendDelay; }
|
||||
public void setResendDelay(int numSeconds) { _resendDelay = numSeconds; }
|
||||
|
||||
/** get the actual payload of the message. may be null */
|
||||
public byte[] getPayload() { return _payload; }
|
||||
public void setPayload(byte payload[]) { _payload = payload; }
|
||||
|
||||
/** is a particular flag set on this packet? */
|
||||
public boolean isFlagSet(int flag) { return 0 != (_flags & flag); }
|
||||
public void setFlag(int flag) { _flags |= flag; }
|
||||
|
||||
/** the signature on the packet (only included if the flag for it is set) */
|
||||
public Signature getOptionalSignature() { return _optionSignature; }
|
||||
public void setOptionalSignature(Signature sig) { _optionSignature = sig; }
|
||||
|
||||
/** the sender of the packet (only included if the flag for it is set) */
|
||||
public Destination getOptionalFrom() { return _optionFrom; }
|
||||
public void setOptionalFrom(Destination from) { _optionFrom = from; }
|
||||
|
||||
/**
|
||||
* How many milliseconds the sender of this packet wants the recipient
|
||||
* to wait before sending any more data (only valid if the flag for it is
|
||||
* set)
|
||||
*/
|
||||
public int getOptionalDelay() { return _optionDelay; }
|
||||
public void setOptionalDelay(int delayMs) { _optionDelay = delayMs; }
|
||||
|
||||
/**
|
||||
* What is the largest payload the sender of this packet wants to receive?
|
||||
*
|
||||
*/
|
||||
public int getOptionalMaxSize() { return _optionMaxSize; }
|
||||
public void setOptionalMaxSize(int numBytes) { _optionMaxSize = numBytes; }
|
||||
|
||||
/**
|
||||
* Write the packet to the buffer (starting at the offset) and return
|
||||
* the number of bytes written.
|
||||
*
|
||||
* @throws IllegalStateException if there is data missing or otherwise b0rked
|
||||
*/
|
||||
public int writePacket(byte buffer[], int offset) throws IllegalStateException {
|
||||
return writePacket(buffer, offset, true);
|
||||
}
|
||||
/**
|
||||
* @param includeSig if true, include the real signature, otherwise put zeroes
|
||||
* in its place.
|
||||
*/
|
||||
private int writePacket(byte buffer[], int offset, boolean includeSig) throws IllegalStateException {
|
||||
int cur = offset;
|
||||
System.arraycopy(_sendStreamId, 0, buffer, cur, _sendStreamId.length);
|
||||
cur += _sendStreamId.length;
|
||||
System.arraycopy(_receiveStreamId, 0, buffer, cur, _receiveStreamId.length);
|
||||
cur += _receiveStreamId.length;
|
||||
DataHelper.toLong(buffer, cur, 4, _sequenceNum);
|
||||
cur += 4;
|
||||
DataHelper.toLong(buffer, cur, 4, _ackThrough);
|
||||
cur += 4;
|
||||
if (_nacks != null) {
|
||||
DataHelper.toLong(buffer, cur, 1, _nacks.length);
|
||||
cur++;
|
||||
for (int i = 0; i < _nacks.length; i++) {
|
||||
DataHelper.toLong(buffer, cur, 4, _nacks[i]);
|
||||
cur += 4;
|
||||
}
|
||||
} else {
|
||||
DataHelper.toLong(buffer, cur, 1, 0);
|
||||
cur++;
|
||||
}
|
||||
DataHelper.toLong(buffer, cur, 1, _resendDelay);
|
||||
cur++;
|
||||
DataHelper.toLong(buffer, cur, 2, _flags);
|
||||
cur += 2;
|
||||
|
||||
int optionSize = 0;
|
||||
if (isFlagSet(FLAG_DELAY_REQUESTED))
|
||||
optionSize += 1;
|
||||
if (isFlagSet(FLAG_FROM_INCLUDED))
|
||||
optionSize += _optionFrom.size();
|
||||
if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED))
|
||||
optionSize += 2;
|
||||
if (isFlagSet(FLAG_SIGNATURE_INCLUDED))
|
||||
optionSize += Signature.SIGNATURE_BYTES;
|
||||
|
||||
DataHelper.toLong(buffer, cur, 2, optionSize);
|
||||
cur += 2;
|
||||
|
||||
if (isFlagSet(FLAG_DELAY_REQUESTED)) {
|
||||
DataHelper.toLong(buffer, cur, 1, _optionDelay);
|
||||
cur++;
|
||||
}
|
||||
if (isFlagSet(FLAG_FROM_INCLUDED)) {
|
||||
cur += _optionFrom.writeBytes(buffer, cur);
|
||||
}
|
||||
if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED)) {
|
||||
DataHelper.toLong(buffer, cur, 2, _optionMaxSize);
|
||||
cur += 2;
|
||||
}
|
||||
if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
|
||||
if (includeSig)
|
||||
System.arraycopy(_optionSignature.getData(), 0, buffer, cur, Signature.SIGNATURE_BYTES);
|
||||
else // we're signing (or validating)
|
||||
Arrays.fill(buffer, cur, Signature.SIGNATURE_BYTES, (byte)0x0);
|
||||
cur += Signature.SIGNATURE_BYTES;
|
||||
}
|
||||
|
||||
if (_payload != null) {
|
||||
System.arraycopy(_payload, 0, buffer, cur, _payload.length);
|
||||
cur += _payload.length;
|
||||
}
|
||||
|
||||
return cur - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the packet from the buffer (starting at the offset) and return
|
||||
* the number of bytes read.
|
||||
*
|
||||
* @param buffer packet buffer containing the data
|
||||
* @param offset index into the buffer to start readign
|
||||
* @param length how many bytes within the buffer past the offset are
|
||||
* part of the packet?
|
||||
*
|
||||
* @throws IllegalArgumentException if the data is b0rked
|
||||
*/
|
||||
public void readPacket(byte buffer[], int offset, int length) throws IllegalArgumentException {
|
||||
int cur = offset;
|
||||
_sendStreamId = new byte[4];
|
||||
System.arraycopy(buffer, cur, _sendStreamId, 0, 4);
|
||||
cur += 4;
|
||||
_receiveStreamId = new byte[4];
|
||||
System.arraycopy(buffer, cur, _receiveStreamId, 0, 4);
|
||||
cur += 4;
|
||||
_sequenceNum = DataHelper.fromLong(buffer, cur, 4);
|
||||
cur += 4;
|
||||
_ackThrough = DataHelper.fromLong(buffer, cur, 4);
|
||||
cur += 4;
|
||||
int numNacks = (int)DataHelper.fromLong(buffer, cur, 1);
|
||||
cur++;
|
||||
if (numNacks > 0) {
|
||||
_nacks = new long[numNacks];
|
||||
for (int i = 0; i < numNacks; i++) {
|
||||
_nacks[i] = DataHelper.fromLong(buffer, cur, 4);
|
||||
cur += 4;
|
||||
}
|
||||
} else {
|
||||
_nacks = null;
|
||||
}
|
||||
_resendDelay = (int)DataHelper.fromLong(buffer, cur, 1);
|
||||
cur++;
|
||||
_flags = (int)DataHelper.fromLong(buffer, cur, 2);
|
||||
cur += 2;
|
||||
|
||||
int optionSize = (int)DataHelper.fromLong(buffer, cur, 2);
|
||||
cur += 2;
|
||||
int payloadBegin = cur + optionSize;
|
||||
|
||||
// skip ahead to the payload
|
||||
_payload = new byte[offset + length - payloadBegin];
|
||||
System.arraycopy(buffer, payloadBegin, _payload, 0, _payload.length);
|
||||
|
||||
// ok now lets go back and deal with the options
|
||||
if (isFlagSet(FLAG_DELAY_REQUESTED)) {
|
||||
_optionDelay = (int)DataHelper.fromLong(buffer, cur, 1);
|
||||
cur++;
|
||||
}
|
||||
if (isFlagSet(FLAG_FROM_INCLUDED)) {
|
||||
_optionFrom = new Destination();
|
||||
cur += _optionFrom.readBytes(buffer, cur);
|
||||
}
|
||||
if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED)) {
|
||||
_optionMaxSize = (int)DataHelper.fromLong(buffer, cur, 2);
|
||||
cur += 2;
|
||||
}
|
||||
if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
|
||||
Signature sig = new Signature();
|
||||
byte buf[] = new byte[Signature.SIGNATURE_BYTES];
|
||||
System.arraycopy(buffer, cur, buf, 0, Signature.SIGNATURE_BYTES);
|
||||
sig.setData(buf);
|
||||
cur += Signature.SIGNATURE_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the signature on the data is valid.
|
||||
*
|
||||
* @return true if the signature exists and validates against the data,
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean verifySignature(I2PAppContext ctx, Destination from, byte buffer[]) {
|
||||
if (!isFlagSet(FLAG_SIGNATURE_INCLUDED)) return false;
|
||||
if (_optionSignature == null) return false;
|
||||
|
||||
int size = writePacket(buffer, 0, false);
|
||||
return ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, from.getSigningPublicKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign and write the packet to the buffer (starting at the offset) and return
|
||||
* the number of bytes written.
|
||||
*
|
||||
* @throws IllegalStateException if there is data missing or otherwise b0rked
|
||||
*/
|
||||
public int writeSignedPacket(byte buffer[], int offset, I2PAppContext ctx, SigningPrivateKey key) throws IllegalStateException {
|
||||
setFlag(FLAG_SIGNATURE_INCLUDED);
|
||||
int size = writePacket(buffer, offset, false);
|
||||
_optionSignature = ctx.dsa().sign(buffer, offset, size, key);
|
||||
// jump into the signed data and inject the signature where we
|
||||
// previously placed a bunch of zeroes
|
||||
int signatureOffset = offset
|
||||
+ 4 // sendStreamId
|
||||
+ 4 // receiveStreamId
|
||||
+ 4 // sequenceNum
|
||||
+ 4 // ackThrough
|
||||
+ (_nacks != null ? 4*_nacks.length + 1 : 1)
|
||||
+ 1 // resendDelay
|
||||
+ 2 // flags
|
||||
+ 2 // optionSize
|
||||
+ (isFlagSet(FLAG_DELAY_REQUESTED) ? 1 : 0)
|
||||
+ (isFlagSet(FLAG_FROM_INCLUDED) ? _optionFrom.size() : 0)
|
||||
+ (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED) ? 2 : 0);
|
||||
System.arraycopy(_optionSignature.getData(), 0, buffer, signatureOffset, Signature.SIGNATURE_BYTES);
|
||||
return size;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Stress test the MessageInputStream
|
||||
*/
|
||||
public class MessageInputStreamTest {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
|
||||
public MessageInputStreamTest() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(MessageInputStreamTest.class);
|
||||
}
|
||||
|
||||
public void testInOrder() {
|
||||
byte orig[] = new byte[32*1024];
|
||||
_context.random().nextBytes(orig);
|
||||
|
||||
MessageInputStream in = new MessageInputStream();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
byte msg[] = new byte[1024];
|
||||
System.arraycopy(orig, i*1024, msg, 0, 1024);
|
||||
in.messageReceived(i, msg);
|
||||
}
|
||||
|
||||
byte read[] = new byte[32*1024];
|
||||
try {
|
||||
int howMany = DataHelper.read(in, read);
|
||||
if (howMany != orig.length)
|
||||
throw new RuntimeException("Failed test: not enough bytes read [" + howMany + "]");
|
||||
if (!DataHelper.eq(orig, read))
|
||||
throw new RuntimeException("Failed test: data read is not equal");
|
||||
|
||||
_log.info("Passed test: in order");
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("IOError reading: " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testRandomOrder() {
|
||||
byte orig[] = new byte[32*1024];
|
||||
_context.random().nextBytes(orig);
|
||||
|
||||
MessageInputStream in = new MessageInputStream();
|
||||
ArrayList order = new ArrayList(32);
|
||||
for (int i = 0; i < 32; i++)
|
||||
order.add(new Integer(i));
|
||||
Collections.shuffle(order);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
byte msg[] = new byte[1024];
|
||||
Integer cur = (Integer)order.get(i);
|
||||
System.arraycopy(orig, cur.intValue()*1024, msg, 0, 1024);
|
||||
in.messageReceived(cur.intValue(), msg);
|
||||
_log.debug("Injecting " + cur);
|
||||
}
|
||||
|
||||
byte read[] = new byte[32*1024];
|
||||
try {
|
||||
int howMany = DataHelper.read(in, read);
|
||||
if (howMany != orig.length)
|
||||
throw new RuntimeException("Failed test: not enough bytes read [" + howMany + "]");
|
||||
if (!DataHelper.eq(orig, read))
|
||||
throw new RuntimeException("Failed test: data read is not equal");
|
||||
|
||||
_log.info("Passed test: random order");
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("IOError reading: " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
MessageInputStreamTest t = new MessageInputStreamTest();
|
||||
try {
|
||||
t.testInOrder();
|
||||
t.testRandomOrder();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
@ -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.23 $ $Date: 2004/10/10 14:33:08 $";
|
||||
public final static String VERSION = "0.4.1.3";
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ public interface I2PSession {
|
||||
* @return whether it was accepted by the router for delivery or not
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* Like sendMessage above, except the key used and the tags sent are exposed to the
|
||||
@ -66,8 +67,8 @@ public interface I2PSession {
|
||||
* the contents of the set is ignored during the call, but afterwards it contains a set of SessionTag
|
||||
* objects that were sent along side the given keyUsed.
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent)
|
||||
throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
|
||||
/** Receive a message that the router has notified the client about, returning
|
||||
* the payload.
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -62,13 +62,21 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
}
|
||||
|
||||
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException {
|
||||
return sendMessage(dest, payload, new SessionKey(), new HashSet(64));
|
||||
return sendMessage(dest, payload, 0, payload.length);
|
||||
}
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, new SessionKey(), new HashSet(64));
|
||||
}
|
||||
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent)
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException {
|
||||
return sendMessage(dest, payload, 0, payload.length, keyUsed, tagsSent);
|
||||
}
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent)
|
||||
throws I2PSessionException {
|
||||
if (isClosed()) throw new I2PSessionException("Already closed");
|
||||
if (SHOULD_COMPRESS) payload = DataHelper.compress(payload);
|
||||
if (SHOULD_COMPRESS) payload = DataHelper.compress(payload, offset, size);
|
||||
else throw new IllegalStateException("we need to update sendGuaranteed to support partial send");
|
||||
|
||||
// we always send as guaranteed (so we get the session keys/tags acked),
|
||||
// but only block until the appropriate event has been reached (guaranteed
|
||||
// success or accepted). we may want to break this out into a seperate
|
||||
|
@ -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");
|
||||
|
@ -50,8 +50,10 @@ public class DSAEngine {
|
||||
public static DSAEngine getInstance() {
|
||||
return I2PAppContext.getGlobalContext().dsa();
|
||||
}
|
||||
|
||||
public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) {
|
||||
return verifySignature(signature, signedData, 0, signedData.length, verifyingKey);
|
||||
}
|
||||
public boolean verifySignature(Signature signature, byte signedData[], int offset, int size, SigningPublicKey verifyingKey) {
|
||||
long start = _context.clock().now();
|
||||
|
||||
byte[] sigbytes = signature.getData();
|
||||
@ -68,7 +70,7 @@ public class DSAEngine {
|
||||
BigInteger r = new NativeBigInteger(1, rbytes);
|
||||
BigInteger y = new NativeBigInteger(1, verifyingKey.getData());
|
||||
BigInteger w = s.modInverse(CryptoConstants.dsaq);
|
||||
byte data[] = calculateHash(signedData).getData();
|
||||
byte data[] = calculateHash(signedData, offset, size).getData();
|
||||
NativeBigInteger bi = new NativeBigInteger(1, data);
|
||||
BigInteger u1 = bi.multiply(w).mod(CryptoConstants.dsaq);
|
||||
BigInteger u2 = r.multiply(w).mod(CryptoConstants.dsaq);
|
||||
@ -88,6 +90,9 @@ public class DSAEngine {
|
||||
}
|
||||
|
||||
public Signature sign(byte data[], SigningPrivateKey signingKey) {
|
||||
return sign(data, 0, data.length, signingKey);
|
||||
}
|
||||
public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
|
||||
if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
|
||||
long start = _context.clock().now();
|
||||
|
||||
@ -100,7 +105,7 @@ public class DSAEngine {
|
||||
|
||||
BigInteger r = CryptoConstants.dsag.modPow(k, CryptoConstants.dsap).mod(CryptoConstants.dsaq);
|
||||
BigInteger kinv = k.modInverse(CryptoConstants.dsaq);
|
||||
Hash h = calculateHash(data);
|
||||
Hash h = calculateHash(data, offset, length);
|
||||
|
||||
if (h == null) return null;
|
||||
|
||||
@ -150,42 +155,42 @@ public class DSAEngine {
|
||||
|
||||
private int[] H0 = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0};
|
||||
|
||||
private Hash calculateHash(byte[] source) {
|
||||
long length = source.length * 8;
|
||||
private Hash calculateHash(byte[] source, int offset, 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[offset + x] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[offset + x + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] |= source[offset + x + 2] << 24 >>> 24 << 8;
|
||||
M0[wordcount] |= source[offset + x + 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[offset + x] << 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[offset + x] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[offset + x + 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[offset + x] << 24 >>> 24 << 24;
|
||||
M0[wordcount] |= source[offset + x + 1] << 24 >>> 24 << 16;
|
||||
M0[wordcount] |= source[offset + x + 2] << 24 >>> 24 << 8;
|
||||
M0[wordcount] |= 0x00000080;
|
||||
break;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -86,6 +86,41 @@ public class Certificate extends DataStructureImpl {
|
||||
DataHelper.writeLong(out, 2, 0L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int writeBytes(byte target[], int offset) {
|
||||
int cur = offset;
|
||||
DataHelper.toLong(target, cur, 1, _type);
|
||||
cur++;
|
||||
if (_payload != null) {
|
||||
DataHelper.toLong(target, cur, 2, _payload.length);
|
||||
cur += 2;
|
||||
System.arraycopy(_payload, 0, target, cur, _payload.length);
|
||||
cur += _payload.length;
|
||||
} else {
|
||||
DataHelper.toLong(target, cur, 2, 0);
|
||||
cur += 2;
|
||||
}
|
||||
return cur - offset;
|
||||
}
|
||||
|
||||
public int readBytes(byte source[], int offset) {
|
||||
int cur = offset;
|
||||
_type = (int)DataHelper.fromLong(source, cur, 1);
|
||||
cur++;
|
||||
int length = (int)DataHelper.fromLong(source, cur, 2);
|
||||
cur += 2;
|
||||
if (length > 0) {
|
||||
_payload = new byte[length];
|
||||
System.arraycopy(source, cur, _payload, 0, length);
|
||||
cur += length;
|
||||
}
|
||||
return cur - offset;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 1 + 2 + (_payload != null ? _payload.length : 0);
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if ((object == null) || !(object instanceof Certificate)) return false;
|
||||
|
@ -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,70 @@ public class DataHelper {
|
||||
throw new DataFormatException("Invalid value (must be positive)", iae);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] toLong(int numBytes, long value) throws IllegalArgumentException {
|
||||
byte val[] = new byte[numBytes];
|
||||
toLong(val, 0, numBytes, value);
|
||||
return val;
|
||||
}
|
||||
|
||||
public static void toLong(byte target[], int offset, 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");
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
target[offset+numBytes-i-1] = (byte)(value >>> (i*8));
|
||||
}
|
||||
|
||||
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 +335,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 +350,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 +442,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 +545,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
|
||||
@ -574,11 +682,14 @@ public class DataHelper {
|
||||
|
||||
/** compress the data and return a new GZIP compressed array */
|
||||
public static byte[] compress(byte orig[]) {
|
||||
return compress(orig, 0, orig.length);
|
||||
}
|
||||
public static byte[] compress(byte orig[], int offset, int size) {
|
||||
if ((orig == null) || (orig.length <= 0)) return orig;
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(orig.length);
|
||||
GZIPOutputStream out = new GZIPOutputStream(baos, orig.length);
|
||||
out.write(orig);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
|
||||
GZIPOutputStream out = new GZIPOutputStream(baos, size);
|
||||
out.write(orig, offset, size);
|
||||
out.finish();
|
||||
out.flush();
|
||||
byte rv[] = baos.toByteArray();
|
||||
@ -594,9 +705,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 +724,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,41 @@ public class Destination extends DataStructureImpl {
|
||||
_signingKey.writeBytes(out);
|
||||
_certificate.writeBytes(out);
|
||||
}
|
||||
|
||||
public int writeBytes(byte target[], int offset) {
|
||||
int cur = offset;
|
||||
System.arraycopy(_publicKey.getData(), 0, target, cur, PublicKey.KEYSIZE_BYTES);
|
||||
cur += PublicKey.KEYSIZE_BYTES;
|
||||
System.arraycopy(_signingKey.getData(), 0, target, cur, SigningPublicKey.KEYSIZE_BYTES);
|
||||
cur += SigningPublicKey.KEYSIZE_BYTES;
|
||||
cur += _certificate.writeBytes(target, cur);
|
||||
return cur - offset;
|
||||
}
|
||||
|
||||
public int readBytes(byte source[], int offset) {
|
||||
int cur = offset;
|
||||
|
||||
_publicKey = new PublicKey();
|
||||
byte buf[] = new byte[PublicKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(source, cur, buf, 0, PublicKey.KEYSIZE_BYTES);
|
||||
_publicKey.setData(buf);
|
||||
cur += PublicKey.KEYSIZE_BYTES;
|
||||
|
||||
_signingKey = new SigningPublicKey();
|
||||
buf = new byte[SigningPublicKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(source, cur, buf, 0, SigningPublicKey.KEYSIZE_BYTES);
|
||||
cur += SigningPublicKey.KEYSIZE_BYTES;
|
||||
|
||||
_certificate = new Certificate();
|
||||
cur += _certificate.readBytes(buf, cur);
|
||||
|
||||
return cur - offset;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return PublicKey.KEYSIZE_BYTES + SigningPublicKey.KEYSIZE_BYTES + _certificate.size();
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if ((object == null) || !(object instanceof Destination)) return false;
|
||||
Destination dst = (Destination) object;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -2,6 +2,7 @@ package net.i2p.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
@ -18,10 +19,14 @@ public class SimpleTimer {
|
||||
private static final SimpleTimer _instance = new SimpleTimer();
|
||||
public static SimpleTimer getInstance() { return _instance; }
|
||||
private Log _log;
|
||||
/** event time (Long) to event (TimedEvent) mapping */
|
||||
private Map _events;
|
||||
/** event (TimedEvent) to event time (Long) mapping */
|
||||
private Map _eventTimes;
|
||||
|
||||
private SimpleTimer() {
|
||||
_events = new TreeMap();
|
||||
_eventTimes = new HashMap();
|
||||
I2PThread runner = new I2PThread(new SimpleTimerRunner());
|
||||
runner.setName("SimpleTimer");
|
||||
runner.setDaemon(true);
|
||||
@ -35,9 +40,13 @@ public class SimpleTimer {
|
||||
public void addEvent(TimedEvent event, long timeoutMs) {
|
||||
long eventTime = System.currentTimeMillis() + timeoutMs;
|
||||
synchronized (_events) {
|
||||
// remove the old scheduled position, then reinsert it
|
||||
if (_eventTimes.containsKey(event))
|
||||
_events.remove(_eventTimes.get(event));
|
||||
while (_events.containsKey(new Long(eventTime)))
|
||||
eventTime++;
|
||||
_events.put(new Long(eventTime), event);
|
||||
_eventTimes.put(event, new Long(eventTime));
|
||||
_events.notifyAll();
|
||||
}
|
||||
}
|
||||
@ -87,6 +96,8 @@ public class SimpleTimer {
|
||||
if (timesToRemove.size() > 0) {
|
||||
for (int i = 0; i < timesToRemove.size(); i++)
|
||||
_events.remove(timesToRemove.get(i));
|
||||
for (int i = 0; i < eventsToFire.size(); i++)
|
||||
_eventTimes.remove(eventsToFire.get(i));
|
||||
} else {
|
||||
if (nextEventDelay != -1)
|
||||
_events.wait(nextEventDelay);
|
||||
|
@ -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))) {
|
||||
|
231
history.txt
231
history.txt
@ -1,4 +1,233 @@
|
||||
$Id: history.txt,v 1.15 2004/09/08 17:15:43 hypercubus Exp $
|
||||
$Id: history.txt,v 1.53 2004/10/17 16:03:06 jrandom Exp $
|
||||
|
||||
* 2004-10-18 0.4.1.3 released
|
||||
|
||||
2004-10-18 jrandom
|
||||
* Allow sending messages with a section of a byte array.
|
||||
* Reduced stats published.
|
||||
|
||||
2004-10-17 jrandom
|
||||
* Don't b0rk on whitespace in the router address.
|
||||
|
||||
2004-10-16 jrandom
|
||||
* More aggressively reduce the capacity of peers if their tunnels are
|
||||
failing so that we move off them quicker.
|
||||
* Simplify some data structure serialization for reuse in the streaming
|
||||
lib, as well as add support for signing and verifying partial byte
|
||||
arrays.
|
||||
* Logging updates
|
||||
|
||||
2004-10-16 jrandom
|
||||
* Increased the default minimum tunnel test time to 5 seconds, since we
|
||||
still see the occational message processing time spike to 2 seconds.
|
||||
* Update the SimpleTimer to allow rescheduling a task thats already
|
||||
queued (useful for the new streaming lib).
|
||||
|
||||
2004-10-15 jrandom
|
||||
* Replaced old minimum tunnel test timeout of 1s with a configurable
|
||||
value (router.config property "router.tunnelTestMinimum", with the
|
||||
default of 2s).
|
||||
|
||||
2004-10-14 jrandom
|
||||
* Tunnel rejection is no longer a sign of an overwhelmingly loaded
|
||||
peer, so don't use it as a key point of the IsFailing calculator.
|
||||
We still use it as a key point of the Capacity calculator, however.
|
||||
|
||||
2004-10-14 jrandom
|
||||
* Allow for a configurable tunnel "growth factor", rather than trying
|
||||
to achieve a steady state. This will let us grow gradually when
|
||||
the router is needed more, rather than blindly accepting the request
|
||||
or arbitrarily choking it at an averaged value. Configure this with
|
||||
"router.tunnelGrowthFactor" in the router.config (default "1.5").
|
||||
* Adjust the tunnel test timeouts dynamically - rather than the old
|
||||
flat 30s (!!!) timeout, we set the timeout to 2x the average tunnel
|
||||
test time (the deviation factor can be adjusted by setting
|
||||
"router.tunnelTestDeviation" to "3.0" or whatever). This should help
|
||||
find the 'good' tunnels.
|
||||
* Added some crazy debugging to try and track down an intermittent hang.
|
||||
|
||||
2004-10-13 jrandom
|
||||
* Fix the probabalistic tunnel reject (we always accepted everything,
|
||||
since the docs on java.util.Random.nextDouble() are wrong..)
|
||||
* Fixed a race on startup (thanks Quadn!)
|
||||
|
||||
2004-10-12 jrandom
|
||||
* Disable the probabalistic drop by default (enable via the router config
|
||||
property "tcp.dropProbabalistically=true")
|
||||
* Disable the actual watchdog shutdown by default, but keep track of more
|
||||
variables and log a lot more when it occurs (enable via the router
|
||||
config property "watchdog.haltOnHang=true")
|
||||
* Implement some tunnel participation smoothing by refusing requests
|
||||
probabalistically as our participating tunnel count exceeds the previous
|
||||
hour's, or when the 10 minute average tunnel test time exceeds the 60
|
||||
minute average tunnel test time. The probabilities in both cases are
|
||||
oldAverage / #current, so if you're suddenly flooded with 200 tunnels
|
||||
and you had previously only participated in 50, you'll have a 25% chance
|
||||
of accepting a subsequent request.
|
||||
|
||||
* 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
|
||||
|
||||
|
48
hosts.txt
48
hosts.txt
@ -1,6 +1,26 @@
|
||||
; 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.64 2004/10/17 16:39:06 jrandom Exp $
|
||||
; changelog:
|
||||
; (1.87) updated curiosity.i2p (via signed email)
|
||||
; (1.86) added blueheron.i2p
|
||||
; (1.85) updated files.i2p (after verifying ident)
|
||||
; (1.84) added utansans.i2p
|
||||
; (1.83) added irc.orz.i2p
|
||||
; (1.82) added nano.i2p
|
||||
; (1.81) added ragnarok.i2p
|
||||
; (1.80) added marcos.i2p
|
||||
; (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
|
||||
@ -150,8 +170,32 @@ cvs.i2p=dIvSbo35u0bc-5Vp0Wqs4YvarZS6l-y-URwOgH~NrRfQJ6mQmnfcmBJ1XPWswSHEGeRchK8l
|
||||
linuxagent.i2p=OE-WAF6jzHUbUF7eytgiIaIKWh~oGf3c8~q-fUBbM2WntbXO7AhpU0QmZ~1lZIiQfzO-2Xyr0e-2VQBNexw73iOPLDII7mLv6xUnZmaKm-QPdvDEI9-ILPWgpMGJubAgA4ZmDgIUg2dSQ19Eq8lp5bwkuIUuU8Jd6JS1fvX-87G7PjcrE7vKM-Ty2gCnp7cWsadl8qYEkXLf5-CIr3LjGM-B-G~NoIqPf56df9ayHVguqT1f0c-d00qY80kUvb8DJ-X6VR9TNut6dKqRajI0earbkALP~wdoFggIIebqm1UXeI1tYROcrb155z4qu-4Nb~q4wzNAI9AVjNboIk50P2X0TrLNmjL9RWCrvHCt-r2ZV35Skpka4YmxATU59jSPw8jhXw1TgM-5DRswEtmOdxJMpkQU~iu~TJWmmcVvpkqyNMqXiqtOKqEgLTj8gOfNaITH0kdMVvXPKmYPTFimWu64T0VGBsqS~PQ50JxtteUP5FZv-dXluL8EbhtwQ7mLAAAA
|
||||
gott.i2p=BxciUZkGQwi6Sj1Ucg5GGagDdwujlj8ClePa4~3d-1nnRJsBhTNJtvs-UuQYY77gPGNlpNk9dt02mxeS7f~pEC4E1KxJH9mhnf0OlIGB4hOOhDlXokAaKE2u1E-vVCDJlZCq32r~Ne53w-L2m5h5FAq5Bx7NXrTzWAEPgAlC8A2wASJWIF-EKOX5kfkkYoF6sKZqam5CxAAAMAUwmnbD--7wo8d2mz0C-c~oE7hzuHsg2J8yME5Zd~-FOZUxkoNCBJdfrVlVRn9~6685zqpaotL-SIqFK6~28ZCNMNCtnZcZZLeG2gZxq2pe8HtgzDrMMSx45vs3JLUp8Bap6~D9oFX0o7k2DQm-5R9D5NWhsJgol5Ny~8ABTXBpW~WQQOuKxE5xJauXM5rQia2yyXgldfOyGjxYnkrTGu6LaxlLmhyAva3ZbOO0mtLvrKLZebLKCYUxP7~TtNmSWEAzPKFYbjdZ~NjE0q4TanLFBaWotefPmy3IuAc8Mr7PbCvi4GmdAAAA
|
||||
beyond.i2p=Gy9wxnDgcaNO8b-1gZTAn4GKWiMZHLSuOpXF9SSrVVO5Gx791OwZVNg9mMHvIkSekWuqtJwIRCArfXtaQNNe4ZJfl2bVNEKJonfXM9HLbNoJiSgmg-x75xYLXb04NDYhIbHJ4zSEpDFufjk1kI35XJo~32~qYynDMbYX9b3QtNfFfcBrOzH5iObTsMBBe5f2zEpjl1UWNGuKYa1tVHef65z6WCr16TUYSj5uDnUyTWWkwrgDZbTnRRlz--BQ9y4WiCgzQyMvRaNU-T6aPj6P9HlQIhV7efttpb2IRLpSKepIYG66ohBhI1n2G2dd18UHdR~PWNIy8x7AsCczlqnfh4lcJdiQqrNHQtpOI3XfM5gLM5sKLwrxbsQwB-6dnhonztTd1o9TWhTuA1FSlk3nRQ22E1~pQRh0sexgWjk1oa0Qr6kOojkY955aL6ZnD7RJx3fbeZ9JAy6s5uxYXuE1wkGQNUVEvi15jgVB8zk4GaB8ME6tdWVtcBTMjEqvulyEAAAA
|
||||
files.i2p=1rI0OWp83VhVRyMiZkPmw~mEo-CVu548n4uJLsHJW4eNzQfQ~k8SSFGCMc0-YmOW8zvB1AmO1~hTy9qrT4-5rkVxvy7XTwK9-Mvb8N9fKvxr89yBitQvBwhsRKNScMBcV-qsauGd1F~wV~eb0BFjfZG2pyB~-AYuqZrqmoEf48Q~aXn5IKnIXkb8RmKbJNAws3opW3Tvbb-cHMhth3noc9QEpCJzzPZ6~hjjh0FTcPFiFAgaRIL81YcSfMTG7eTg2X20~5j4Em4GY6n8zHw6S5hbBuSMp~udmz11Bvc3QMcbfPMYhMxGMaqWUN8yN3kJwjk8griosz0o6XE~NcUvVXKZELW7jNmURd5e2a-zkSwjlOzoRi3OQhdeGypbUM0c-0-2OxOMJM~yw0bRingvRHT02Xr11nhyZRbysSMxFfxMY5doNKvJk~H7XhCaXCn0LtP7pd9JU9NPKzxIqbP8W0dZFP8C217yRmAHTfxbMmuYaQZenEkWmUVqlTyO-4NBAAAA
|
||||
files.i2p=aEKZJq-9MfKzgKfxERC2Joj1ar-0c6dTrcLvwg4RVMI5uGCYfCSCRTtgFcwvEpVfTQ5RsGIxtPorEvbLjiY5TJJwtQj~ZWe3o2asm7Cwp-nmegXdAFyUSAKI33XUDvtVZjx2Erc~eGa39sIJrtJnfvapfRqmq1Xh9dcTMzEs9Aaz7cnMumTi6p5w-bBsQpQR3IBzsGkfmsUFaA4nwodz6ZhBs1Fqls7WrFLAlUz9hiKwtV-MrFy5RU5IH7elPkcN~5ReIDVBZ4axJZfMBOyszt3h6gmjyMiiaQ7keks8KDqFbQRZKUS8aRPCIzB90bzxbWZRO4gu0ApMeOd~tuIH71zYZ0UqdLOWo67iZhFz~njriskKH~1~lk--5Mk6487POUcY740ZC3FJl~6VXjf9Pv1n08Usf2Z3rK2i9QbwENsn9eH4T5bP5-JNDL8c3IZAHPo93W27gsNPAQkWrKC~Fvk9KK8jATpEBl2e5iZVUmwA07xLw~XJrFKQwaLS-KpPAAAA
|
||||
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=7tcdVioqcmDw4nHxleQBPS8-wO4IsYwmBQbYBeLWAXQsSenRUu8epki-wEMiDkHBf5-5RuOC26vy11f3taRZdxY8zbTWpgZW0L9ABS3vjTd0jkpPjuKhAWnQGr65W3YgKLxfoGO6jpPXOj8M1Bhb2aHSjHYRTpHorzzrU2KL3RDrJTrfkPh-3zNwYYHiZhcw0usSxoH4Kmn1AwjfJtKkhjRdw3e33QwZpvHyNzK6y5bvq1q5aTP0P-zm6xzKnOI0Kss6cm6Com92Oz3Rj~6wuZNCRvcUYelneMvgR~USjd~6-0R~Yrw~NkVW1fZYPFXX0u5IinGHMKvVzyiTclBYiAxFvkeiVcnkI5AJ4tV7I8sMnKPNW0o00zdjEgzVjdnFN4HXTtQTvHeFnfUmfxPusgtm3JaQ2WVo88-Sx9VA-JS6mcvG46v3QbXK4YHPdIgCYZ0Gq1Ds0CYblOks8hnKfObhnkpEgUYSsaUOAQXHlRLh8~D3MZibNamxCy31QotcAAAA
|
||||
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
|
||||
marcos.i2p=oN0aQlEygTHH1M2zLdkg1S8TcBaUIO4LQHC78R45ZImUCyOXVGzETk2AV6OD7LzLuzUOQSSfoHyVdctYMqq0buqdB6lzv1zKeNgofTHLvITEUJM5xemIz9vE91BIURjBpRVuonCGEQSBH~xqAsixv4OGtVyts5Nvle~vM~apZCBzEGEtWVikCyHSWL5MCBArbaEtYtCpUN-D2I628pb3JhbQppS3HCSa7b3tMFIIV-bqEjm1IIhvvcb5yyix78XKw~KAuE7KYvawXDOuJ0gtH6Hdox-UHMAWNP2~55oz-PPbchj3KvtL0yhI~6MJYKSpQEpoOsDpVDwmcnyU3V0NsEnab2Jjo0Cir7fmFIUjn9EWFjWk3yL5vd6qLxd2fjfO0Azqzb0uHp4wnP2sz25MPOpQMk-dNoX7DYI7LC9A3Ozu3yTisE62LVi8IRFB3p2O34DYN-flxR8ytn1B492x~0Ka80gd~HdiNo2rO4Qc04PILXe98NQj46kki8poho1DAAAA
|
||||
ragnarok.i2p=mkRjUNekHYH3tpLDlt-qMSS5-SPPjLpvaIuCYOrNRM0ehuH93H74WuldWrDqzr77hLS3~JGD7qKVjaz9YDTDhK3dGV6K6xuXomJbShnYIQ0b-S0SZrhLXC8KIcp~DLQAW6rmoiIsyr99nZ1RPyVCOI~futZ9UnmZRsWbMu3z3dZfh7wGLeoAQAmnXW3IMxE7c0NFul6ojLGZkbK5Wrh1~gRESfB3TSF6TurQMaoL2Rf~ehVWFg6jtpDJ1UruwUWzyMapVqbe8Rftg9bXq6UlrBq61xuseNw20L1B-S0Gif2sC6DnhLT3k4MLnjVpB6OySQsuMoA67cnuLm8CZ~v9tH5~YlqU-hRH3yd-AFiMY4PkepI-Gjh--tr4NSNGsAlqM2XOf4z5XsdqQeT4GhWqXHjzb1nZcKmfumb69vOhWX9DuyVOq~wfY-RIuxlU08K0wV4IqmewK3TCIjIWTzpcxFwsZAGKx2QxMF8QXsQz1qTDSlzvX6hrnf1NXYXBPDVhAAAA
|
||||
nano.i2p=oeXpaAMmVruU-7boMLZvnnLWvPnl-~WqLJKiJOigwiAs4c9umoCEo1gnN7IIr0XoloC4JmTZjsRfD-LE4kKKLKYMpw4hfGEQ74y~8fnf0Xe4gcG26l5O5RvKStZdK1pYzYioVfCgQk4a-RZfBQSd5l2mSrSHvpqzBmHrW9GZt56OymRELLHxfXn15AJXIRPdTtuiroXcKPMztZyvOsOWX47bkCcMfYTMJIrlYrlomh8uG4e45Kb8nX3uehy-kwPGFxMyJWMLs5ra7K~WzCzf6hbcdQ5vJVmYRj122WEjmtAl-gEKcK0XiLJMLF9y4aoIJGVHeA71a7mfKvSBEHjJ5BubC2IRoU5ZKxAkHtkOfoyDZ7ZxIB1r8~jAE2aPJzotQTN3l2gpcOFFcEapxXXWvFmIPjY0veorUGTjkXoGaLNl0-6JrH~w~5q2-bIt1mbWMySqX94YQmVTFYejArVS99NbdOIjb3VQoXKVXzjyu6Vr9BcfyYK9jMuqiztb-UfLAAAA
|
||||
irc.orz.i2p=0oLxoY4VcI~e~OnFdHtYp9aghBcBLBK46BE-yffvaxsnsNgmf5xiRDORVJ0xjg6e8LZ-gTUXr5EHiJnJa5GEv3sris0PWEXW0QLV2WbkIOI3XNR8sa1WMAJYFX9wYSHNdGDuHj0Igcd9rxwaBufdcHeJ0WLvp1FXCMxEf9OTh52wL3ku5pPGlXaVp22RhJXqaKqGeIFh0A9t-gSF5cPB7D3jvoXPJlZtPFLkrsVQeDCpFC9TLaI2sebJjuEHaBhCLvjA8usG8WiZ0m-TVNwkg0XV~yy-rpOEGq-8CCLa1-7c6mc0gMmeolEFz9L9x6hXzw4TR0MXNMeu8nqeMhbvqws39iLiz1L2r6amzQrXjHReX1ibrEprNfLY~Ne1cgqQ5VsHpCr-UJv3D1QoFCJUwG7z0dJrgoi37aPRRjzUF-z67hi3z-ghKrY7d3m0YpTHUCwZ5o2uwUFM7xEvCXY4nQ8ndwEI0xJKfbBgWEmR8OxV3jbn9ZhSYSoygsbUQg55AAAA
|
||||
utansans.i2p=87krkpFeYipyBHntsD2t-2A~pMW2jJG~3n2ZsvyOFeajYMAfr0s1G1EMxu~ZfywgFmWNir5pLlaXmAgd-IerlUnRF0FJrqqDlZVllYnAp-IZbGqg3PygDhSgYkuTh67l5wQEQTqwPMoz04F9O4w2GfzU-316xp634yWIYiFzeadHlnMVj-dsgM~namEo5dGmMWBpzk9iFkseTOtPJPC8e~TFrOhCPpPIbRPk6YkaVGJ0IyQ89bUmrRCH8ZiJuziY5i8S6YmGCuUIi5q9dLyu9~c5ucRQn13Ja9abWDXKgPF4MrErT4P5ATL-iQ~a00YF-YSXbSB~~0g3288QQwAN83oOKwSobL3vMXfmWyB7oA8zrjT8a4R4~tN3KXqbPTvkc-fZ-XDSaR57NssXLrz1DvJwhlQc2wcPAepFLX9c1IwgfF5coBwtZaq16gamvprRH9GCu4iWbjqhnQnaTiB~P1VqXRPGv5xI0JgcIgW0Q1H8vB9y2IQ~dW1gbGIiYdo9AAAA
|
||||
blueheron.i2p=ZQkG-vHKcOcfg314mNZ9iNTP9Zl8W9H2gZzEPx9VesuIkeYRFQD1JbPvxWq5DBUfOzRb36c5pJeFuWWh35SViwmoJ~npcrqMWnfTtCq~JBYKCVYhpDZ-oo1Vg63GRwZ0hwaMv~l5jPWISdg~a5as-Cg69od~s86pdx9ci2GqSgINcyRMeBkWG2NEAUZSyhiMjSgW9lMVwA-5aXIiGlOaiKv4ldYZxwS9hpO0NLgWIIrQ7o2Nr5OL-Kh~FrShgSQlMSd0QwMFS0~QGKmcL7AmyIme3szLA9oN1bnKJ8ztRlTx3dzCI7nH9WXKmLWqvQck0PdRIT581rYw7qfU6uwN6UduS8enWnSXj5q47T6KzfWYBQu7AXzaatQGdMB6ct51Urfl56bRLT6Bst09Z2mvyjELlgQjGrVNoQlmRJ-e~y2kUmc-OYl0j~3g~EEiXnxmYXO3M6h54d60QcJgY7ccrWmnq7ayi~fBXXshHtZD~6w-cgQ4S5gBnpaEVG1Nt9xuAAAA
|
||||
|
||||
|
@ -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 {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user