Compare commits

..

76 Commits

Author SHA1 Message Date
jrandom
503b289240 * 2004-10-10 0.4.1.2 released 2004-10-10 19:33:08 +00:00
jrandom
35e3bbb862 2004-10-10 cervantes
* Update the I2PTunnel HTTP proxy to strip out the i2paddresshelper from
      the request.
2004-10-10 14:57:15 +00:00
jrandom
8dc261da79 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-10 00:03:25 +00:00
jrandom
65676f8988 2004-10-08 jrandom
* Revamp the AESInputStream so it doesn't allocate any temporary objects
      during its operation.
2004-10-08 22:53:03 +00:00
jrandom
730da3aa27 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-08 18:38:48 +00:00
jrandom
ff8674bca9 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-08 02:08:10 +00:00
jrandom
c7cfef3b61 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-07 19:19:51 +00:00
jrandom
32188b1cc0 expose some direct byte formatting methods
allow SHA256 to be run against a partial array
append to the stats.log instead of overwriting it
2004-10-07 16:48:46 +00:00
jrandom
37479d8c0d logging 2004-10-07 16:45:11 +00:00
jrandom
f5c7d6576d no need to double b0rk 2004-10-07 16:42:55 +00:00
jrandom
38c422bbc0 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 21:03:51 +00:00
jrandom
39d4e5ea81 list the shutdown time w/ the clock fudge factor included 2004-10-06 16:47:36 +00:00
jrandom
4191ad1cbf 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-06 13:23:38 +00:00
jrandom
29287da37c 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-06 01:12:03 +00:00
jrandom
98c780415b 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 19:21:47 +00:00
jrandom
756af9c699 oops 2004-10-05 18:21:44 +00:00
jrandom
7f9076bb1d updated beyond.i2p (after verification) 2004-10-05 16:04:16 +00:00
jrandom
2404f1ab9a added b.i2p 2004-10-05 15:57:08 +00:00
jrandom
64bcfd09ec 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-05 15:38:37 +00:00
jrandom
6251d22c6e added tinyurl.i2p 2004-10-05 15:26:20 +00:00
jrandom
de1b4937a1 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-04 17:30:22 +00:00
jrandom
d092dd79ba get rid of the really really frequent temporary object creation 2004-10-04 13:53:10 +00:00
jrandom
a3ba968386 24h time 2004-10-04 01:17:01 +00:00
jrandom
5ca2b97128 24h time 2004-10-04 01:00:38 +00:00
jrandom
c9daad1cfd added detonate.i2p 2004-10-04 00:16:13 +00:00
jrandom
0526d5b53a cli to splot the stat log 2004-10-03 23:53:16 +00:00
jrandom
34163fb8e4 dont overwrite index.html anymore (0.4.1.2 wont) 2004-10-03 21:06:17 +00:00
jrandom
98d2d661a8 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-03 20:48:43 +00:00
jrandom
d9f0a0fd74 dont list an explicit webdefault.xml (use the default) 2004-10-03 14:04:21 +00:00
jrandom
d20d043e0f 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 19:05:24 +00:00
jrandom
ce186e1872 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-02 12:31:15 +00:00
jrandom
a14da92e1d * 2004-10-01 0.4.1.1 released 2004-10-01 17:23:00 +00:00
jrandom
2b54d850ea logging 2004-10-01 17:19:37 +00:00
jrandom
a63c1b19fc 2004-10-01 jrandom
* Handle partial reseeds, caused by seeds going away before the download
      completes (thanks Sugadude!)
2004-10-01 14:35:49 +00:00
jrandom
34f74cd6ef 2004-10-01 jrandom
* Explicitly refuse IPv6 addresses, since only some peers support
      them and we want fully reachable peers.
2004-10-01 11:49:02 +00:00
jrandom
c0b8e62135 2004-10-01 jrandom
* Additional error handling for a variety of transport layer errors.
2004-10-01 09:39:14 +00:00
jrandom
ea24166b8e added identiguy.i2p 2004-10-01 09:32:46 +00:00
jrandom
178b229d66 *cough* (oops) 2004-09-30 16:44:46 +00:00
jrandom
276493da65 * 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-30 15:58:54 +00:00
jrandom
e85dadfef2 added jabber-2.i2p 2004-09-30 13:25:31 +00:00
jrandom
1c70efb350 added eepsite info 2004-09-30 13:23:01 +00:00
jrandom
6804a0c564 * always flush the console output (duh)
* deal with some degenerate situations with identities changing and auto IP detection
* some catch-alls for cleaning up the registry on degenerate tunnels
* lots of logging
2004-09-30 13:10:02 +00:00
jrandom
6eb7ecc2d4 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.
plus minor bugfixes / refactoring / logging
2004-09-30 06:57:22 +00:00
jrandom
f4956b06b6 be more careful on startup 2004-09-30 06:51:28 +00:00
jrandom
9a2f7c2660 include the timeouts due to inability to find the leaseSet 2004-09-30 00:51:35 +00:00
jrandom
b6017c558a * updated stats:
- sendsPerFailure: how many partial sends we make when they all fail
- timeoutCongestionInbound: describes how much faster than our average speed we were receiving data when each partial send timed out (in Bps)
- timeoutCongestionMessage: our send processing time when each partial send timed out (in ms)
- timeoutCongestionTunnel: our tunnel test time when each partial send timed out (in ms)
- participatingMessagesProcessedActive: # of messages more than the (most recent) average that a tunnel we were participating in transmitted (for tunnels with more than the average)
* updated to use Writer for rendering the console, so we can do partial writes (and hopefully help debug some kooky threading bugs on kaffe)
2004-09-29 22:54:38 +00:00
jrandom
62ed6c6a58 * updated stats:
- sendsPerFailure: how many partial sends we make when they all fail
- timeoutCongestionInbound: describes how much faster than our average speed we were receiving data when each partial send timed out (in Bps)
- timeoutCongestionMessage: our send processing time when each partial send timed out (in ms)
- timeoutCongestionTunnel: our tunnel test time when each partial send timed out (in ms)
- participatingMessagesProcessedActive: # of messages more than the (most recent) average that a tunnel we were participating in transmitted (for tunnels with more than the average)
* updated to use Writer for rendering the console, so we can do partial writes (and hopefully help debug some kooky threading bugs on kaffe)
2004-09-29 22:49:19 +00:00
jrandom
24966c812f javad0c 2004-09-29 20:12:26 +00:00
jrandom
ea8dc2e0af *nix daemon scripts are gone 2004-09-29 19:38:15 +00:00
jrandom
010b285e67 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)
in addition, refactor various file ops out of the DataHelper into FileUtil
2004-09-29 19:34:02 +00:00
jrandom
774231f347 * started reducing the temporary buffers created within various crypto methods , as we've
got some pretty heavy GC churn when under load.  rough estimate is we allocate 5-8x as
much data as we need, copying it all over the place before forwarding it (or processing it).
this should cut down a few of those copies, but not enough yet.  it'd be great to get that
down to 2x.
* lots of logging
2004-09-28 20:33:23 +00:00
jrandom
ff1dfd8f25 let the algorithm handle writing the output to various places in the output array (so we can cut down on temporary memory allocation) 2004-09-28 16:38:24 +00:00
jrandom
2741ac195d * protocol doc & impl cleanup
* more defensive programming
* more javadoc updates
2004-09-28 08:34:48 +00:00
jrandom
cf780e296e bugfixes for autodetection/update of IP address 2004-09-27 18:05:28 +00:00
jrandom
0361246db0 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-27 07:57:43 +00:00
jrandom
63355ecd5b more tcp transport updates (getting closer to the old functionality)
* avoid bad peers
* shitlist appropriately
* include the bandwidth limiter
* add socket timeouts
* deal with *cough* closing connections
* javadocs
2004-09-26 18:11:39 +00:00
jrandom
0f54ba59fb die phttp die 2004-09-26 15:32:24 +00:00
jrandom
b67b243ebd the following isn't the end of the 0.4.1 updates, as there are still more things left to clean
up and debug in the new tcp transport, but it all works, and i dont like having big changes
sitting on my local machine (and there's no real need for branching atm)
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-26 15:16:44 +00:00
jrandom
4c29c20613 javadoc fix 2004-09-26 14:50:49 +00:00
mpc
4c2619d948 minor changes 2004-09-24 21:08:00 +00:00
jrandom
ea5662a4a2 another minor semantic jikes warning 2004-09-23 01:21:33 +00:00
jrandom
7c1ce777a1 cleanup per jikes' whining (overloaded var names, val overflow, etc) 2004-09-23 01:13:22 +00:00
jrandom
3bb85f2d61 add some logical exit values (useful for scripting).thanks xolo! 2004-09-23 01:05:40 +00:00
jrandom
93e36b3113 added jake.i2p 2004-09-23 00:08:51 +00:00
jrandom
932fb670e3 added anonymnet.i2p sasquotch.i2p orz.i2p microbleu.i2p www/smtp/pop3.postman.i2p 2004-09-22 23:58:37 +00:00
jrandom
54dce61a95 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-22 00:10:26 +00:00
jrandom
e686c0e0a2 added curiosity.i2p 2004-09-17 19:47:58 +00:00
jrandom
05acf32f39 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-16 23:55:12 +00:00
mpc
67064012c9 added freeciv.nightblade.i2p 2004-09-16 20:50:26 +00:00
jrandom
10e93c3b1b rename (wtf was i thinking "Calculator"...) 2004-09-16 02:04:40 +00:00
jrandom
5b2ec1cbb5 moved udp transport to 0.4.4 instead of 1.1 2004-09-14 19:52:46 +00:00
jrandom
972f701c5c ganttproject.sf.net based plan 2004-09-14 02:19:33 +00:00
jrandom
51285efbc3 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-13 03:08:16 +00:00
jrandom
e2635705f9 added xolotl.i2p 2004-09-11 01:25:24 +00:00
jrandom
7762107543 added modulus.i2p 2004-09-10 04:11:15 +00:00
jrandom
9123ad89c8 added links to www.i2p and dev.i2p (thanks pseudonym) 2004-09-09 04:10:25 +00:00
162 changed files with 7248 additions and 4452 deletions

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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 />");
}
}
}

View File

@@ -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)
*
*/

View File

@@ -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" />

View File

@@ -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) {

View File

@@ -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"));
}

View File

@@ -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)");

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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());
}
}

View File

@@ -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 "";
}
}
}

View File

@@ -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>";
}

View File

@@ -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();
}

View File

@@ -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 {

View File

@@ -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";
}
}

View File

@@ -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 />

View File

@@ -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 />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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" />

View File

@@ -14,8 +14,8 @@ package net.i2p;
*
*/
public class CoreVersion {
public final static String ID = "$Revision: 1.19 $ $Date: 2004/09/03 14:46:07 $";
public final static String VERSION = "0.4.0.1";
public final static String ID = "$Revision: 1.22 $ $Date: 2004/10/01 12:23:00 $";
public final static String VERSION = "0.4.1.2";
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);

View File

@@ -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;
}

View File

@@ -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) {}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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));
}
}

View File

@@ -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) {}
}

View File

@@ -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;
}
}
}

View File

@@ -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");
}
}

View File

@@ -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");

View File

@@ -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");

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -12,27 +12,23 @@ package net.i2p.data;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.TreeMap;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import net.i2p.util.OrderedProperties;
@@ -99,24 +95,28 @@ public class DataHelper {
*/
public static void writeProperties(OutputStream rawStream, Properties props)
throws DataFormatException, IOException {
OrderedProperties p = new OrderedProperties();
if (props != null) p.putAll(props);
ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
for (Iterator iter = p.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
String val = p.getProperty(key);
// now make sure they're in UTF-8
//key = new String(key.getBytes(), "UTF-8");
//val = new String(val.getBytes(), "UTF-8");
writeString(baos, key);
baos.write(_equalBytes);
writeString(baos, val);
baos.write(_semicolonBytes);
if (props != null) {
OrderedProperties p = new OrderedProperties();
p.putAll(props);
ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
for (Iterator iter = p.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
String val = p.getProperty(key);
// now make sure they're in UTF-8
//key = new String(key.getBytes(), "UTF-8");
//val = new String(val.getBytes(), "UTF-8");
writeString(baos, key);
baos.write(_equalBytes);
writeString(baos, val);
baos.write(_semicolonBytes);
}
baos.close();
byte propBytes[] = baos.toByteArray();
writeLong(rawStream, 2, propBytes.length);
rawStream.write(propBytes);
} else {
writeLong(rawStream, 2, 0);
}
baos.close();
byte propBytes[] = baos.toByteArray();
writeLong(rawStream, 2, propBytes.length);
rawStream.write(propBytes);
}
/**
@@ -261,7 +261,66 @@ public class DataHelper {
throw new DataFormatException("Invalid value (must be positive)", iae);
}
}
public static byte[] toLong(int numBytes, long value) throws IllegalArgumentException {
if (numBytes <= 0) throw new IllegalArgumentException("Invalid number of bytes");
if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
byte val[] = new byte[numBytes];
for (int i = 0; i < numBytes; i++)
val[numBytes-i-1] = (byte)(value >>> (i*8));
return val;
}
public static long fromLong(byte src[], int offset, int numBytes) {
if ( (src == null) || (src.length == 0) )
return 0;
long rv = 0;
for (int i = 0; i < numBytes; i++) {
long cur = src[offset+i] & 0xFF;
if (cur < 0) cur = cur+256;
cur = (cur << (8*(numBytes-i-1)));
rv += cur;
}
if (rv < 0)
throw new IllegalArgumentException("wtf, fromLong got a negative? " + rv + ": offset="+ offset +" numBytes="+numBytes);
return rv;
}
public static void main(String args[]) {
for (int i = 0; i <= 0xFF; i++)
testLong(1, i);
System.out.println("Test 1byte passed");
for (long i = 0; i <= 0xFFFF; i++)
testLong(2, i);
System.out.println("Test 2byte passed");
for (long i = 0; i <= 0xFFFFFF; i++)
testLong(3, i);
System.out.println("Test 3byte passed");
for (long i = 0; i <= 0xFFFFFFFF; i++)
testLong(4, i);
System.out.println("Test 4byte passed");
for (long i = 0; i <= 0xFFFFFFFF; i++)
testLong(8, i);
System.out.println("Test 8byte passed");
}
private static void testLong(int numBytes, long value) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(numBytes);
writeLong(baos, numBytes, value);
byte written[] = baos.toByteArray();
byte extract[] = toLong(numBytes, value);
if (!eq(written, extract))
throw new RuntimeException("testLong("+numBytes+","+value+") FAILED");
long read = fromLong(extract, 0, extract.length);
if (read != value)
throw new RuntimeException("testLong("+numBytes+","+value+") FAILED on read (" + read + ")");
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/** Read in a date from the stream as specified by the I2P data structure spec.
* A date is an 8 byte unsigned integer in network byte order specifying the number of
* milliseconds since midnight on January 1, 1970 in the GMT timezone. If the number is
@@ -272,7 +331,7 @@ public class DataHelper {
* @return date read, or null
*/
public static Date readDate(InputStream in) throws DataFormatException, IOException {
long date = readLong(in, 8);
long date = readLong(in, DATE_LENGTH);
if (date == 0L) return null;
return new Date(date);
@@ -287,10 +346,25 @@ public class DataHelper {
public static void writeDate(OutputStream out, Date date)
throws DataFormatException, IOException {
if (date == null)
writeLong(out, 8, 0L);
writeLong(out, DATE_LENGTH, 0L);
else
writeLong(out, 8, date.getTime());
writeLong(out, DATE_LENGTH, date.getTime());
}
public static byte[] toDate(Date date) throws IllegalArgumentException {
if (date == null)
return toLong(DATE_LENGTH, 0L);
else
return toLong(DATE_LENGTH, date.getTime());
}
public static Date fromDate(byte src[], int offset) throws IllegalArgumentException {
long when = fromLong(src, offset, DATE_LENGTH);
if (when <= 0)
return null;
else
return new Date(when);
}
public static final int DATE_LENGTH = 8;
/** Read in a string from the stream as specified by the I2P data structure spec.
* A string is 1 or more bytes where the first byte is the number of bytes (not characters!)
@@ -364,12 +438,16 @@ public class DataHelper {
public static void writeBoolean(OutputStream out, Boolean bool)
throws DataFormatException, IOException {
if (bool == null)
writeLong(out, 1, 2);
writeLong(out, 1, BOOLEAN_UNKNOWN);
else if (Boolean.TRUE.equals(bool))
writeLong(out, 1, 1);
writeLong(out, 1, BOOLEAN_TRUE);
else
writeLong(out, 1, 0);
writeLong(out, 1, BOOLEAN_FALSE);
}
public static final byte BOOLEAN_TRUE = 0x1;
public static final byte BOOLEAN_FALSE = 0x0;
public static final byte BOOLEAN_UNKNOWN = 0x2;
//
// The following comparator helpers make it simpler to write consistently comparing
@@ -463,12 +541,38 @@ public class DataHelper {
public final static byte[] xor(byte lhs[], byte rhs[]) {
if ((lhs == null) || (rhs == null) || (lhs.length != rhs.length)) return null;
byte rv[] = new byte[lhs.length];
byte diff[] = new byte[lhs.length];
for (int i = 0; i < lhs.length; i++)
diff[i] = (byte) (lhs[i] ^ rhs[i]);
xor(lhs, 0, rhs, 0, diff, 0, lhs.length);
return diff;
}
/**
* xor the lhs with the rhs, storing the result in out.
*
* @param lhs one of the source arrays
* @param startLeft starting index in the lhs array to begin the xor
* @param rhs the other source array
* @param startRight starting index in the rhs array to begin the xor
* @param out output array
* @param startOut starting index in the out array to store the result
* @param len how many bytes into the various arrays to xor
*/
public final static void xor(byte lhs[], int startLeft, byte rhs[], int startRight, byte out[], int startOut, int len) {
if ( (lhs == null) || (rhs == null) || (out == null) )
throw new NullPointerException("Invalid params to xor (" + lhs + ", " + rhs + ", " + out + ")");
if (lhs.length < startLeft + len)
throw new IllegalArgumentException("Left hand side is too short");
if (rhs.length < startRight + len)
throw new IllegalArgumentException("Right hand side is too short");
if (out.length < startOut + len)
throw new IllegalArgumentException("Result is too short");
for (int i = 0; i < len; i++)
out[startOut + i] = (byte) (lhs[startLeft + i] ^ rhs[startRight + i]);
}
//
// The following hashcode helpers make it simpler to write consistently hashing
// functions for objects based on their value, not JVM memory address
@@ -594,9 +698,12 @@ public class DataHelper {
/** decompress the GZIP compressed data (returning null on error) */
public static byte[] decompress(byte orig[]) throws IOException {
return decompress(orig, 0, orig.length);
}
public static byte[] decompress(byte orig[], int offset, int length) throws IOException {
if ((orig == null) || (orig.length <= 0)) return orig;
GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(orig), orig.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream(orig.length * 2);
GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(orig, offset, length), length);
ByteArrayOutputStream baos = new ByteArrayOutputStream(length * 2);
byte buf[] = new byte[4 * 1024];
while (true) {
int read = in.read(buf);
@@ -610,91 +717,4 @@ public class DataHelper {
return rv;
}
/**
* Read in the last few lines of a (newline delimited) textfile, or null if
* the file doesn't exist.
*
*/
public static String readTextFile(String filename, int maxNumLines) {
File f = new File(filename);
if (!f.exists()) return null;
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
List lines = new ArrayList(maxNumLines);
String line = null;
while ( (line = in.readLine()) != null) {
lines.add(line);
while (lines.size() > maxNumLines)
lines.remove(0);
}
StringBuffer buf = new StringBuffer(lines.size() * 80);
for (int i = 0; i < lines.size(); i++)
buf.append((String)lines.get(i)).append('\n');
return buf.toString();
} catch (IOException ioe) {
return null;
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
}
}
public static boolean extractZip(File zipfile, File targetDir) {
try {
byte buf[] = new byte[16*1024];
ZipFile zip = new ZipFile(zipfile);
Enumeration entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry)entries.nextElement();
if (entry.getName().indexOf("..") != -1) {
System.err.println("ERROR: Refusing to extract a zip entry with '..' in it [" + entry.getName() + "]");
return false;
}
File target = new File(targetDir, entry.getName());
File parent = target.getParentFile();
if ( (parent != null) && (!parent.exists()) ) {
boolean parentsOk = parent.mkdirs();
if (!parentsOk) {
System.err.println("ERROR: Unable to create the parent dir for " + entry.getName() + ": [" + parent.getAbsolutePath() + "]");
return false;
}
}
if (entry.isDirectory()) {
if (!target.exists()) {
boolean created = target.mkdirs();
if (!created) {
System.err.println("ERROR: Unable to create the directory [" + entry.getName() + "]");
return false;
} else {
System.err.println("INFO: Creating directory [" + entry.getName() + "]");
}
}
} else {
try {
InputStream in = zip.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(target);
int read = 0;
while ( (read = in.read(buf)) != -1) {
fos.write(buf, 0, read);
}
fos.close();
in.close();
System.err.println("INFO: File [" + entry.getName() + "] extracted");
} catch (IOException ioe) {
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + "]");
ioe.printStackTrace();
return false;
}
}
}
zip.close();
return true;
} catch (IOException ioe) {
System.err.println("ERROR: Unable to extract the zip file");
ioe.printStackTrace();
return false;
}
}
}

View File

@@ -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

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View 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();
}
}
}

View File

@@ -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);
}

View 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);
}

View 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) {}
}
}
}

View File

@@ -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) */

View File

@@ -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;
}
}

View File

@@ -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) {}

View 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");
}
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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))) {

View File

@@ -1,4 +1,168 @@
$Id: history.txt,v 1.15 2004/09/08 17:15:43 hypercubus Exp $
$Id: history.txt,v 1.43 2004/10/10 09:57:15 jrandom Exp $
* 2004-10-10 0.4.1.2 released
2004-10-10 cervantes
* Update the I2PTunnel HTTP proxy to strip out the i2paddresshelper from
the request.
2004-10-09 jrandom
* Added a watchdog timer to do some baseline liveliness checking to help
debug some odd errors.
* Added a pair of summary stats for bandwidth usage, allowing easy export
with the other stats ("bw.sendBps" and "bw.receiveBps")
* Trimmed another memory allocation on message reception.
2004-10-08 jrandom
* Revamp the AESInputStream so it doesn't allocate any temporary objects
during its operation.
2004-10-08 jrandom
* Don't kill the establisher threads during a soft restart.
* Attempt to validate the peer's routerInfo earlier during handshaking.
* Revamp the AESOutputStream so it doesn't allocate any temporary objects
during its operation.
2004-10-07 jrandom
* Reimplement the I2NP reading with less temporary memory allocation.
There is still significant GC churn, especially under load, but this
should help.
* Catch some oddball errors in the transport (message timeout while
establishing).
2004-10-07 jrandom
* Expire queued messages even when the writer is blocked.
* Reimplement most of the I2NP writing with less temporary memory
allocations (I2NP reading still gobbles memory).
2004-10-06 jrandom
* Implement an active queue management scheme on the TCP transports,
dropping messages probabalistically as the queue fills up. The
estimated queue capacity is determined by the rate at which messages
have been sent to the peer (averaged at 1, 5, and 60m periods). As
we exceed 1/2 of the estimated capacity, we drop messages throughout
the queue probabalistically with regards to their size. This is based
on RFC 2309's RED, with the minimum threshold set to 1/2 the
estimated connection capacity. We may want to consider using a send
rate and queue size measured across all connections, to deal with our
own local bandwidth saturation, but we'll try the per-con metrics first.
2004-10-06 jrandom
* Enable explicit disabling of the systray entirely for windows machines
with strange configurations: add -Dsystray.disable=true to the java
command line. (thanks mihi!)
2004-10-05 jrandom
* Allow peers on the same LAN to communicate with each other safely even
when they cannot talk to each other through the external address.
2004-10-05 jrandom
* Display how much time is left before the graceful shutdown is complete.
* Debug some improperly failed messages on timeout or disconnection.
2004-10-05 jrandom
* Don't go into a fast busy if an I2PTunnel 'server' is explicitly killed
(thanks mule!)
* Handle some more error conditions regarding abruptly closing sockets
(thanks Jonva!)
2004-10-04 jrandom
* Update the shitlist to reject a peer for an exponentially increasing
period of time (with an upper bounds of an hour).
* Various minor stat and debugging fixes
2004-10-03 jrandom
* Add a new stat logging component to optionally dump the raw stats to
disk as they are generated, rather than rely upon the summarized data.
By default, this is off, but the router property "stat.logFilters" can
be set to a comma delimited list of stats (e.g. "client.sendAckTime")
which will be written to the file "stats.log" (or whatever the property
"stat.logFile" is set to). This can also log profile related stats,
such as "dbResponseTime" or "tunnelTestResponseTime".
2004-10-02 jrandom
* Assure that we quickly fail messages bound for shitlisted peers.
* Address a race on startup where the first peer contacted could hang the
router (thanks Romster!)
* Only whine about an intermittent inability to query the time server once
2004-10-02 jrandom
* Command line utility to verify a peer's reachability - simply run
net.i2p.router.transport.tcp.ConnectionHandler hostname port# and it
will print out whether that peer is reachable or not (using a simple
verification handshake).
* 2004-10-01 0.4.1.1 released
2004-10-01 jrandom
* Handle partial reseeds, caused by seeds going away before the download
completes (thanks Sugadude!)
2004-10-01 jrandom
* Explicitly refuse IPv6 addresses, since only some peers support
them and we want fully reachable peers.
2004-10-01 jrandom
* Additional error handling for a variety of transport layer errors.
* 2004-09-30 0.4.1 released (not backwards compatible)
2004-09-30 jrandom
* Bundle the configuration necessary to run an eepsite out of the box
with Jetty - simply edit ./eepsite/docroot/index.html and give people
the key listed on the I2PTunnel configuration page, and its up.
* Router console cleanup, and some (off by default) tunnels -
smtp.postman.i2p (port 7659), pop.postman.i2p (port 7660), and
irc.baffled.i2p (port 7661)
2004-09-29 jrandom
* Always wipe the Jetty work directory on startup, so that web updates
are reflected immediately (Jetty does not honor the cache across
multiple executions)
2004-09-27 jrandom
* Limit the number of connection tags saved to 10,000. This is a huge
limit, but consumes no more than 1MB of RAM. For now, we drop them
randomly after reaching that size, forcing those dropped peers to use
a full DH negotiation.
* HTML cleanup in the console.
2004-09-26 jrandom
* Complete rewrite of the TCP transport with IP autodetection and
low CPU overhead reconnections. More concise connectivity errors
are listed on the /oldconsole.jsp as well. The IP autodetection works
by listening to the first person who tells you what your IP address is
when you have not defined one yourself and you have no other TCP
connections.
* Update to the I2NP message format to add transparent verification at
the I2NP level (beyond standard TCP verification).
* Remove a potential weakness in our AESEngine's safeEncrypt and safeDecrypt
implementation (rather than verifying with E(H(key)), we now verify with
E(H(iv))).
* The above changes are NOT BACKWARDS COMPATIBLE.
* Removed all of the old unused PHTTP code.
* Refactor various methods and clean up some javadoc.
2004-09-21 jrandom
* Have two tiers of hosts.txt files - the standard "hosts.txt" and
the new "userhosts.txt". Updates to I2P will only overwrite the former,
but values stored in the later take precedence. Both are queried on
lookup.
2004-09-16 jrandom
* Refactor the TCP transport to deal with changing identities gracefully,
and to prevent some wasted effort by keeping track of what host+port
combinations we are connected to (rather than just the identities). Also
catch a few configuration errors earlier.
* Removed no longer relevent methods from the Transport API that were
exposing ideas that probably shouldn't be exposed.
* Removed the 0.4.0.1 specific files from i2pupdate.zip (relating to script
updates)
2004-09-13 jrandom
* Update for the SDK reconnection to deal with overflow.
* Web improvements (@ not # on the /logs.jsp [thanks ugha!] and fixed the
rounding on lifetime bandwidth used [thanks gott!]).
* 2004-09-08 0.4.0.1 released

View File

@@ -1,6 +1,18 @@
; TC's hosts.txt guaranteed freshness
; $Id: hosts.txt,v 1.42 2004/09/08 02:46:21 jrandom Exp $
; $Id: hosts.txt,v 1.56 2004/10/05 10:57:08 jrandom Exp $
; changelog:
; (1.79) updated beyond.i2p's key
; (1.78) added b.i2p
; (1.77) added tinyurl.i2p
; (1.76) added detonate.i2p
; (1.75) added identiguy.i2p
; (1.74) added jabber-2.i2p
; (1.73) added jake.i2p
; (1.72) added anonymnet.i2p sasquotch.i2p orz.i2p microbleu.i2p {www,smtp,pop3}.postman.i2p
; (1.71) added curiosity.i2p
; (1.70) added freeciv.nightblade.i2p
; (1.69) added xolotl.i2p
; (1.68) added modulus.i2p
; (1.67) added eepdot.i2p
; (1.66) removed datagram_test.i2p
; (1.65) added socks1.tor.i2p
@@ -154,4 +166,22 @@ files.i2p=1rI0OWp83VhVRyMiZkPmw~mEo-CVu548n4uJLsHJW4eNzQfQ~k8SSFGCMc0-YmOW8zvB1A
sugadude.i2p=PIV8bZaIH4wRqzlzVLX1mDkELhLFdyLlKxcd2nUrJvd0YeTByls6LGFZ7wr0-9MT7cb3Ee23U1BApgm0~jT5bzFGIQOvx7AT8o0uMy~fcP1lhzo4lNwD5bHnf9OXe59FzORC3s79bwFmTtMCrEoYvQXCGherxwFfXywRPrJ2x0AjfjungiwX3vrndMdol1SDWTLdxTSARLPgLmswz47gGm4dOipjHBSGOm5bdgZBD6di8YGxHrB072QfXxBVSGzTgtQNnK4qAsZv1YbETk2CQ1nOKpCj0Zjkcnc1trTFOpUQKeOp6kiGCriAn8Ezbu1yuf2fiDAmPenFf8bDR7fNFR7kMDcKsbiht7fFi0wjPdE4Lx5H2PFyTuiw3~-osNsXFLtjvaeIV4P99vZRof1avADgp5k4pC8fEPKWfwXGPPFJjYEbWPE4VxmxcP93Iq-CMZfSd8fPeZNeBz8qL~n9IXJoXjO0G3nouQ7d1ZF4okVRO8FmZ91Umpy79v2I4sYFAAAA
socks1.tor.i2p=sl3oda7CJe3TN1JVoALIuoRAe--qYgDwo0A8PrUGaaWQ2xXiWYaTV7~FQOmv13JRCtbO-8rhOfGWnV-qia4CtRxH6nR6fytW~uJKRP4hbjhfvBuS1QdX2GwWlbgJdV8VT3OpJAe5iuKYCFnnSbVG2VZajtsoKJxHY748h1zhIh4YaMBGqoodQJrnvYWd4HJJ-ZauE-s-K2zWOTJ-EKZNp9UZr5DWDV3P5JTSruc7vyKiDVFra~-JT8mjnWBE9GKy1HiJKAe2UyKHBVjvJ9iL4bJ3HLH-z3oIP5KmW7s4czTq2fdO7yhssLMKxaGqhzsNViWv8FtvLJtHkTsprVQBeS2Eeqiw3iwcC4DGP4dUkj2Ex7DPqvxlA58Df0INgNz-kUPuURf0ZSK45v-s7F0f03BbwIu5eErLZhQckxs9tX6twSPXk2RaceOMA0-eKlbCh3FcpbFbfcimjOTcmpeUN7s-7C-XfM1vazIaIpTADwzZ9Ocs5TV~CU8TPyxZkx8FAAAA
eepdot.i2p=IXWmPK6689w4d2j-B-zQRdgG6md6UdvDZz9e3MnEWaoU7SiHk8Yrw4-2MSavhycFDkQNdpdJgYVhK0Ve8aF4TNf88KdI5SY4nl079CrjhTaNoQiUxOTJIUzTWGrDmNITfoV7PAjGWoMjw5dOcbK~PMpMTlOx9w8CtFEHU2cG4Gdcpu5NFpv6a5FWZNO-GRYrWfW1laZBviaE1Twwva-thbY~G5un9JFAoQZ88mS2JRKrxFuy1P1xCEEEiLvJfOcHVdL-0ebQV5q5Cwlyvrkki1se4URzlgF-FjQjTiaS0kbtHv6NkG-R19poUQu-ktMdMdDf2RLFBJPtyTvbyteyeXnI4LjGxSzQ8eH3txelIZKXwCRPYFNqutAmoQMqLf~NLDPtIq3QGp798sBbt3nooOKGEk3RVcJDwEzx~t3Qj6DWEA0xwSm56YYG84EYT2itIYGH8J4epFjGdV3zfWiME~QHLKfAwwkY-JdCiaDTk7RPfY1jkBw~SyI1jTYrX-PgAAAA
modulus.i2p=HL47CwJWiovjoHMTK~2tK6~sYEghJapUNkeqOdnkWFsf985N8eCpRUQtz7fFJZrHCTHjqeO5hxvcFye~Jjtf~id7pFlaotkpmbnx75x5HCiTIBLTUfbPurjhTXNK3A0JFxQ5lmYd8S5WqNykdaZGHjhfDSC~PUcfJA398S611e2D5se1LKAp0qFFhbNi69Unovj7HdXYJLiATDhewt7tY6mMa-p3BeTcvu26MhET4itYBhzp12AKiqWrEQM-4tpCmK5K7gxECHOTuMtZu7SEVc4CYAgBIsILtT0YA84441o8h0kpsKGDPFuszMWtz5XSIFlO7mwpu6PCmBx6FZbaZFSQ8CghxqhrWGnGIno-Lr9vKeTpD-AT7rqwuUrZHfd3yhGhOA7i0nM6Uh~qXbvFkzK83kyyxbX4InjAZ4g897LixiCc2qj6~eeh1c9oNcZ01-ho5U7lXUo5WrfG1-N7DeH2xkWGzFrjlZ3dXP8w~f7osxtth596Jz~cY8xNacMuAAAA
xolotl.i2p=byBX2FzIeKKRoUStOzidJ6jni4dkWBNK4x3khxgNo8NlJ8HqLl2MlgxlRsvhTHQy5L1GvTC9DYpnW0tE22Kl9QkPIGPikBLvwePT82gsRCxXOJ6CF8JiK0h9~giTOrRmguIo7d8DpDF3Sw7a9VVJf~9Dxs4IMCMPre36rPdmqkYSTZcfITfWCG1M1xnxQz9OuB6YKnnYcLvccSAcOTrWFEeiPHC0CsAo1EmJekmEGCK3lkNBRomfw05uhLqA4mFQgZbvHfSDhDv1eEUeQq8YBk4-vi4AsRjdmgLL4yduqoYnLgTYL6OvWuJ60EdxPkuZUzW8~5MGZfwKQLc4G0YmAjgLlQi1sdXT4HFFLNRvG2GO956Eay9Z3eLO2K7EvxY0C9MQ5n0LullF5NJD-V509h7kBPuItUC0haicVHXXwcXW-Lx36biz8apA9D24vMWvq4KLystsrtMetH1q1oyS4jA5BXWf~6FA~eCoZrX4lgnHJ6MHPCEmlUcQPrEvApIyAAAA
freeciv.nightblade.i2p=mDlAeW1BD7ictjta8G0YwebMBmATFIWVXrVF6gpm3A13NMi1LIaq5da~zuQBWD3BLYmblE-3-U4snRHttVJBr-e9jAvy7ZBskGqie30JbzPbTBzLJWqdpaKzahI-eiezoDgVyhOstCBbjFc3CW~ckiLfj4MVS2nCV7qgujSWHho8mspb8lS0uJJk0XQImYx4QWY7KFCz2CaHY8JX~m05~81hTdJLZUjhDVBXsjj0wW-lE8mDZckiCn7ZaRSASBhFHiZnB6aGdY32Ltad6SjH0LngOcVbR43DYSHODabD6igb90c00wruQRMFarQSBBAk31uWnjftggllcA0X77NILD0PKG8RGa2fRcqyyVveGgYWhsl8vInVI-q-xI1PWairamHkzd-du58cmxzkqYZQR~XX5tPR3lQ-avScr0HgxHkMuTZSxEh72BcQP-qw2m0mPDrE445EPw3ipk8pRQi6H8lS0kCfDi8DBEygnqoLIqu35wrpEICCyog1buvppZTfAAAA
curiosity.i2p=pka8sWaYxpm1U9gX6F7WJ56Kl12Y~Fks1w0O3DnpE2bfRUZldWpFdtnB6mHhqyinZKJWJVwVR92uFpQPdLtwjfCQtVzw7zXpndXG05QeRk4viRd6mxRua8xBgc2IFhXRXUDP3sSZT6aKFyP6S-R8yGkXID5fxrO~um5aBmHGalDohXHdPxbqrBbSWqjKHr35f7zSiJkCCRxDMGqWkrVuzoZIhJIVeRZxYaubKW9R-oJdmDqhtQeP7Au7IFzno66-fa9gsGWCWAyoJe0dk4tKGZA~Q-qlwW1I3esAnp2LPwlkrqPL-A5xqw1Gdwgh93rKGtUV41wKlhubfEiUXbkDgw6RLcpxXKbQxkJPUGum2-B9QVraAanVB1NDsW2nJvK0lb7SGgEHrENHW~Z5X8CANURb5PHR4CRcp~xwrbS3DPYAoiah7Rd7-PqcbXHxSu5jl4sVm3pZYKbo8V-PLKxIYzSWUhrmj1wGRTizeml0xvl5ysoDc5p2srCT-T4ihrKrAAAA
anonymnet.i2p=Iku15m2pHtAfphzLKbhptluZuJ2FSst-b6WaiP-DWLue579sGChPuZEVxnbriFouidM4hw2Kvud1AeAYm632kDZZzIBf5EyCEdAPwc9R6cfBqe2N4hcvAXyWH9jevGMNe~NMOnjNvl8rKm2bGcEprvo1FPXKA1Ene2ATPViBVg-2xQyuZs9ZcU8rSi9~PrtG05zepAwfAGM2kIhNdF4biECXT-SLSxkU9An3GtAZjNkRMdiMPSY94mZWEalFbscuL8mlhl4xFg7XsnA1TEn6KaMnBjuf3FV9XSlXZ7pUD87BrRZYFHA0ujw5FqGu~-qLuIkbUpyhYz2rIHxNNJHm9l3T8yvumCanwr39xvganMLAD4nw~i0PKqQ5tLx0WBo64-GMz8Rbhfkhhj4a09qeR6OmDMwiyHoBgv9NDM6TCYBbLFMjf6X3wbcap4oOTNXvO3RG5T7kF-1RJ2IH6V3SwL9JpdH51fTo2WgBL9cESCvGntRM9g~EFyGyMoBAcmilAAAA
sasquotch.i2p=6Hv24DvlxKauUfLHN4cPJd13cRyFq1wqaCb95r7fCYvhdFzluuZLDBYCM3w9GM3EVyAXS8uz0BCy9ZYncWXCsFQYejkTj~pTJEo5QjM1DszuUAGvDrqlm21e-ZwzEY817dIQCp9dQShfSnP41J~jVktE3ryMmtzAnCIZ~nMUejc9wManQG4muxuyUADdIiBIp-MXOAdXeEaaP0~5WPZhf0okm6uJd~fvO4h1Sy-CQuuJzWKYzDOvHFu-~9ONYQV8EdP4wovC15uHgX79YwAd8bpNTcfzJN9ypr9cQ0zGxYzDuK9LHaSD5MXQ8Hu2RgIrKUfb~osG4MQuYalBkUr3dpLzXLEokNIPk~BI~fI9AuG27wLI47fvOUB8Zbu1J9rSgz-J-~x8Tp4UFvRKDJ2N~5rj9mMdm9iO~U8DJvkOjjRraXhwqh3YcrnhHLPia10jvu72dAGi~S4bxiHuEcDn1JZIj64Jb6TC6xfhwEn-uoE~dqXdbr0MMoVcDsOP5dPjAAAA
orz.i2p=GALU66G3Deh71g1COXAWKQvwVB2ULbf6ALTvc-vNHfZ~jkLhGpxmXOlVOu17hfWhB~whwj-~Hn7dxLgbXO1WXb-xmvKKIgxUssDosoSbM2v~LgzJq~iIkeoN9VQe4tz2pMql1-f3kV8-AHZIILR7tY61TjDLQbZSVhT0S7FIcTQulbct8wjP-p4Dvp4XUUFXJDRqIpZB9beNALEO-SYpFuadDeavDY4iUhNcERDXlj38ginXceHm5SXaiUNTr~qXzNNuR0r5FsAgjHLuy3UgnxM2aL~j7PXBieNL~mLs~YcYRYvZVtG~SXKQjUqw5iUJYYutgqHsiT7IrQKZ~FgvIYJWaZBgF-84WsfHgCw6jECkiiLgUxh676iNqMSfTkp0KMgjt~ekU9aWpZdiaD5KV2-phiuVMdEVbXCGfLnwSqWIQIrSAAXvsjL8ew7sCbtBOriGKUzeL~rBBltL6gSVdxn92fVdSz2XWGExvaT856ahgOtD8RFqCQTAUm~63xuSAAAA
microbleu.i2p=V-3EgQik4jTtYyE4OXHBNl2kslSh-1g7SvtKvt-xzm32Q0zt07meIq2Brj1tkv~xll8t1gyfvy0Wn1n7Pcf4tlSEQ2KfJm6oHv-ZIovxewn420yl8cLgbB-dtoiY84fRxl8pS2GTHL~SOFOzussSSocKIBay71ODyhe4mJdtFA76LY6ycgsFIxK4U~Hb5YcIbenO3-94Oc7PXaRt4XmQ-7C9ZKAJXhLdlQGF3407gituMrhnppwQMSQP2ULJEBiLNtB7h1KasNn0Ao~HNf7bsJyCB29YGgIESIIAZxrBFNsjOpYg4WE3iWfzU-C0ohOCIvQhMXS0jPitke9R7Oor8TmJNagfZVnE2zg2oIPP8uKqf~kFTugeI3dUrlfdSYr-rvzEGzRMOFIT9GBEXnuNPnX3tUHD0LNewP-D3VvnT6Pu~0kc7s8gyjc5~gI3vj8gn8gQnnFnz6BTYfqLufF7UQnJtEKrCi1eAG8Dnbc6vaoA9qoAEXAtN5SFXiprqwBvAAAA
www.postman.i2p=r8Ti6CtRJtSNAhxaoJuHZnbhAhjrbHIzMAVsuCNmLA7NO78mHvqLMk0HjQXou5fpnE40rCz5mxg-Zfz6J6B0rpE-UiqiozIC1cM-H-XM09Ftu6Ta97BeQ5MdrjtzJlagwXNM1Cn8k35UAdJQR2CfHQfJv0BUGVmkU8-D42fLqAVuRU9WpmA44YNMXJMT7kSqiZxKPdnXbpfst2h6ERLqGbqgCEToaH6NOyA8Lu4FJbOfkzfhrVIWHCiqn1FaAUK2Ie1POhfo8blfhQ1NdgkxGnTeaD1MJolI1qatpBWpsuiPlfMy7rxzTmP2dwpi-QQEdISi8U2eag3jsKGopQXwyn7Rx4zPQd82e9LCpiXWg2HVco1QV4H9z2alSHVJkWU-jC7jzQkDe-Iws-ZfEhKENRDps9Ev93KU-5-fohZZ614Ia0iDUs9RxP3mOM-RTiers~2B7Iq5-6hNMEoIzPzGbMKrrLs1Bos6LoZmIwGRS5pvlAis7usHjmBCy2hwqvi8AAAA
smtp.postman.i2p=AUVlGWmbU0qNUBGvu1ls5OQcdZNjq7k1OPzqkhheGlc3HoQFi97-3BZevo4ThjL0WxHoBIMagAfXjAEm7EegzYqkfGtQ5TpEVAxg01eIGO-Lqq46MqbOFX~edpgi9StZIAPaXJps0MPtSfh0FsL-N5PTW2nqkITrMPxOuhyl8CvAdR~TxHSImMI5nNzCW39xkDrEBx5Mkn1s~xm2XdhyttG2z~g6~nec4X3rpV0sO1Fq2T1sgaKcHWUvJofzUV1y~bKnltJEB~KZpkkOxjz3SdcJzn8SPblyWAm3SUiAVY8ev2XwSaLl7-xe2bQtrnjbPfpHZ50yhGY-00wTcXEfSgt20DkibP7xg3cSAcVFla2IiGeJc~4WTCP3vkBipTnSFdNr3Ez2kCEa50kMiRfDkIk4S2E64~JBrgyNURXL4YNC~FV7qaK2gqHUJkhRiRQP2Hbq2lDygJGFjr2vIi0TBoZ0lWaX6cu8Jywhp-jZgrvun-F~n87iRvnNjkjuG6BYAAAA
pop.postman.i2p=W4ZehJpFv9HnM4qnWb6c305H1vWRoghgSz~UXVVl7AM6cNYPU~DHzI0ezxyYIcsywhDvRdSvN5QQSyb2t-waFRaoMxmub9Z68uvcNPjAyG1Hc-igVbcmiGKo1RwXXO1JTzaAFE8NB2mvZmpksPDks0ugcd3AzBrrkxsqt8KLYSXBc7hDM59YUGl0j59NUZoE3tJgZlQ~fYr4P4P9VetBgVQ5mJFpwF~RvM2frx9zQ2SonCSTNFR88MEUJ6EoZUTDG-iz6mUVv2qOanAD1ZfSmmMZpbtFLovqvUGv8JLxFhFdkNmt3AmIZzPjmvrAu2X~VnAhX80Wrvba8df9w0qtplH5LYBykmN~wndjcQxOH7~LbGeJ-8q4DHf-DSDPFyn6L4uCk35kCSGXjEf1f44DSHU338Wiagn9ut7twiFSf8NLXvKV2-uWmx~twDLTd9cEjCEBm7ZXMaqWTK1kOGj0nlybm~mgMW-~IRnb6alnR0GMxAE-6fnWS52PJtmWU0ToAAAA
jake.i2p=BzdF-Ib~jWRj9i1hypIasw67yv0YDEdCqloJr4Qq2Wvkt56slqzd0Qri6FQnWsGfTpmilvGI1H-7WAyU5KXc~nQ7F7KB~Im9cI1mIeMKeGK4Yzb6jV5SHctDZw2j1hqMpdjU76r45WiOgiAaNFin10SJ8IriNqce9VehnOupB53tpvoj1GnEIyxxaOsSDmxIakFZ8MsLW~s9wyxnlfvP-iOXLMpM6Achhcmxj-DWDcjwK-6rvLYoG6SY5vmpPNzhuyAa-8di8N3zBxL6WTf1Ox9UQrpXXZ1luYDUNxpFfPjzl9ZPpv4Ax6QzJvWn8B85GYs9ZkS1bpbtbbmQ1DTlOpwFMmidr0vaf68hNGvVY5yUgPZy28s8jvrz4AMEfAGlsozRkxr2JRwm3Oj3dqeW6ICKRwnThkjnXnGhQiIDV~bDfkgBzWvh4TyIYm5NBwAYFZdSx81Eno4sthfElFTeSDj0TjCKegNmAd6t4D82JMk8abws0MC-pIqaNLZRU1YVAAAA
jabber-2.i2p=62UDEWG936i-w144HMYX~1aiRnvIkRg2Rbjor3KXUPfKaPXx6A6R54nhLYVI0Zt3Y6bquRIlvZd1KKb6VnQ~GbPhDKvOIzrSP~G7IajZOdncG4QlsuJYwOVVOSVAkR55pxdwwVHXkoR4~4hlahYGvGAayvvDxxWojr-dWg-IIUnEv8hjjstUfphSy~Jx17de0G~8n0DSZ~YKu83Cnu9sSydoXqqczq3KChFDjfUYtohNiZA8lXfrfv5K3pEeTOCemE1rDflPGu~5fawk3G1xNetuZQCKdkFNSxtkRpj3Vm2ej1ApLUi92zog3ekBbxEwfiP0DfC4BvdwgAimVGH8MpXS4BijlDNNbCWak6Pdr24OqVwLJXzWfqb11WFH-mc2JYJCPhJCvESYs~iK3JOZ0QzbW9F-495oB6RD-9guK9bBQHC1lMsNVhaj3Mh8gohKghvy2MrTNbirHKDjyyiAj5RrT1OjWoZNBMvXPEZEtEowuzZptP-tTf19mhGfPFOjAAAA
identiguy.i2p=EhDXPsItHi7Dfx8~~0iHPzkjiK1568wqEifARTr-ngIznwVaBmeEnSHXfLkA-7F~Nrqw95yQLlZpja6N1DyQNtJXPx-Db3apXuKwsuTNSGgZme2kFHXPh7PCsfzARwxn4d2-Nx75V4BSCgQr0gRjDa~L~JmtxPRUpZX2NyBvD0w5MSaD~9t4RuCRQ2gVDpUUDcTh2jkm2bX-R9vRIHhCZLasHxDR7rJC9-38uMsQ6ywd4ulQQYIs0kB1sEofdXUypyqphQU9xIxz7azgzKJp~dHnJpJ6SpaH7UrDN-YfOkAvGFBbk9k-u3NGl571Y205dQF~l3XHvVKf6NS9~JvtVh0JibwQ2qLVPy3Y~TtViffvpunNGOrfnVrT5-1c3lWNHx8gTalY3R-vU5rDd8Bz3AhNM6KWktZq8LiHHhJUxIkebXZsid-f2g~QgRRywxG7ksIlKsCMEn076f03L-oWJIlrAg5MdQd-qlg1Bs1IhrR8YT8jNYrX1bGdlmPrJDpiAAAA
detonate.i2p=6swCa-wAcpBdiCnMdObQlQ15isZTpAV8rlArR54Q5dZkALb5iMCjt0hYMoz89R9ycmtxcTNkgdNX37JsuAjeBFk~nUI11EGSyu-T3AOJg0sxUkoESuxqyLajqDSx8WVziI95LM8zOg~Gv0hpObbziMzu8hzLML2fTWF681sBA6gFzVSnjK9zA3cbWX7f0zGo4crruXsjrmJqWfS2~fNt5RYwHth57u-rZ8a4vl58uyv1Gb1~FAlyjyGMcr7eaQq3UJdEgHOHtXZSoGXZSAerpFreeHqC6Mu~-~-T7iph3jlfNyJYxLOBD8QKMPW~hGW9l6ips5zcc0KFjX2PWH5y4nbttb1LNvI6zn-q1F5t-ITP7UIovWcINfSzy5YoiuT1K6ZSay9DQSeuldBt9ajXDCkJKxOiZlB9C0RAmd9WDyAIKt~HhdnlpA~yOUuthBzrAe7iXt7lUqY3Rwqiby1CgqPKY941ChVY57AwWyxG4clM-a2MB8GuBImfqhp2LDFWAAAA
tinyurl.i2p=mfjh9H8RPkh6vYTSpFoghxSnrOzwBeE8ri3mIKwQOak0v0382ZawEDavYKcjIGg6xqzC0KA8KcOu0h151HzHZgCq2Qbzb6VGGSyyXqtsPGxSIjifIveSkIqNZE~ThySOiWXJ9Qp1EmFe9zA2m6Ey~lZL~yD8ackLzB6VY32xQN7y8kvPSt39Boty0mPXSvS5faVAd0UkbuEHOCP~~Z-E~WB2L2-ZWUD~P3zrZK560fa9-aU8g6pCjIJ8Vqx19tbkvYA~IUPtgXsgmjX6hWLpxN1oHE18jsj1IcAu0TCfldWyOtqcGOeBo20BVLZnx7-AqS0TiZhoIj7nog3x3xoOH2w6JomdJ9AT~4Z08pz0HvymVud0PXKOU7yP~QBj1~Us05-k0F-W6SmU6906l5YfNoXACurwy0VtgTmv7oJyOWpPdhFkZ98PwPL16W4iYsvZx6lDxvCxViAkYLw-fAkmueKrn2ZBau6TlhksvZt-Fqyjs~iZ4yme1243d87IZNb5AAAA
b.i2p=b2Ol9hg3uAOK3mB7sK~ydOZQlZIcc0Cixh~M89i71VgzxsK6NYCvFuiW8YeDZ9p3e-cNQrGTxrV6405km0F~pfKKyu09E-~-zAM19SHFmVWbT-XLEpfo9krLQu7416VMRPsPfLISzRU2wAptW2N6CuQmOEp8telmilhUiEqYTC7GBzmo-XNIKs9XSs3-6wSLkZ0haRJtS7YDdmjrDE-UXhu55E7VhUnm7TAxSH4bdUtM5tDUU7Q8lq~t7y9qSu0EWwvMBnkR9-p8SlcVBr-Zy4aG10OUcvnA07TA~Y8OKtEzJZ1PvzuZVIKerAQXuLK~SMB-9Xni7v7pbGW6Lok6dG9KJjrLORTpURAFgC~mux096li0VcotR6eMfBwGH9zLWgBruknix3TCrmUoafzCP4vyuDrugN8-0k54HZemGb601~9PJQYwyP-V4b33LJdq1d-tKDvgFqR3mm-YrEgZbUQ22BSsI3Jx~tWc3hft8KHkfF3zV6Op4TB04XeQ-WupAAAA
beyond.i2p=WNtBKmOowfzhsCX7dWwddaKVZttpm6aSYDiXzExh2ABPS7Ts9WBZxkqWS8CdEHq6ZSOUGzT6kyQYRGmF9~uTZ~nkI-UG8Hqh6uibT0H6-NOR0k2Qjp5y49VB9VRHJ6I2Vxg1uo09edWYKUatMgl7GESInmhZPDF4NOAq1SD6TQpLfAvVxPWglISZWg2Br3K-u9cHqH3Q0fvyy-Cka9ALZiBkXlZ5vccy5B2KE2JXdI1fAn1TLx8dKuR11Xsd-aNjPofis1Ak-cTia9YjKYSiO4v0A7uguQwBZCmTwI-uXLzUeOZjg69NuIhFUi2hN3tuNvCqAg73ct0lAMnfZ1d3oT9BGW6Aqh4fMTXr8MPT0Qpq9te7KF7L5q-LJ-9JFnYVvjx0P-6YUe-mH89HwyL4nip-ET8jzgIRyYE-WNzc1Q5KOGcrQVZJl7Vv5lziCCMxYoSKqiThps1vv-lC1uEyPbMYANkJVJdx9bnTqlQ8r9rlmFFQEmBCojc7LeRZpslTAAAA

View File

@@ -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)

View File

@@ -1 +1 @@
<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>

View File

@@ -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

View 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>

View File

@@ -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

View 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>

View File

@@ -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
View 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&#47;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&#47;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&#47;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&#47;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&#47;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&#47;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>

View File

@@ -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>

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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))

View File

@@ -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; }

View File

@@ -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[]);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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))

View File

@@ -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; }

View File

@@ -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();
}
}

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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 {

View File

@@ -9,8 +9,10 @@ package net.i2p.router;
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
@@ -21,12 +23,13 @@ import java.util.Set;
public abstract class CommSystemFacade implements Service {
public abstract void processMessage(OutNetMessage msg);
public void renderStatusHTML(OutputStream out) throws IOException { }
public void renderStatusHTML(Writer out) throws IOException { }
/** Create the set of RouterAddress structures based on the router's config */
public Set createAddresses() { return new HashSet(); }
public int countActivePeers() { return 0; }
public List getMostRecentErrorMessages() { return Collections.EMPTY_LIST; }
}
class DummyCommSystemFacade extends CommSystemFacade {

View File

@@ -60,6 +60,13 @@ public class InNetMessagePool {
I2NPMessage messageBody = msg.getMessage();
msg.processingComplete();
Date exp = messageBody.getMessageExpiration();
if (_log.shouldLog(Log.INFO))
_log.info("Received inbound "
+ " with id " + messageBody.getUniqueId()
+ " expiring on " + exp
+ " of type " + messageBody.getClass().getName());
boolean valid = _context.messageValidator().validateMessage(messageBody.getUniqueId(), exp.getTime());
if (!valid) {
if (_log.shouldLog(Log.WARN))

View File

@@ -9,7 +9,7 @@ package net.i2p.router;
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -289,6 +289,37 @@ public class JobQueue {
}
boolean isAlive() { return _alive; }
/**
* When did the most recently begin job start?
*/
public long getLastJobBegin() {
long when = -1;
// not synchronized, so might b0rk if the runners are changed
for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext(); ) {
long cur = ((JobQueueRunner)iter.next()).getLastBegin();
if (cur > when)
cur = when;
}
return when;
}
/**
* retrieve the most recently begin and still currently active job, or null if
* no jobs are running
*/
public Job getLastJob() {
Job j = null;
long when = -1;
// not synchronized, so might b0rk if the runners are changed
for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext(); ) {
JobQueueRunner cur = (JobQueueRunner)iter.next();
if (cur.getLastBegin() > when) {
j = cur.getCurrentJob();
when = cur.getLastBegin();
}
}
return j;
}
/**
* Blocking call to retrieve the next ready job
*
@@ -558,18 +589,18 @@ public class JobQueue {
// the remainder are utility methods for dumping status info
////
public void renderStatusHTML(OutputStream out) throws IOException {
public void renderStatusHTML(Writer out) throws IOException {
ArrayList readyJobs = null;
ArrayList timedJobs = null;
ArrayList activeJobs = new ArrayList(1);
ArrayList justFinishedJobs = new ArrayList(4);
out.write("<!-- jobQueue rendering -->\n".getBytes());
out.write("<!-- jobQueue rendering -->\n");
out.flush();
synchronized (_readyJobs) { readyJobs = new ArrayList(_readyJobs); }
out.write("<!-- jobQueue rendering: after readyJobs sync -->\n".getBytes());
out.write("<!-- jobQueue rendering: after readyJobs sync -->\n");
out.flush();
synchronized (_timedJobs) { timedJobs = new ArrayList(_timedJobs); }
out.write("<!-- jobQueue rendering: after timedJobs sync -->\n".getBytes());
out.write("<!-- jobQueue rendering: after timedJobs sync -->\n");
out.flush();
int numRunners = 0;
synchronized (_queueRunners) {
@@ -586,7 +617,7 @@ public class JobQueue {
numRunners = _queueRunners.size();
}
out.write("<!-- jobQueue rendering: after queueRunners sync -->\n".getBytes());
out.write("<!-- jobQueue rendering: after queueRunners sync -->\n");
out.flush();
StringBuffer buf = new StringBuffer(32*1024);
@@ -617,6 +648,7 @@ public class JobQueue {
buf.append(j.toString()).append("</li>\n");
}
buf.append("</ol>\n");
out.flush();
buf.append("# timed jobs: ").append(timedJobs.size()).append("<ol>\n");
TreeMap ordered = new TreeMap();
@@ -631,15 +663,15 @@ public class JobQueue {
}
buf.append("</ol>\n");
out.write("<!-- jobQueue rendering: after main buffer, before stats -->\n".getBytes());
out.write("<!-- jobQueue rendering: after main buffer, before stats -->\n");
out.flush();
getJobStats(buf);
out.write("<!-- jobQueue rendering: after stats -->\n".getBytes());
out.write("<!-- jobQueue rendering: after stats -->\n");
out.flush();
out.write(buf.toString().getBytes());
out.write(buf.toString());
}
/** render the HTML for the job stats */

View File

@@ -11,6 +11,7 @@ class JobQueueRunner implements Runnable {
private long _numJobs;
private Job _currentJob;
private Job _lastJob;
private long _lastBegin;
public JobQueueRunner(RouterContext context, int id) {
_context = context;
@@ -31,6 +32,7 @@ class JobQueueRunner implements Runnable {
public int getRunnerId() { return _id; }
public void stopRunning() { _keepRunning = false; }
public void startRunning() { _keepRunning = true; }
public long getLastBegin() { return _lastBegin; }
public void run() {
long lastActive = _context.clock().now();
long jobNum = 0;
@@ -103,6 +105,7 @@ class JobQueueRunner implements Runnable {
private void runCurrentJob() {
try {
_lastBegin = _context.clock().now();
_currentJob.runJob();
} catch (OutOfMemoryError oom) {
try {

View File

@@ -9,7 +9,7 @@ package net.i2p.router;
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -95,5 +95,5 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
public Set findNearestRouters(Hash key, int maxNumRouters, Set peersToIgnore) { return new HashSet(_routers.values()); }
public void renderStatusHTML(OutputStream out) throws IOException {}
public void renderStatusHTML(Writer out) throws IOException {}
}

View File

@@ -139,37 +139,18 @@ public class OutNetMessage {
public long getMessageSize() {
if (_messageSize <= 0) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); // large enough to hold most messages
_message.writeBytes(baos);
long sz = baos.size();
baos.reset();
_messageSize = sz;
} catch (DataFormatException dfe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe);
} catch (IOException ioe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe);
}
_messageSize = _message.getMessageSize();
}
return _messageSize;
}
public byte[] getMessageData() {
public int getMessageData(byte outBuffer[]) {
if (_message == null) {
return null;
return -1;
} else {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); // large enough to hold most messages
_message.writeBytes(baos);
byte data[] = baos.toByteArray();
_messageSize = data.length;
return data;
} catch (DataFormatException dfe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe);
} catch (IOException ioe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe);
}
return null;
int len = _message.toByteArray(outBuffer);
_messageSize = len;
return len;
}
}

View File

@@ -41,8 +41,18 @@ public class OutNetMessagePool {
*
*/
public void add(OutNetMessage msg) {
if (_log.shouldLog(Log.INFO))
_log.info("Adding outbound message to "
+ msg.getTarget().getIdentity().getHash().toBase64().substring(0,6)
+ " with id " + msg.getMessage().getUniqueId()
+ " expiring on " + msg.getMessage().getMessageExpiration()
+ " of type " + msg.getMessageType());
boolean valid = validate(msg);
if (!valid) return;
if (!valid) {
_context.messageRegistry().unregisterPending(msg);
return;
}
MessageSelector selector = msg.getReplySelector();
if (selector != null) {
_context.messageRegistry().registerPending(msg);

View File

@@ -8,7 +8,7 @@ package net.i2p.router;
*
*/
import java.io.OutputStream;
import java.io.Writer;
import java.util.List;
/**
@@ -31,6 +31,6 @@ class DummyPeerManagerFacade implements PeerManagerFacade {
public void shutdown() {}
public void startup() {}
public void restart() {}
public void renderStatusHTML(OutputStream out) { }
public void renderStatusHTML(Writer out) { }
public List selectPeers(PeerSelectionCriteria criteria) { return null; }
}

View File

@@ -12,7 +12,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
@@ -30,6 +30,7 @@ import net.i2p.crypto.DHSessionKeyBuilder;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.RouterInfo;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.i2np.GarlicMessage;
import net.i2p.data.i2np.TunnelMessage;
import net.i2p.router.message.GarlicMessageHandler;
@@ -37,6 +38,7 @@ import net.i2p.router.message.TunnelMessageHandler;
import net.i2p.router.startup.StartupJob;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
@@ -125,6 +127,11 @@ public class Router {
_gracefulShutdownDetector.setName("Graceful shutdown hook");
_gracefulShutdownDetector.start();
I2PThread watchdog = new I2PThread(new RouterWatchdog(_context));
watchdog.setName("RouterWatchdog");
watchdog.setDaemon(true);
watchdog.start();
_shutdownTasks = new HashSet(0);
}
@@ -220,16 +227,73 @@ public class Router {
}
public boolean isAlive() { return _isAlive; }
/**
* Rebuild and republish our routerInfo since something significant
* has changed.
*/
public void rebuildRouterInfo() {
if (_log.shouldLog(Log.INFO))
_log.info("Rebuilding new routerInfo");
RouterInfo ri = null;
if (_routerInfo != null)
ri = new RouterInfo(_routerInfo);
else
ri = new RouterInfo();
try {
ri.setPublished(_context.clock().now());
Properties stats = _context.statPublisher().publishStatistics();
ri.setOptions(stats);
ri.setAddresses(_context.commSystem().createAddresses());
SigningPrivateKey key = _context.keyManager().getSigningPrivateKey();
if (key == null) {
_log.log(Log.CRIT, "Internal error - signing private key not known? wtf");
return;
}
ri.sign(key);
setRouterInfo(ri);
_context.netDb().publish(ri);
} catch (DataFormatException dfe) {
_log.log(Log.CRIT, "Internal error - unable to sign our own address?!", dfe);
}
}
/**
* coallesce the stats framework every minute
*
*/
private final class CoallesceStatsJob extends JobImpl {
public CoallesceStatsJob() { super(Router.this._context); }
public CoallesceStatsJob() {
super(Router.this._context);
Router.this._context.statManager().createRateStat("bw.receiveBps", "How fast we receive data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
Router.this._context.statManager().createRateStat("bw.sendBps", "How fast we send data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
}
public String getName() { return "Coallesce stats"; }
public void runJob() {
Router.this._context.statManager().coallesceStats();
RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
if (receiveRate != null) {
Rate rate = receiveRate.getRate(60*1000);
if (rate != null) {
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
Router.this._context.statManager().addRateData("bw.receiveBps", (long)bps, 60*1000);
}
}
RateStat sendRate = _context.statManager().getRate("transport.sendMessageSize");
if (sendRate != null) {
Rate rate = receiveRate.getRate(60*1000);
if (rate != null) {
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
Router.this._context.statManager().addRateData("bw.sendBps", (long)bps, 60*1000);
}
}
requeue(60*1000);
}
}
@@ -281,8 +345,8 @@ public class Router {
_context.inNetMessagePool().registerHandlerJobBuilder(TunnelMessage.MESSAGE_TYPE, new TunnelMessageHandler(_context));
}
public void renderStatusHTML(OutputStream out) throws IOException {
out.write(("<h1>Router console</h1>\n" +
public void renderStatusHTML(Writer out) throws IOException {
out.write("<h1>Router console</h1>\n" +
"<i><a href=\"/oldconsole.jsp\">console</a> | <a href=\"/oldstats.jsp\">stats</a></i><br>\n" +
"<form action=\"/oldconsole.jsp\">" +
"<select name=\"go\" onChange='location.href=this.value'>" +
@@ -297,7 +361,7 @@ public class Router {
"<option value=\"/oldconsole.jsp#netdb\">Network Database</option>\n" +
"<option value=\"/oldconsole.jsp#logs\">Log messages</option>\n" +
"</select> <input type=\"submit\" value=\"GO\" /> </form>" +
"<hr />\n").getBytes());
"<hr />\n");
StringBuffer buf = new StringBuffer(32*1024);
@@ -419,39 +483,39 @@ public class Router {
buf.append("trying to transfer data. Lifetime averages count how many elephants there are on the moon [like anyone reads this text]</i>");
buf.append("\n");
out.write(buf.toString().getBytes());
out.write(buf.toString());
_context.bandwidthLimiter().renderStatusHTML(out);
out.write("<hr /><a name=\"clients\"> </a>\n".getBytes());
out.write("<hr /><a name=\"clients\"> </a>\n");
_context.clientManager().renderStatusHTML(out);
out.write("\n<hr /><a name=\"transports\"> </a>\n".getBytes());
out.write("\n<hr /><a name=\"transports\"> </a>\n");
_context.commSystem().renderStatusHTML(out);
out.write("\n<hr /><a name=\"profiles\"> </a>\n".getBytes());
out.write("\n<hr /><a name=\"profiles\"> </a>\n");
_context.peerManager().renderStatusHTML(out);
out.write("\n<hr /><a name=\"tunnels\"> </a>\n".getBytes());
out.write("\n<hr /><a name=\"tunnels\"> </a>\n");
_context.tunnelManager().renderStatusHTML(out);
out.write("\n<hr /><a name=\"jobs\"> </a>\n".getBytes());
out.write("\n<hr /><a name=\"jobs\"> </a>\n");
_context.jobQueue().renderStatusHTML(out);
out.write("\n<hr /><a name=\"shitlist\"> </a>\n".getBytes());
out.write("\n<hr /><a name=\"shitlist\"> </a>\n");
_context.shitlist().renderStatusHTML(out);
out.write("\n<hr /><a name=\"pending\"> </a>\n".getBytes());
out.write("\n<hr /><a name=\"pending\"> </a>\n");
_context.messageRegistry().renderStatusHTML(out);
out.write("\n<hr /><a name=\"netdb\"> </a>\n".getBytes());
out.write("\n<hr /><a name=\"netdb\"> </a>\n");
_context.netDb().renderStatusHTML(out);
@@ -466,7 +530,8 @@ public class Router {
buf.append("</pre></td></tr>\n");
}
buf.append("</table>\n");
out.write(buf.toString().getBytes());
out.write(buf.toString());
out.flush();
}
private static int MAX_MSG_LENGTH = 120;
@@ -571,7 +636,7 @@ public class Router {
try { _context.messageRegistry().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message registry", t); }
try { _context.messageValidator().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message validator", t); }
try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
_context.listContexts().remove(_context);
RouterContext.listContexts().remove(_context);
dumpStats();
try {
for (Iterator iter = _shutdownTasks.iterator(); iter.hasNext(); ) {
@@ -625,6 +690,14 @@ public class Router {
public boolean gracefulShutdownInProgress() {
return (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS));
}
/** How long until the graceful shutdown will kill us? */
public long getShutdownTimeRemaining() {
long exp = _context.tunnelManager().getLastParticipatingExpiration();
if (exp < 0)
return -1;
else
return exp + 2*CLOCK_FUDGE_FACTOR - _context.clock().now();
}
/**
* Simple thread that sits and waits forever, managing the
@@ -727,7 +800,7 @@ public class Router {
File updateFile = new File(UPDATE_FILE);
if (updateFile.exists()) {
System.out.println("INFO: Update file exists [" + UPDATE_FILE + "] - installing");
boolean ok = DataHelper.extractZip(updateFile, new File("."));
boolean ok = FileUtil.extractZip(updateFile, new File("."));
if (ok)
System.out.println("INFO: Update installed");
else

View File

@@ -31,4 +31,15 @@ public interface RouterThrottle {
*
*/
public boolean acceptNetDbLookupRequest(Hash key);
/** How backed up we are at the moment processing messages (in milliseconds) */
public long getMessageDelay();
/** How backed up our tunnels are at the moment (in milliseconds) */
public long getTunnelLag();
/**
* How much faster (or if negative, slower) we are receiving data as
* opposed to our longer term averages?
*
*/
public double getInboundRateDelta();
}

Some files were not shown because too many files have changed in this diff Show More