Compare commits

...

40 Commits

Author SHA1 Message Date
a2bd71c75b * 2005-03-18 0.5.0.3 released
2005-03-18  jrandom
    * Minor tweak to the timestamper to help reduce small skews
    * Adjust the stats published to include only the relevent ones
    * Only show the currently used speed calculation on the profile page
    * Allow the full max # resends to be sent, rather than piggybacking the
      RESET packet along side the final resend (duh)
    * Add irc.postman.i2p to the default list of IRC servers for new installs
    * Drop support for routers running 0.5 or 0.5.0.1 while maintaining
      backwards compatability for users running 0.5.0.2.
2005-03-18 22:34:51 +00:00
89509490c5 2005-03-18 jrandom
* Eepproxy Fix for corrupted HTTP headers (thanks nickster!)
    * Fixed case sensitivity issues on the HTTP headers (thanks duck!)
2005-03-18 08:48:00 +00:00
a997a46040 2005-03-17 jrandom
* Update the old speed calculator and associated profile data points to
      use a non-tiered moving average of the tunnel test time, avoiding the
      freshness issues of the old tiered speed stats.
    * Explicitly synchronize all of the methods on the PRNG, rather than just
      the feeder methods (sun and kaffe only need the feeder, but it seems ibm
      needs all of them synchronized).
    * Properly use the tunnel tests as part of the profile stats.
    * Don't flood the jobqueue with sequential persist profile tasks, but
      instead, inject a brief scheduling delay between them.
    * Reduce the TCP connection establishment timeout to 20s (which is still
      absurdly excessive)
    * Reduced the max resend delay to 30s so we can get some resends in when
      dealing with client apps that hang up early (e.g. wget)
    * Added more alternative socketManager factories (good call aum!)
2005-03-17 22:12:51 +00:00
538dd07e7b 2005-03-16 jrandom
* Adjust the old speed calculator to include end to end RTT data in its
      estimates, and use that as the primary speed calculator again.
    * Use the mean of the high capacity speeds to determine the fast
      threshold, rather than the median.  Perhaps we should use the mean of
      all active non-failing peers?
    * Updated the profile page to sort by tier, then alphabetically.
    * Added some alternative socketManager factories (good call aum!)
2005-03-17 05:29:55 +00:00
046778404e added arkan.i2p, search.i2p, floureszination.i2p, antipiratbyran.i2p
asylum.i2p, templar.i2p
2005-03-16 02:56:01 +00:00
766f83d653 added feedspace.i2p 2005-03-16 02:46:17 +00:00
b20aee6753 2005-03-14 jrandom
* New strict speed calculator that goes off the actual number of messages
      verifiably sent through the peer by way of tunnels.  Initially, this only
      contains the successful message count on inbound tunnels, but may be
      augmented later to include verified outbound messages, peers queried in
      the netDb, etc.  The speed calculation decays quickly, but should give
      a better differential than the previous stat (both values are shown on
      the /profiles.jsp page)
2005-03-15 03:47:14 +00:00
f9aa3aef18 added wiki.fr.i2p 2005-03-14 04:31:55 +00:00
d74aa6e53d (no, this doesnt fix things yet, but its a save point along the path)
2005-03-11  jrandom
    * Rather than the fixed resend timeout floor (10s), use 10s+RTT as the
      minimum (increased on resends as before, of course).
    * Always prod the clock update listeners, even if just to tell them that
      the time hasn't changed much.
    * Added support for explicit peer selection for individual tunnel pools,
      which will be useful in debugging but not recommended for use by normal
      end users.
    * More aggressively search for the next hop's routerInfo on tunnel join.
    * Give messages received via inbound tunnels that are bound to remote
      locations sufficient time (taking into account clock skew).
    * Give alternate direct send messages sufficient time (10s min, not 5s)
    * Always give the end to end data message the explicit timeout (though the
      old default was sufficient before)
    * No need to give end to end messages an insane expiration (+2m), as we
      are already handling skew on the receiving side.
    * Don't complain too loudly about expired TunnelCreateMessages (at least,
      not until after all those 0.5 and 0.5.0.1 users upgrade ;)
    * Properly keep the sendBps stat
    * When running the router with router.keepHistory=true, log more data to
      messageHistory.txt
    * Logging updates
    * Minor formatting updates
2005-03-11 22:23:36 +00:00
ea6fbc7835 added septu.i2p 2005-03-09 20:02:14 +00:00
536e604b8e 2005-03-07 jrandom
* Fix the HTTP response header filter to allow multiple headers with the
      same name (thanks duck and spotteri!)
2005-03-08 02:45:14 +00:00
49d6f5018f * Properly expand the HTTP response header buffer (thanks shendaras!) 2005-03-07 00:40:45 +00:00
4a830e422a added music.i2p, rotten.i2p, wintermute.i2p, kaji2.i2p, aspnet.i2p, gaming.i2p, nntp.i2p 2005-03-07 00:38:19 +00:00
df6c52fe75 * 2005-03-06 0.5.0.2 released
2005-03-06  jrandom
    * Allow the I2PTunnel web interface to select streaming lib options for
      individual client tunnels, rather than sharing them across all of them,
      as we do with the session options.  This way people can (and should) set
      the irc proxy to interactive and the eepproxy to bulk.
    * Added a startRouter.sh script to new installs which simply calls
      "sh i2prouter start".  This should make it clear how people should start
      I2P.
2005-03-07 00:07:27 +00:00
01979c08b3 2005-03-04 jrandom
* Filter HTTP response headers in the eepproxy, forcing Connection: close
      so that broken (/malicious) webservers can't allow persistent
      connections.  All HTTP compliant browsers should now always close the
      socket.
    * Enabled the GZIPInputStream's cache (they were'nt cached before)
    * Make sure our first send is always a SYN (duh)
    * Workaround for some buggy compilers
2005-03-05 02:54:42 +00:00
7928ef83cc added cowsay.i2p 2005-03-04 23:37:39 +00:00
10afe0a060 2005-03-03 jrandom
* Loop while starting up the I2PTunnel instances, in case the I2CP
      listener isn't up yet (thanks detonate!)
    * Implement custom reusable GZIP streams to both reduce memory churn
      and prevent the exposure of data in the standard GZIP header (creation
      time, OS, etc).  This is RFC1952 compliant, and backwards compatible,
      though has only been tested within the confines of I2P's compression use
      (DataHelper.[de]compress).
    * Preemptively support the next protocol version, so that after the 0.5.0.2
      release, we'll be able to drop protocol=2 to get rid of 0.5 users.
2005-03-04 06:09:20 +00:00
ef230cfa3d 2005-03-02 jrandom
* Fix one substantial OOM cause (session tag manager was only dropping
      tags once the critical limit was met, rather than honoring their
      expiration) (duh)
    * Lots of small memory fixes
    * Double the allowable concurrent outstanding tunnel build tasks (20)
2005-03-03 03:36:52 +00:00
2d15a42137 big code cleanup to reduce number of compiler warnings 2005-03-01 23:25:15 +00:00
57d6a2f645 2005-03-01 jrandom
* Really disable the streaming lib packet caching
    * Synchronized a message handling point in the SDK (even though its use is
      already essentially single threaded, its better to play it safe)
    * Don't add new RepublishLeaseSetJobs on failure, just requeue up the
      existing one (duh)
    * Throttle the number of concurrent pending tunnel builds across all
      pools, in addition to simply throttling the number of new requests per
      minute for each pool individually.  This should avoid the cascading
      failure when tunnel builds take too long, as no new builds will be
      created until the previous ones are handled.
    * Factored out and extended the DataHelper's unit tests for dealing with
      long and date formatting.
    * Explicitly specify the HTTP auth realm as "i2prouter", though this
      alone doesn't address the bug where jetty asks for authentication too
      much.  (thanks orion!)
    * Updated the StreamSinkServer to ignore all read bytes, rather than write
      them to the filesystem.
2005-03-01 17:50:52 +00:00
469a0852d7 2005-02-27 jrandom
* Don't rerequest leaseSets if there are already pending requests
    * Reverted the insufficiently tested caching in the DSA/SHA1 impl, and
      temporary disabled the streaming lib packet caching.
    * Reduced the resend RTT penalty to 10s
2005-02-27 22:09:37 +00:00
7983bb1490 1.3 here too 2005-02-27 00:13:00 +00:00
2e7eac02ed 2005-02-26 jrandom
* Force 1.3-isms on the precompiled jsps too (thanks laberhost)
2005-02-27 00:03:42 +00:00
238389fc7f 2005-02-26 jrandom
* Further streaming lib caching improvements
    * Reduce the minimum RTT (used to calculate retry timeouts), but also
      increase the RTT on resends.
    * Lower the default message size to 4KB from 16KB to further reduce the
      chance of failed fragmentation.
    * Extend tunnel rebuild throttling to include fallback rebuilds
    * If there are less than 20 routers known, don't drop the last 20 (to help
      avoid dropping all peers under catastrophic failures)
    * New stats for end to end messages - "client.leaseSetFoundLocally",
      "client.leaseSetFoundRemoteTime", and "client.leaseSetFailedRemoteTime"
2005-02-26 19:16:46 +00:00
4cec9da0a6 2005-02-24 jrandom
* Throttle the number of tunnel rebuilds per minute, preventing CPU
      overload under catastrophic failures (thanks Tracker and cervantes!)
    * Block the router startup process until we've initialized the clock
2005-02-24 23:53:35 +00:00
00f27d4400 2005-02-24 jrandom
* Cache temporary memory allocation in the DSA's SHA1 impl, and the packet
      data in the streaming lib.
    * Fixed a streaming lib bug where the connection initiator would fail the
      stream if the ACK to their SYN was lost.
2005-02-24 18:05:25 +00:00
f61618e4a4 2005-02-23 jrandom
* Now that we don't get stale SAM sessions, it'd be nice if we didn't
      get stale tunnel pools, don't you think?
2005-02-23 21:44:30 +00:00
265d5e306e * 2005-02-23 0.5.0.1 released 2005-02-23 05:00:52 +00:00
10ed058c2e 2005-02-22 jrandom
* Reworked the tunnel (re)building process to remove the tokens and
      provide cleaner controls on the tunnels built.
    * Fixed situations where the timestamper wanted to test more servers than
      were provided (thanks Tracker!)
    * Get rid of the dead SAM sessions by using the streaming lib's callbacks
      (thanks Tracker!)
2005-02-23 04:20:28 +00:00
8a21f0efec 2005-02-22 jrandom
* Temporary workaround for the I2CP disconnect bug (have the streaminglib
      try to automatically reconnect on accept()/connect(..)).
    * Loop check for expired lease republishing (just in case)
2005-02-22 23:13:00 +00:00
b8291ac5a4 2005-02-22 jrandom
* Temporary workaround for the I2CP disconnect bug (have the streaminglib
      try to automatically reconnect on accept()/connect(..)).
    * Loop check for expired lease republishing (just in case)
2005-02-22 22:58:21 +00:00
c17433cb93 2005-02-22 jrandom
* Adjusted (and fixed...) the timestamper change detection
    * Deal with a rare reordering bug at the beginning of a stream (so we
      don't drop it unnecessarily)
    * Cleaned up some dropped message handling in the router
    * Reduced job queue churn when dealing with a large number of tunnels by
      sharing an expiration job
    * Keep a separate list of the most recent CRIT messages (shown on the
      logs.jsp).  This way they don't get buried among any other messages.
    * For clarity, display the tunnel variance config as "Randomization" on
      the web console.
    * If lease republishing fails (boo! hiss!) try it again
    * Actually fix the negative jobLag in the right place (this time)
    * Allow reseeding when there are less than 10 known peer references
    * Lots of logging updates.
2005-02-22 07:07:29 +00:00
35fe7f8203 2005-02-20 jrandom
* Allow the streaming lib resend frequency to drop down to 20s as the
      minimum, so that up to 2 retries can get sent on an http request.
    * Add further limits to failsafe tunnels.
    * Keep exploratory and client tunnel testing and building stats separate.
    * Only use the 60s period for throttling tunnel requests due to transient
      network overload.
    * Rebuild tunnels earlier (1-3m before expiration, by default)
    * Cache the next hop's routerInfo for participating tunnels so that the
      tunnel participation doesn't depend on the netDb.
    * Fixed a long standing bug in the streaming lib where we wouldn't always
      unchoke messages when the window size grows.
    * Make sure the window size never reaches 0 (duh)
2005-02-21 19:08:01 +00:00
21f13dba43 2005-02-20 jrandom
* Allow the streaming lib resend frequency to drop down to 20s as the
      minimum, so that up to 2 retries can get sent on an http request.
    * Add further limits to failsafe tunnels.
    * Keep exploratory and client tunnel testing and building stats separate.
    * Only use the 60s period for throttling tunnel requests due to transient
      network overload.
    * Rebuild tunnels earlier (1-3m before expiration, by default)
    * Cache the next hop's routerInfo for participating tunnels so that the
      tunnel participation doesn't depend on the netDb.
    * Fixed a long standing bug in the streaming lib where we wouldn't always
      unchoke messages when the window size grows.
    * Make sure the window size never reaches 0 (duh)
2005-02-21 18:02:14 +00:00
0db239a3fe added irc.postman.i2p 2005-02-21 03:13:40 +00:00
4745d61f9b added subrosa.i2p 2005-02-21 02:55:12 +00:00
b9a4c3ba52 *cough* 2005-02-20 11:09:05 +00:00
cbf6a70a1a 2005-02-20 jrandom
* Only build failsafe tunnels if we need them
    * Properly implement the selectNotFailingPeers so that we get a random
      selection of peers, rather than using the strictOrdering (thanks dm!)
    * Don't include too many "don't tell me about" peer references in the
      lookup message - only send the 10 peer references closest to the target.
2005-02-20 09:12:43 +00:00
7d4e093b58 2005-02-19 jrandom
* Only build new extra tunnels on failure if we don't have enough
    * Fix a fencepost in the tunnel building so that e.g. a variance of
      2 means +/- 2, not +/- 1 (thanks dm!)
    * Avoid an NPE on client disconnect
    * Never select a shitlisted peer to participate in a tunnel
    * Have netDb store messages timeout after 10s, not the full 60s (duh)
    * Keep session tags around for a little longer, just in case (grr)
    * Cleaned up some closing event issues on the streaming lib
    * Stop bundling the jetty 5.1.2 and updated wrapper.config in the update
      so that 0.4.* users will need to do a clean install, but we don't need
      to shove an additional 2MB in each update to those already on 0.5.
    * Imported the susimail css (oops, thanks susi!)
2005-02-19 23:20:56 +00:00
d27feabcb3 clear the old precompiled .java files (thanks duck!) 2005-02-18 16:56:46 +00:00
224 changed files with 3671 additions and 1141 deletions

View File

@ -21,7 +21,8 @@
<target name="distclean" depends="clean" />
<target name="compile" depends="init">
<javac srcdir="${src}" destdir="${build}" classpath="${servlet}"/>
<javac debug="true" deprecation="on" source="1.3" target="1.3"
srcdir="${src}" destdir="${build}" classpath="${servlet}"/>
</target>
<target name="jar" depends="compile">

View File

@ -31,6 +31,9 @@
</war>
</target>
<target name="precompilejsp">
<delete dir="../jsp/WEB-INF/" />
<delete file="../jsp/web-fragment.xml" />
<delete file="../jsp/web-out.xml" />
<mkdir dir="../jsp/WEB-INF/" />
<mkdir dir="../jsp/WEB-INF/classes" />
<!-- there are various jspc ant tasks, but they all seem a bit flakey -->
@ -53,7 +56,8 @@
<arg value="-webapp" />
<arg value="../jsp/" />
</java>
<javac destdir="../jsp/WEB-INF/classes/" srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
<javac debug="true" deprecation="on" source="1.3" target="1.3"
destdir="../jsp/WEB-INF/classes/" srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
<classpath>
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />

View File

@ -0,0 +1,242 @@
package net.i2p.i2ptunnel;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2005 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.FilterOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import net.i2p.data.ByteArray;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
/**
* Simple stream for delivering an HTTP response to
* the client, trivially filtered to make sure "Connection: close"
* is always in the response.
*
*/
class HTTPResponseOutputStream extends FilterOutputStream {
private static final Log _log = new Log(HTTPResponseOutputStream.class);
private ByteCache _cache;
protected ByteArray _headerBuffer;
private boolean _headerWritten;
private byte _buf1[];
private static final int CACHE_SIZE = 8*1024;
public HTTPResponseOutputStream(OutputStream raw) {
super(raw);
_cache = ByteCache.getInstance(8, CACHE_SIZE);
_headerBuffer = _cache.acquire();
_headerWritten = false;
_buf1 = new byte[1];
}
public void write(int c) throws IOException {
_buf1[0] = (byte)c;
write(_buf1, 0, 1);
}
public void write(byte buf[]) throws IOException {
write(buf, 0, buf.length);
}
public void write(byte buf[], int off, int len) throws IOException {
if (_headerWritten) {
out.write(buf, off, len);
return;
}
for (int i = 0; i < len; i++) {
ensureCapacity();
_headerBuffer.getData()[_headerBuffer.getValid()] = buf[off+i];
_headerBuffer.setValid(_headerBuffer.getValid()+1);
if (headerReceived()) {
writeHeader();
_headerWritten = true;
if (i + 1 < len) // write out the remaining
out.write(buf, off+i+1, len-i-1);
return;
}
}
}
/** grow (and free) the buffer as necessary */
private void ensureCapacity() {
if (_headerBuffer.getValid() + 1 >= _headerBuffer.getData().length) {
int newSize = (int)(_headerBuffer.getData().length * 1.5);
ByteArray newBuf = new ByteArray(new byte[newSize]);
System.arraycopy(_headerBuffer.getData(), 0, newBuf.getData(), 0, _headerBuffer.getValid());
newBuf.setValid(_headerBuffer.getValid());
newBuf.setOffset(0);
if (_headerBuffer.getData().length == CACHE_SIZE)
_cache.release(_headerBuffer);
_headerBuffer = newBuf;
}
}
/** are the headers finished? */
private boolean headerReceived() {
if (_headerBuffer.getValid() < 3) return false;
byte first = _headerBuffer.getData()[_headerBuffer.getValid()-3];
byte second = _headerBuffer.getData()[_headerBuffer.getValid()-2];
byte third = _headerBuffer.getData()[_headerBuffer.getValid()-1];
return (isNL(second) && isNL(third)) || // \n\n
(isNL(first) && isNL(third)); // \n\r\n
}
/**
* Tweak that first HTTP response line (HTTP 200 OK, etc)
*
*/
protected String filterResponseLine(String line) {
return line;
}
/** we ignore any potential \r, since we trim it on write anyway */
private static final byte NL = '\n';
private boolean isNL(byte b) { return (b == NL); }
/** ok, received, now munge & write it */
private void writeHeader() throws IOException {
String responseLine = null;
boolean connectionSent = false;
boolean proxyConnectionSent = false;
int lastEnd = -1;
for (int i = 0; i < _headerBuffer.getValid(); i++) {
if (isNL(_headerBuffer.getData()[i])) {
if (lastEnd == -1) {
responseLine = new String(_headerBuffer.getData(), 0, i+1); // includes NL
responseLine = filterResponseLine(responseLine);
responseLine = (responseLine.trim() + "\n");
out.write(responseLine.getBytes());
} else {
for (int j = lastEnd+1; j < i; j++) {
if (_headerBuffer.getData()[j] == ':') {
int keyLen = j-(lastEnd+1);
int valLen = i-(j+2);
if ( (keyLen <= 0) || (valLen <= 0) )
throw new IOException("Invalid header @ " + j);
String key = new String(_headerBuffer.getData(), lastEnd+1, keyLen);
String val = new String(_headerBuffer.getData(), j+2, valLen);
if ("Connection".equalsIgnoreCase(key)) {
out.write("Connection: close\n".getBytes());
connectionSent = true;
} else if ("Proxy-Connection".equalsIgnoreCase(key)) {
out.write("Proxy-Connection: close\n".getBytes());
proxyConnectionSent = true;
} else {
out.write((key.trim() + ": " + val.trim() + "\n").getBytes());
}
break;
}
}
}
lastEnd = i;
}
}
if (!connectionSent)
out.write("Connection: close\n".getBytes());
if (!proxyConnectionSent)
out.write("Proxy-Connection: close\n".getBytes());
out.write("\n".getBytes()); // end of the headers
// done, shove off
if (_headerBuffer.getData().length == CACHE_SIZE)
_cache.release(_headerBuffer);
else
_headerBuffer = null;
}
public static void main(String args[]) {
String simple = "HTTP/1.1 200 OK\n" +
"foo: bar\n" +
"baz: bat\n" +
"\n" +
"hi ho, this is the body";
String filtered = "HTTP/1.1 200 OK\n" +
"Connection: keep-alive\n" +
"foo: bar\n" +
"baz: bat\n" +
"\n" +
"hi ho, this is the body";
String winfilter= "HTTP/1.1 200 OK\r\n" +
"Connection: keep-alive\r\n" +
"foo: bar\r\n" +
"baz: bat\r\n" +
"\r\n" +
"hi ho, this is the body";
String minimal = "HTTP/1.1 200 OK\n" +
"\n" +
"hi ho, this is the body";
String winmin = "HTTP/1.1 200 OK\r\n" +
"\r\n" +
"hi ho, this is the body";
String invalid1 = "HTTP/1.1 200 OK\n";
String invalid2 = "HTTP/1.1 200 OK";
String invalid3 = "HTTP 200 OK\r\n";
String invalid4 = "HTTP 200 OK\r";
String invalid5 = "HTTP/1.1 200 OK\r\n" +
"I am broken, and I smell\r\n" +
"\r\n";
String invalid6 = "HTTP/1.1 200 OK\r\n" +
":I am broken, and I smell\r\n" +
"\r\n";
String invalid7 = "HTTP/1.1 200 OK\n" +
"I am broken, and I smell:\n" +
":asdf\n" +
":\n" +
"\n";
String large = "HTTP/1.1 200 OK\n" +
"Last-modified: Tue, 25 Nov 2003 12:05:38 GMT\n" +
"Expires: Tue, 25 Nov 2003 12:05:38 GMT\n" +
"Content-length: 32\n" +
"\n" +
"hi ho, this is the body";
/* */
test("Simple", simple, true);
test("Filtered", filtered, true);
test("Filtered windows", winfilter, true);
test("Minimal", minimal, true);
test("Windows", winmin, true);
test("Large", large, true);
test("Invalid (short headers)", invalid1, true);
test("Invalid (no headers)", invalid2, true);
test("Invalid (windows with short headers)", invalid3, true);
test("Invalid (windows no headers)", invalid4, true);
test("Invalid (bad headers)", invalid5, true);
test("Invalid (bad headers2)", invalid6, false);
test("Invalid (bad headers3)", invalid7, false);
/* */
}
private static void test(String name, String orig, boolean shouldPass) {
System.out.println("====Testing: " + name + "\n" + orig + "\n------------");
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
HTTPResponseOutputStream resp = new HTTPResponseOutputStream(baos);
resp.write(orig.getBytes());
resp.flush();
String received = new String(baos.toByteArray());
System.out.println(received);
} catch (Exception e) {
if (shouldPass)
e.printStackTrace();
else
System.out.println("Properly fails with " + e.getMessage());
}
}
}

View File

@ -12,15 +12,12 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import net.i2p.I2PException;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
@ -104,11 +101,17 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
this.l = l;
this.handlerName = handlerName + _clientId;
synchronized (sockLock) {
if (ownDest) {
sockMgr = buildSocketManager();
} else {
sockMgr = getSocketManager();
while (sockMgr == null) {
synchronized (sockLock) {
if (ownDest) {
sockMgr = buildSocketManager();
} else {
sockMgr = getSocketManager();
}
}
if (sockMgr == null) {
_log.log(Log.CRIT, "Unable to create socket manager");
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
}
}
if (sockMgr == null) {

View File

@ -22,9 +22,7 @@ import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.Clock;
import net.i2p.util.EventDispatcher;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
/**
@ -196,9 +194,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
if (_log.shouldLog(Log.DEBUG))
_log.debug(getPrefix(requestId) + "Line=[" + line + "]");
if (line.startsWith("Connection: ") ||
line.startsWith("Keep-Alive: ") ||
line.startsWith("Proxy-Connection: "))
String lowercaseLine = line.toLowerCase();
if (lowercaseLine.startsWith("connection: ") ||
lowercaseLine.startsWith("keep-alive: ") ||
lowercaseLine.startsWith("proxy-connection: "))
continue;
if (method == null) { // first line (GET /base64/realaddr)
@ -337,29 +336,29 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
}
} else {
if (line.startsWith("Host: ") && !usingWWWProxy) {
if (lowercaseLine.startsWith("host: ") && !usingWWWProxy) {
line = "Host: " + host;
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Setting host = " + host);
} else if (line.startsWith("User-Agent: ")) {
} else if (lowercaseLine.startsWith("user-agent: ")) {
// always stripped, added back at the end
line = null;
continue;
} else if (line.startsWith("Accept")) {
} else if (lowercaseLine.startsWith("accept")) {
// strip the accept-blah headers, as they vary dramatically from
// browser to browser
line = null;
continue;
} else if (line.startsWith("Referer: ")) {
} else if (lowercaseLine.startsWith("referer: ")) {
// Shouldn't we be more specific, like accepting in-site referers ?
//line = "Referer: i2p";
line = null;
continue; // completely strip the line
} else if (line.startsWith("Via: ")) {
} else if (lowercaseLine.startsWith("via: ")) {
//line = "Via: i2p";
line = null;
continue; // completely strip the line
} else if (line.startsWith("From: ")) {
} else if (lowercaseLine.startsWith("from: ")) {
//line = "From: i2p";
line = null;
continue; // completely strip the line
@ -418,7 +417,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
I2PSocket i2ps = createI2PSocket(dest, getDefaultOptions(opts));
byte[] data = newRequest.toString().getBytes("ISO-8859-1");
Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
I2PTunnelRunner runner = new I2PTunnelRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
I2PTunnelRunner runner = new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
} catch (SocketException ex) {
_log.info(getPrefix(requestId) + "Error trying to connect", ex);
l.log(ex.getMessage());

View File

@ -0,0 +1,41 @@
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
* (c) 2003 - 2004 mihi
*/
package net.i2p.i2ptunnel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.FilterOutputStream;
import java.net.Socket;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
/**
* Override the response with a stream filtering the HTTP headers
* received. Specifically, this makes sure we get Connection: close,
* so the browser knows they really shouldn't try to use persistent
* connections. The HTTP server *should* already be setting this,
* since the HTTP headers sent by the browser specify Connection: close,
* and the server should echo it. However, both broken and malicious
* servers could ignore that, potentially confusing the user.
*
*/
public class I2PTunnelHTTPClientRunner extends I2PTunnelRunner {
public I2PTunnelHTTPClientRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData, List sockList, Runnable onTimeout) {
super(s, i2ps, slock, initialI2PData, sockList, onTimeout);
}
protected OutputStream getSocketOut() throws IOException {
OutputStream raw = super.getSocketOut();
return new HTTPResponseOutputStream(raw);
}
}

View File

@ -4,7 +4,6 @@
package net.i2p.i2ptunnel;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
@ -17,7 +16,6 @@ import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.data.DataHelper;
import net.i2p.util.EventDispatcher;
import net.i2p.util.I2PThread;

View File

@ -3,7 +3,6 @@
*/
package net.i2p.i2ptunnel;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
@ -31,7 +30,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
* Sun's impl of BufferedOutputStream), but that is the streaming
* api's job...
*/
static int MAX_PACKET_SIZE = 1024 * 32;
static int MAX_PACKET_SIZE = 1024 * 4;
static final int NETWORK_BUFFER_SIZE = MAX_PACKET_SIZE;
@ -112,10 +111,13 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
return startedOn;
}
protected InputStream getSocketIn() throws IOException { return s.getInputStream(); }
protected OutputStream getSocketOut() throws IOException { return s.getOutputStream(); }
public void run() {
try {
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream(); // = new BufferedOutputStream(s.getOutputStream(), NETWORK_BUFFER_SIZE);
InputStream in = getSocketIn();
OutputStream out = getSocketOut(); // = new BufferedOutputStream(s.getOutputStream(), NETWORK_BUFFER_SIZE);
i2ps.setSocketErrorListener(this);
InputStream i2pin = i2ps.getInputStream();
OutputStream i2pout = i2ps.getOutputStream(); //new BufferedOutputStream(i2ps.getOutputStream(), MAX_PACKET_SIZE);
@ -216,7 +218,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
this.out = out;
_toI2P = toI2P;
direction = (toI2P ? "toI2P" : "fromI2P");
_cache = ByteCache.getInstance(256, NETWORK_BUFFER_SIZE);
_cache = ByteCache.getInstance(32, NETWORK_BUFFER_SIZE);
setName("StreamForwarder " + _runnerId + "." + (++__forwarderId));
start();
}
@ -281,6 +283,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
//else
// _log.warn("You may ignore this", ex);
} finally {
_cache.release(ba);
if (_log.shouldLog(Log.INFO)) {
_log.info(direction + ": done forwarding between "
+ from + " and " + to);
@ -302,7 +305,6 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
finishLock.notifyAll();
// the main thread will close sockets etc. now
}
_cache.release(ba);
}
}
}

View File

@ -75,10 +75,16 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
I2PClient client = I2PClientFactory.createClient();
Properties props = new Properties();
props.putAll(getTunnel().getClientOptions());
synchronized (slock) {
sockMgr = I2PSocketManagerFactory.createManager(privData, getTunnel().host, Integer.parseInt(getTunnel().port),
props);
while (sockMgr == null) {
synchronized (slock) {
sockMgr = I2PSocketManagerFactory.createManager(privData, getTunnel().host, Integer.parseInt(getTunnel().port),
props);
}
if (sockMgr == null) {
_log.log(Log.CRIT, "Unable to create socket manager");
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
}
}
sockMgr.setName("Server");
getTunnel().addSession(sockMgr.getSession());

View File

@ -1,12 +1,8 @@
package net.i2p.i2ptunnel;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

View File

@ -1,7 +1,5 @@
package net.i2p.i2ptunnel;
import java.io.File;
import java.util.Iterator;
import java.util.Properties;
import java.util.Random;
@ -63,6 +61,8 @@ class WebEditPageFormGenerator {
buf.append("value=\"squid.i2p\" ");
buf.append("/><br />\n");
addStreamingOptions(buf, controller);
buf.append("<hr />Note: the following options are shared across all client tunnels and");
buf.append(" HTTP proxies<br />\n");
@ -86,6 +86,8 @@ class WebEditPageFormGenerator {
buf.append("value=\"").append(controller.getTargetDestination()).append("\" ");
buf.append(" /> (either the hosts.txt name or the full base64 destination)<br />\n");
addStreamingOptions(buf, controller);
buf.append("<hr />Note: the following options are shared across all client tunnels and");
buf.append(" HTTP proxies<br />\n");
@ -124,6 +126,8 @@ class WebEditPageFormGenerator {
buf.append("<input type=\"hidden\" name=\"privKeyGenerate\" value=\"true\" />");
}
addStreamingOptions(buf, controller);
addOptions(buf, controller);
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\">\n");
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
@ -166,6 +170,8 @@ class WebEditPageFormGenerator {
buf.append("<input type=\"hidden\" name=\"privKeyGenerate\" value=\"true\" />");
}
addStreamingOptions(buf, controller);
addOptions(buf, controller);
buf.append("<input type=\"submit\" name=\"action\" value=\"Save\">\n");
buf.append("<input type=\"submit\" name=\"action\" value=\"Remove\">\n");
@ -206,8 +212,9 @@ class WebEditPageFormGenerator {
buf.append(" checked=\"true\" />\n<br />\n");
else
buf.append(" />\n<br />\n");
}
/**
* Generate the fields asking for what port and interface the tunnel should
* listen on.
@ -245,6 +252,46 @@ class WebEditPageFormGenerator {
buf.append("\"><br />\n");
}
private static void addStreamingOptions(StringBuffer buf, TunnelController controller) {
int connectDelay = 0;
int maxWindowSize = -1;
Properties opts = getOptions(controller);
if (opts != null) {
String delay = opts.getProperty("i2p.streaming.connectDelay");
if (delay != null) {
try {
connectDelay = Integer.parseInt(delay);
} catch (NumberFormatException nfe) {
connectDelay = 0;
}
}
String max = opts.getProperty("i2p.streaming.maxWindowSize");
if (max != null) {
try {
maxWindowSize = Integer.parseInt(max);
} catch (NumberFormatException nfe) {
maxWindowSize = -1;
}
}
}
buf.append("<b>Delay connection briefly? </b> ");
buf.append("<input type=\"checkbox\" name=\"connectDelay\" value=\"");
buf.append((connectDelay > 0 ? connectDelay : 1000)).append("\" ");
if (connectDelay > 0)
buf.append("checked=\"true\" ");
buf.append("/> (useful for brief request/response connections)<br />\n");
buf.append("<b>Communication profile:</b>");
buf.append("<select name=\"profile\">");
if (maxWindowSize <= 0)
buf.append("<option value=\"interactive\">Interactive</option><option value=\"bulk\" selected=\"true\">Bulk</option>");
else
buf.append("<option value=\"interactive\" selected=\"true\">Interactive</option><option value=\"bulk\">Bulk</option>");
buf.append("</select><br />\n");
}
/**
* Add fields for customizing the I2PSession options, including helpers for
* tunnel depth and count, as well as I2CP host and port.
@ -255,8 +302,6 @@ class WebEditPageFormGenerator {
private static void addOptions(StringBuffer buf, TunnelController controller) {
int tunnelDepth = 2;
int numTunnels = 2;
int connectDelay = 0;
int maxWindowSize = -1;
Properties opts = getOptions(controller);
if (opts != null) {
String depth = opts.getProperty("inbound.length");
@ -275,22 +320,6 @@ class WebEditPageFormGenerator {
numTunnels = 2;
}
}
String delay = opts.getProperty("i2p.streaming.connectDelay");
if (delay != null) {
try {
connectDelay = Integer.parseInt(delay);
} catch (NumberFormatException nfe) {
connectDelay = 0;
}
}
String max = opts.getProperty("i2p.streaming.maxWindowSize");
if (max != null) {
try {
maxWindowSize = Integer.parseInt(max);
} catch (NumberFormatException nfe) {
maxWindowSize = -1;
}
}
}
buf.append("<b>Tunnel depth:</b> ");
@ -330,21 +359,6 @@ class WebEditPageFormGenerator {
}
buf.append("</select><br />\n");
buf.append("<b>Delay connection briefly? </b> ");
buf.append("<input type=\"checkbox\" name=\"connectDelay\" value=\"");
buf.append((connectDelay > 0 ? connectDelay : 1000)).append("\" ");
if (connectDelay > 0)
buf.append("checked=\"true\" ");
buf.append("/> (useful for brief request/response connections)<br />\n");
buf.append("<b>Communication profile:</b>");
buf.append("<select name=\"profile\">");
if (maxWindowSize <= 0)
buf.append("<option value=\"interactive\">Interactive</option><option value=\"bulk\" selected=\"true\">Bulk</option>");
else
buf.append("<option value=\"interactive\" selected=\"true\">Interactive</option><option value=\"bulk\">Bulk</option>");
buf.append("</select><br />\n");
buf.append("<b>I2CP host:</b> ");
buf.append("<input type=\"text\" name=\"clientHost\" size=\"20\" value=\"");
if ( (controller != null) && (controller.getI2CPHost() != null) )

View File

@ -296,6 +296,10 @@ public class WebEditPageHelper {
cOpt.setProperty("option.inbound.length", _tunnelDepth);
cOpt.setProperty("option.outbound.length", _tunnelDepth);
}
// these are per-proxy settings, not per-session settings, and
// as such don't need to be shared. the values are propogated
// to the current tunnel's settings via cur.setConfig above
/*
if (_connectDelay)
cOpt.setProperty("option.i2p.streaming.connectDelay", "1000");
else
@ -304,6 +308,7 @@ public class WebEditPageHelper {
cOpt.setProperty("option.i2p.streaming.maxWindowSize", "1");
else
cOpt.remove("option.i2p.streaming.maxWindowSize");
*/
if (_name != null) {
cOpt.setProperty("option.inbound.nickname", _name);
cOpt.setProperty("option.outbound.nickname", _name);

View File

@ -14,7 +14,6 @@ import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.DataFormatException;
import net.i2p.i2ptunnel.I2PTunnel;
import net.i2p.util.Log;

View File

@ -4,27 +4,16 @@
*/
package net.i2p.client.streaming;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.I2PSessionListener;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.Log;
/**

View File

@ -36,18 +36,27 @@ public class I2PSocketManagerFactory {
* @return the newly created socket manager, or null if there were errors
*/
public static I2PSocketManager createManager() {
String i2cpHost = System.getProperty(I2PClient.PROP_TCP_HOST, "localhost");
int i2cpPort = 7654;
String i2cpPortStr = System.getProperty(I2PClient.PROP_TCP_PORT);
if (i2cpPortStr != null) {
try {
i2cpPort = Integer.parseInt(i2cpPortStr);
} catch (NumberFormatException nfe) {
// gobble gobble
}
}
return createManager(getHost(), getPort(), System.getProperties());
}
/**
* Create a socket manager using a brand new destination connected to the
* I2CP router on the local machine on the default port (7654).
*
* @return the newly created socket manager, or null if there were errors
*/
public static I2PSocketManager createManager(Properties opts) {
return createManager(getHost(), getPort(), opts);
}
return createManager(i2cpHost, i2cpPort, System.getProperties());
/**
* Create a socket manager using a brand new destination connected to the
* I2CP router on the specified host and port
*
* @return the newly created socket manager, or null if there were errors
*/
public static I2PSocketManager createManager(String host, int port) {
return createManager(host, port, System.getProperties());
}
/**
@ -72,6 +81,26 @@ public class I2PSocketManagerFactory {
}
}
/**
* Create a socket manager using the destination loaded from the given private key
* stream and connected to the default I2CP host and port.
*
* @return the newly created socket manager, or null if there were errors
*/
public static I2PSocketManager createManager(InputStream myPrivateKeyStream) {
return createManager(myPrivateKeyStream, getHost(), getPort(), System.getProperties());
}
/**
* Create a socket manager using the destination loaded from the given private key
* stream and connected to the default I2CP host and port.
*
* @return the newly created socket manager, or null if there were errors
*/
public static I2PSocketManager createManager(InputStream myPrivateKeyStream, Properties opts) {
return createManager(myPrivateKeyStream, getHost(), getPort(), opts);
}
/**
* Create a socket manager using the destination loaded from the given private key
* stream and connected to the I2CP router on the specified machine on the given
@ -154,4 +183,20 @@ public class I2PSocketManagerFactory {
}
}
private static String getHost() {
return System.getProperty(I2PClient.PROP_TCP_HOST, "localhost");
}
private static int getPort() {
int i2cpPort = 7654;
String i2cpPortStr = System.getProperty(I2PClient.PROP_TCP_PORT);
if (i2cpPortStr != null) {
try {
i2cpPort = Integer.parseInt(i2cpPortStr);
} catch (NumberFormatException nfe) {
// gobble gobble
}
}
return i2cpPort;
}
}

View File

@ -1,7 +1,5 @@
package net.i2p.client.streaming;
import java.util.Properties;
/**
* Define the configuration for streaming and verifying data on the socket.
*

View File

@ -1,6 +1,5 @@
package net.i2p.client.streaming;
import java.util.Iterator;
import java.util.Properties;
/**

View File

@ -8,8 +8,6 @@ import java.io.OutputStream;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.util.Random;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.data.Destination;

View File

@ -122,11 +122,12 @@ public class StreamSinkServer {
long written = 0;
int read = 0;
while ( (read = in.read(buf)) != -1) {
_fos.write(buf, 0, read);
//_fos.write(buf, 0, read);
written += read;
if (_log.shouldLog(Log.DEBUG))
_log.debug("read and wrote " + read);
}
_fos.write(("written: [" + written + "]\n").getBytes());
long lifetime = System.currentTimeMillis() - start;
_log.error("Got EOF from client socket [written=" + written + " lifetime=" + lifetime + "]");
} catch (IOException ioe) {
@ -150,7 +151,7 @@ public class StreamSinkServer {
StreamSinkServer server = null;
switch (args.length) {
case 0:
server = new StreamSinkServer("dataDir", "server.key", "localhost", 10001);
server = new StreamSinkServer("dataDir", "server.key", "localhost", 7654);
break;
case 2:
server = new StreamSinkServer(args[0], args[1]);

View File

@ -1,24 +1,12 @@
package net.i2p.client.streaming;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PClientFactory;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.util.Log;
import net.i2p.util.I2PThread;

View File

@ -74,7 +74,9 @@
<arg value="../jsp/" />
</java>
<javac destdir="../jsp/WEB-INF/classes/" srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
<javac debug="true" deprecation="on" source="1.3" target="1.3"
destdir="../jsp/WEB-INF/classes/"
srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
<classpath>
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />

View File

@ -17,11 +17,6 @@ public class ConfigAdvancedHandler extends FormHandler {
private boolean _shouldSave;
private String _config;
public void ConfigNetHandler() {
_shouldSave = false;
_forceRestart = false;
}
protected void processForm() {
if (_shouldSave) {
saveChanges();

View File

@ -1,11 +1,8 @@
package net.i2p.router.web;
import java.io.ByteArrayInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
import net.i2p.util.Log;
/**
* Handler to deal with form submissions from the logging config form and act
@ -21,10 +18,6 @@ public class ConfigLoggingHandler extends FormHandler {
private String _dateFormat;
private String _fileSize;
public void ConfigNetHandler() {
_shouldSave = false;
}
protected void processForm() {
if (_shouldSave) {
saveChanges();

View File

@ -1,14 +1,9 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.TreeSet;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
public class ConfigLoggingHelper {

View File

@ -13,15 +13,10 @@ import java.net.URLConnection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.i2p.util.Log;
import net.i2p.time.Timestamper;
import net.i2p.router.RouterContext;
import net.i2p.router.ClientTunnelSettings;
/**
* Handler to deal with form submissions from the main config form and act
* upon the values.
@ -41,13 +36,6 @@ public class ConfigNetHandler extends FormHandler {
private String _reseedFrom;
private String _sharePct;
public void ConfigNetHandler() {
_guessRequested = false;
_reseedRequested = false;
_saveRequested = false;
_timeSyncEnabled = false;
}
protected void processForm() {
if (_guessRequested) {
guessHostname();

View File

@ -1,16 +1,7 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
import java.util.TreeMap;
import net.i2p.time.Timestamper;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
import net.i2p.router.ClientTunnelSettings;
public class ConfigNetHelper {
private RouterContext _context;

View File

@ -8,7 +8,6 @@ import java.util.Properties;
import java.util.TreeMap;
import net.i2p.data.DataHelper;
import net.i2p.router.ClientTunnelSettings;
import net.i2p.router.Router;
import net.i2p.apps.systray.SysTray;
import net.i2p.apps.systray.UrlLauncher;
@ -20,7 +19,6 @@ import org.tanukisoftware.wrapper.WrapperManager;
*
*/
public class ConfigServiceHandler extends FormHandler {
public void ConfigNetHandler() {}
private class UpdateWrapperManagerTask implements Runnable {
private int _exitCode;

View File

@ -1,15 +1,8 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
import java.util.Set;
import java.util.Properties;
import java.util.TreeMap;
import net.i2p.util.Log;
import net.i2p.data.Destination;
import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings;
@ -49,9 +42,11 @@ public class ConfigTunnelsHelper {
TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(dest.calculateHash());
TunnelPoolSettings out = _context.tunnelManager().getOutboundSettings(dest.calculateHash());
String name = (in != null ? in.getDestinationNickname() : null);
if ( (in == null) || (out == null) ) continue;
String name = in.getDestinationNickname();
if (name == null)
name = (out != null ? out.getDestinationNickname() : null);
name = out.getDestinationNickname();
if (name == null)
name = dest.calculateHash().toBase64().substring(0,6);
@ -110,7 +105,7 @@ public class ConfigTunnelsHelper {
buf.append("</tr>\n");
// tunnel depth variance
buf.append("<tr><td>Variance</td>\n");
buf.append("<tr><td>Randomization</td>\n");
buf.append("<td><select name=\"").append(index).append(".varianceInbound\">\n");
buf.append("<option value=\"0\" ");
if (in.getLengthVariance() == 0) buf.append(" selected=\"true\" ");

View File

@ -1,9 +1,5 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import net.i2p.router.RouterContext;
import net.i2p.util.FileUtil;

View File

@ -3,10 +3,7 @@ package net.i2p.router.web;
import java.util.List;
import java.util.ArrayList;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
import net.i2p.router.ClientTunnelSettings;
/**
* Simple form handler base class - does not depend on servlets or jsp,

View File

@ -1,7 +1,5 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import net.i2p.router.RouterContext;
@ -41,6 +39,22 @@ public class LogsHelper {
return buf.toString();
}
public String getCriticalLogs() {
List msgs = _context.logManager().getBuffer().getMostRecentCriticalMessages();
StringBuffer buf = new StringBuffer(16*1024);
buf.append("<ul>");
buf.append("<code>\n");
for (int i = msgs.size(); i > 0; i--) {
String msg = (String)msgs.get(i - 1);
buf.append("<li>");
buf.append(msg);
buf.append("</li>\n");
}
buf.append("</code></ul>\n");
return buf.toString();
}
public String getServiceLogs() {
String str = FileUtil.readTextFile("wrapper.log", 500, false);
if (str == null)

View File

@ -4,8 +4,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import net.i2p.router.RouterContext;
import net.i2p.router.admin.StatsGenerator;

View File

@ -8,14 +8,12 @@ import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
/**
* Handler to deal with reseed requests. This reseed from the URL

View File

@ -13,10 +13,7 @@ import org.mortbay.jetty.servlet.WebApplicationContext;
import org.mortbay.http.DigestAuthenticator;
import org.mortbay.http.handler.SecurityHandler;
import org.mortbay.http.HashUserRealm;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.SecurityConstraint;
import org.mortbay.http.Authenticator;
import org.mortbay.util.MultiException;
public class RouterConsoleRunner {
private Server _server;
@ -78,7 +75,7 @@ public class RouterConsoleRunner {
private void initialize(WebApplicationContext context) {
String password = getPassword();
if (password != null) {
HashUserRealm realm = new HashUserRealm();
HashUserRealm realm = new HashUserRealm("i2prouter");
realm.put("admin", password);
realm.addUserToRole("admin", "routerAdmin");
context.setRealm(realm);

View File

@ -3,7 +3,6 @@ package net.i2p.router.web;
import java.util.Iterator;
import java.util.Set;
import java.io.ByteArrayOutputStream;
import java.io.Writer;
import net.i2p.data.Hash;

View File

@ -1,10 +1,10 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import net.i2p.data.DataHelper;
@ -70,7 +70,32 @@ public class SummaryHelper {
else
return DataHelper.formatDuration(router.getUptime());
}
private static final DateFormat _fmt = new java.text.SimpleDateFormat("HH:mm:ss", Locale.UK);
public String getTime() {
if (_context == null) return "";
String now = null;
synchronized (_fmt) {
now = _fmt.format(new Date(_context.clock().now()));
}
long ms = _context.clock().getOffset();
if (ms < 60 * 1000) {
return now + " (" + (ms / 1000) + "s)";
} else if (ms < 60 * 60 * 1000) {
return now + " (" + (ms / (60 * 1000)) + "m)";
} else if (ms < 24 * 60 * 60 * 1000) {
return now + " (" + (ms / (60 * 60 * 1000)) + "h)";
} else {
return now + " (" + (ms / (24 * 60 * 60 * 1000)) + "d)";
}
}
public boolean allowReseed() {
return (_context.netDb().getKnownRouters() < 10);
}
/**
* Retrieve amount of used memory.

View File

@ -19,6 +19,9 @@
<h4>Connection logs:</h4><a name="connectionlogs"> </a>
<jsp:getProperty name="logsHelper" property="connectionLogs" />
<hr />
<h4>Critical logs:</h4><a name="criticallogs"> </a>
<jsp:getProperty name="logsHelper" property="criticalLogs" />
<hr />
<h4>Service logs:</h4><a name="servicelogs"> </a>
<jsp:getProperty name="logsHelper" property="serviceLogs" />
</div>

View File

@ -10,6 +10,7 @@
<b>Ident:</b> <jsp:getProperty name="helper" property="ident" /><br />
<b>Version:</b> <jsp:getProperty name="helper" property="version" /><br />
<b>Uptime:</b> <jsp:getProperty name="helper" property="uptime" /><br />
<b>Now:</b> <jsp:getProperty name="helper" property="time" /><br />
<b>Memory:</b> <jsp:getProperty name="helper" property="memory" /><br />
<hr />
@ -23,7 +24,7 @@
if (helper.getActivePeers() <= 0) {
%><b><a href="config.jsp">check your NAT/firewall</a></b><br /><%
}
if (helper.getActiveProfiles() <= 10) { // 10 is the min fallback
if (helper.allowReseed()) {
if ("true".equals(System.getProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false"))) {
out.print(" <i>reseeding</i>");
} else {

View File

@ -17,7 +17,6 @@ import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -221,7 +220,7 @@ public class SAMBridge implements Runnable {
SAMBridge bridge = new SAMBridge(host, port, opts, keyfile);
I2PThread t = new I2PThread(bridge, "SAMListener");
if (Boolean.valueOf(System.getProperty("sam.shutdownOnOOM", "false")).booleanValue()) {
t.addOOMEventListener(new I2PThread.OOMEventListener() {
I2PThread.addOOMEventListener(new I2PThread.OOMEventListener() {
public void outOfMemory(OutOfMemoryError err) {
err.printStackTrace();
System.err.println("OOMed, die die die");

View File

@ -8,9 +8,7 @@ package net.i2p.sam;
*
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;

View File

@ -132,6 +132,8 @@ public class SAMStreamSession {
if (socketMgr == null) {
throw new SAMException("Error creating I2PSocketManager");
}
socketMgr.addDisconnectListener(new DisconnectListener());
forceFlush = Boolean.valueOf(allprops.getProperty(PROP_FORCE_FLUSH, DEFAULT_FORCE_FLUSH)).booleanValue();
@ -156,6 +158,12 @@ public class SAMStreamSession {
t.start();
}
}
private class DisconnectListener implements I2PSocketManager.DisconnectListener {
public void sessionDisconnected() {
close();
}
}
/**
* Get the SAM STREAM session Destination.

View File

@ -15,7 +15,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.Socket;

View File

@ -2,7 +2,6 @@ package net.i2p.sam.client;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Properties;

View File

@ -1,27 +1,19 @@
package net.i2p.sam.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
import net.i2p.util.I2PThread;
import net.i2p.sam.client.SAMEventHandler;
import net.i2p.sam.client.SAMClientEventListenerImpl;
import net.i2p.sam.client.SAMReader;
/**

View File

@ -1,27 +1,17 @@
package net.i2p.sam.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.FileOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
import net.i2p.util.I2PThread;
import net.i2p.sam.client.SAMEventHandler;
import net.i2p.sam.client.SAMClientEventListenerImpl;
import net.i2p.sam.client.SAMReader;
/**

View File

@ -2,19 +2,15 @@ package net.i2p.client.streaming;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.SessionTag;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
@ -57,7 +53,7 @@ public class Connection {
private I2PSocketFull _socket;
/** set to an error cause if the connection could not be established */
private String _connectionError;
private boolean _disconnectScheduled;
private long _disconnectScheduledOn;
private long _lastReceivedOn;
private ActivityTimer _activityTimer;
/** window size when we last saw congestion */
@ -75,8 +71,8 @@ public class Connection {
private long _lifetimeDupMessageSent;
private long _lifetimeDupMessageReceived;
public static final long MAX_RESEND_DELAY = 60*1000;
public static final long MIN_RESEND_DELAY = 30*1000;
public static final long MAX_RESEND_DELAY = 30*1000;
public static final long MIN_RESEND_DELAY = 10*1000;
/** wait up to 5 minutes after disconnection so we can ack/close packets */
public static int DISCONNECT_TIMEOUT = 5*60*1000;
@ -113,7 +109,7 @@ public class Connection {
_connectionManager = manager;
_resetReceived = false;
_connected = true;
_disconnectScheduled = false;
_disconnectScheduledOn = -1;
_lastReceivedOn = -1;
_activityTimer = new ActivityTimer();
_ackSinceCongestion = true;
@ -181,9 +177,15 @@ public class Connection {
}
}
}
void windowAdjusted() {
synchronized (_outboundPackets) {
_outboundPackets.notifyAll();
}
}
void ackImmediately() {
_receiver.send(null, 0, 0);
PacketLocal packet = _receiver.send(null, 0, 0);
//packet.releasePayload();
}
/**
@ -191,6 +193,10 @@ public class Connection {
*
*/
void sendReset() {
if (_disconnectScheduledOn < 0) {
_disconnectScheduledOn = _context.clock().now();
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
}
_resetSent = true;
if (_resetSentOn <= 0)
_resetSentOn = _context.clock().now();
@ -252,7 +258,7 @@ public class Connection {
}
packet.setFlag(Packet.FLAG_DELAY_REQUESTED);
long timeout = (_options.getRTT() < MIN_RESEND_DELAY ? MIN_RESEND_DELAY : _options.getRTT());
long timeout = _options.getRTT() + MIN_RESEND_DELAY;
if (timeout > MAX_RESEND_DELAY)
timeout = MAX_RESEND_DELAY;
if (_log.shouldLog(Log.DEBUG))
@ -382,6 +388,10 @@ public class Connection {
}
void resetReceived() {
if (_disconnectScheduledOn < 0) {
_disconnectScheduledOn = _context.clock().now();
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
}
_resetReceived = true;
MessageOutputStream mos = _outputStream;
MessageInputStream mis = _inputStream;
@ -398,6 +408,7 @@ public class Connection {
public boolean getHardDisconnected() { return _hardDisconnected; }
public boolean getResetSent() { return _resetSent; }
public long getResetSentOn() { return _resetSentOn; }
public long getDisconnectScheduledOn() { return _disconnectScheduledOn; }
void disconnect(boolean cleanDisconnect) {
disconnect(cleanDisconnect, true);
@ -424,8 +435,8 @@ public class Connection {
killOutstandingPackets();
}
if (removeFromConMgr) {
if (!_disconnectScheduled) {
_disconnectScheduled = true;
if (_disconnectScheduledOn < 0) {
_disconnectScheduledOn = _context.clock().now();
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
}
}
@ -445,8 +456,8 @@ public class Connection {
SimpleTimer.getInstance().removeEvent(_activityTimer);
_activityTimer = null;
if (!_disconnectScheduled) {
_disconnectScheduled = true;
if (_disconnectScheduledOn < 0) {
_disconnectScheduledOn = _context.clock().now();
if (_log.shouldLog(Log.INFO))
_log.info("Connection disconnect complete from dead, drop the con "
@ -573,15 +584,23 @@ public class Connection {
}
}
/** how many packets have we sent and the other side has ACKed? */
public long getAckedPackets() { return _ackedPackets; }
public long getCreatedOn() { return _createdOn; }
public long getCloseSentOn() { return _closeSentOn; }
public void setCloseSentOn(long when) { _closeSentOn = when; }
public void setCloseSentOn(long when) {
_closeSentOn = when;
if (_disconnectScheduledOn < 0) {
_disconnectScheduledOn = _context.clock().now();
SimpleTimer.getInstance().addEvent(new DisconnectEvent(), DISCONNECT_TIMEOUT);
}
}
public long getCloseReceivedOn() { return _closeReceivedOn; }
public void setCloseReceivedOn(long when) { _closeReceivedOn = when; }
public void incrementUnackedPacketsReceived() { _unackedPacketsReceived++; }
public int getUnackedPacketsReceived() { return _unackedPacketsReceived; }
/** how many packets have we sent but not yet received an ACK for? */
public int getUnackedPacketsSent() {
synchronized (_outboundPackets) {
return _outboundPackets.size();
@ -850,7 +869,10 @@ public class Connection {
_log.warn("Congestion resending packet " + _packet.getSequenceNum() + ": new windowSize " + newWindowSize
+ ") for " + Connection.this.toString());
// setRTT has its own ceiling
getOptions().setRTT(getOptions().getRTT() + 10*1000);
getOptions().setWindowSize(newWindowSize);
windowAdjusted();
}
}
@ -870,13 +892,15 @@ public class Connection {
_context.sessionKeyManager().failTags(_remotePeer.getPublicKey());
}
if (_log.shouldLog(Log.WARN))
_log.warn("Resend packet " + _packet + " time " + numSends +
" activeResends: " + _activeResends +
" (wsize "
+ newWindowSize + " lifetime "
+ (_context.clock().now() - _packet.getCreatedOn()) + "ms)");
_outboundQueue.enqueue(_packet);
if (numSends - 1 <= _options.getMaxResends()) {
if (_log.shouldLog(Log.WARN))
_log.warn("Resend packet " + _packet + " time " + numSends +
" activeResends: " + _activeResends +
" (wsize "
+ newWindowSize + " lifetime "
+ (_context.clock().now() - _packet.getCreatedOn()) + "ms)");
_outboundQueue.enqueue(_packet);
}
_lastSendTime = _context.clock().now();
@ -889,7 +913,7 @@ public class Connection {
return;
}
if (numSends > _options.getMaxResends()) {
if (numSends - 1 > _options.getMaxResends()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Too many resends");
_packet.cancelled();

View File

@ -1,8 +1,7 @@
package net.i2p.client.streaming;
import java.io.InterruptedIOException;
import java.io.IOException;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.Log;
/**
@ -131,13 +130,19 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver {
}
private PacketLocal buildPacket(Connection con, byte buf[], int off, int size, boolean forceIncrement) {
if (size > Packet.MAX_PAYLOAD_SIZE) throw new IllegalArgumentException("size is too large (" + size + ")");
boolean ackOnly = isAckOnly(con, size);
boolean isFirst = (con.getAckedPackets() <= 0) && (con.getUnackedPacketsSent() <= 0);
PacketLocal packet = new PacketLocal(_context, con.getRemotePeer(), con);
byte data[] = new byte[size];
//ByteArray data = packet.acquirePayload();
ByteArray data = new ByteArray(new byte[size]);
if (size > 0)
System.arraycopy(buf, off, data, 0, size);
System.arraycopy(buf, off, data.getData(), 0, size);
data.setValid(size);
data.setOffset(0);
packet.setPayload(data);
if (ackOnly && !forceIncrement)
if ( (ackOnly && !forceIncrement) && (!isFirst) )
packet.setSequenceNum(0);
else
packet.setSequenceNum(con.getNextOutboundPacketNum());
@ -155,7 +160,8 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver {
packet.setFlag(Packet.FLAG_SIGNATURE_REQUESTED, con.getOptions().getRequireFullySigned());
if ( (!ackOnly) && (packet.getSequenceNum() <= 0) ) {
//if ( (!ackOnly) && (packet.getSequenceNum() <= 0) ) {
if (isFirst) {
packet.setFlag(Packet.FLAG_SYNCHRONIZE);
packet.setOptionalFrom(con.getSession().getMyDestination());
packet.setOptionalMaxSize(con.getOptions().getMaxMessageSize());

View File

@ -328,6 +328,7 @@ public class ConnectionManager {
}
_outboundQueue.enqueue(packet);
packet.releasePayload();
if (blocking) {
synchronized (req) {

View File

@ -81,7 +81,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
super.init(opts);
setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK));
setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 16*1024));
setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 4*1024));
setRTT(getInt(opts, PROP_INITIAL_RTT, 30*1000));
setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1));
setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 1000));
@ -160,6 +160,8 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
public void setWindowSize(int numMsgs) {
if (numMsgs > _maxWindowSize)
numMsgs = _maxWindowSize;
else if (numMsgs <= 0)
numMsgs = 1;
_windowSize = numMsgs;
}

View File

@ -34,6 +34,7 @@ public class ConnectionPacketHandler {
if (!ok) {
if ( (!packet.isFlagSet(Packet.FLAG_RESET)) && (_log.shouldLog(Log.ERROR)) )
_log.error("Packet does NOT verify: " + packet);
packet.releasePayload();
return;
}
@ -47,6 +48,7 @@ public class ConnectionPacketHandler {
if (_log.shouldLog(Log.WARN))
_log.warn("Received a packet after hard disconnect, ignoring: " + packet + " on " + con);
}
packet.releasePayload();
return;
}
@ -72,6 +74,7 @@ public class ConnectionPacketHandler {
+ ": dropping " + packet);
ack(con, packet.getAckThrough(), packet.getNacks(), null, false);
con.getOptions().setChoke(5*1000);
packet.releasePayload();
return;
}
con.getOptions().setChoke(0);
@ -91,6 +94,7 @@ public class ConnectionPacketHandler {
con.closeReceived();
boolean fastAck = false;
boolean ackOnly = false;
if (isNew) {
con.incrementUnackedPacketsReceived();
@ -127,11 +131,19 @@ public class ConnectionPacketHandler {
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("ACK only packet received: " + packet);
ackOnly = true;
}
}
}
fastAck = fastAck || ack(con, packet.getAckThrough(), packet.getNacks(), packet, isNew);
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE) &&
((packet.getSendStreamId() == null) ||
DataHelper.eq(packet.getSendStreamId(), Packet.STREAM_ID_UNKNOWN) ) ) {
// don't honor the ACK 0 in SYN packets received when the other side
// has obviously not seen our messages
} else {
fastAck = fastAck || ack(con, packet.getAckThrough(), packet.getNacks(), packet, isNew);
}
con.eventOccurred();
if (fastAck) {
if (con.getLastSendTime() + 2000 < _context.clock().now()) {
@ -140,6 +152,11 @@ public class ConnectionPacketHandler {
con.ackImmediately();
}
}
if (ackOnly || !isNew) {
// non-ack message payloads are queued in the MessageInputStream
packet.releasePayload();
}
}
private boolean ack(Connection con, long ackThrough, long nacks[], Packet packet, boolean isNew) {
@ -199,6 +216,8 @@ public class ConnectionPacketHandler {
+ con.getLastCongestionSeenAt() + " (#resends: " + numResends
+ ") for " + con);
// setRTT has its own ceiling
con.getOptions().setRTT(con.getOptions().getRTT() + 10*1000);
con.getOptions().setWindowSize(oldSize);
congested = true;
@ -224,6 +243,9 @@ public class ConnectionPacketHandler {
newWindowSize += 1;
}
}
if (newWindowSize <= 0)
newWindowSize = 1;
if (_log.shouldLog(Log.DEBUG))
_log.debug("New window size " + newWindowSize + "/" + oldWindow + " congestionSeenAt: "
@ -233,6 +255,7 @@ public class ConnectionPacketHandler {
con.setCongestionWindowEnd(newWindowSize + lowest);
}
con.windowAdjusted();
return congested;
}
@ -255,11 +278,15 @@ public class ConnectionPacketHandler {
con.setRemotePeer(packet.getOptionalFrom());
return true;
} else {
// neither RST nor SYN and we dont have the stream id yet? nuh uh
if (_log.shouldLog(Log.WARN))
_log.warn("Packet without RST or SYN where we dont know stream ID: "
+ packet);
return false;
// neither RST nor SYN and we dont have the stream id yet?
if (packet.getSequenceNum() <= 2) {
return true;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Packet without RST or SYN where we dont know stream ID: "
+ packet);
return false;
}
}
} else {
if (!DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) {

View File

@ -1,6 +1,5 @@
package net.i2p.client.streaming;
import java.net.ConnectException;
import net.i2p.I2PException;
/**

View File

@ -1,15 +1,8 @@
package net.i2p.client.streaming;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
@ -17,7 +10,6 @@ import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.I2PSessionListener;
import net.i2p.data.Destination;
import net.i2p.util.Log;
@ -105,7 +97,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
}
public I2PSocket receiveSocket() throws I2PException {
if (_session.isClosed()) throw new I2PException("Session closed");
verifySession();
Connection con = _connectionManager.getConnectionHandler().accept(-1);
if (_log.shouldLog(Log.DEBUG))
_log.debug("receiveSocket() called: " + con);
@ -149,6 +141,12 @@ public class I2PSocketManagerFull implements I2PSocketManager {
return _serverSocket;
}
private void verifySession() throws I2PException {
if (!_connectionManager.getSession().isClosed())
return;
_connectionManager.getSession().connect();
}
/**
* Create a new connected socket (block until the socket is created)
*
@ -160,8 +158,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
*/
public I2PSocket connect(Destination peer, I2PSocketOptions options)
throws I2PException, NoRouteToHostException {
if (_connectionManager.getSession().isClosed())
throw new I2PException("Session is closed");
verifySession();
if (options == null)
options = _defaultOptions;
ConnectionOptions opts = null;

View File

@ -92,7 +92,9 @@ public class MessageHandler implements I2PSessionListener {
*/
public void errorOccurred(I2PSession session, String message, Throwable error) {
if (_log.shouldLog(Log.ERROR))
_log.error("error occurred: " + message, error);
_log.error("error occurred: " + message + "- " + error.getMessage());
if (_log.shouldLog(Log.WARN))
_log.warn("cause", error);
//_manager.disconnectAllHard();
}

View File

@ -2,8 +2,6 @@ package net.i2p.client.streaming;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -13,6 +11,7 @@ import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
/**
@ -52,6 +51,7 @@ public class MessageInputStream extends InputStream {
private int _readTimeout;
private IOException _streamError;
private long _readTotal;
private ByteCache _cache;
private byte[] _oneByte = new byte[1];
@ -70,6 +70,7 @@ public class MessageInputStream extends InputStream {
_dataLock = new Object();
_closeReceived = false;
_locallyClosed = false;
_cache = ByteCache.getInstance(128, Packet.MAX_PAYLOAD_SIZE);
}
/** What is the highest block ID we've completely received through? */
@ -166,7 +167,7 @@ public class MessageInputStream extends InputStream {
buf.append("Close received, ready bytes: ");
long available = 0;
for (int i = 0; i < _readyDataBlocks.size(); i++)
available += ((ByteArray)_readyDataBlocks.get(i)).getData().length;
available += ((ByteArray)_readyDataBlocks.get(i)).getValid();
available -= _readyDataBlockIndex;
buf.append(available);
buf.append(" blocks: ").append(_readyDataBlocks.size());
@ -178,8 +179,8 @@ public class MessageInputStream extends InputStream {
ByteArray ba = (ByteArray)_notYetReadyBlocks.get(id);
buf.append(id).append(" ");
if (ba.getData() != null)
notAvailable += ba.getData().length;
if (ba != null)
notAvailable += ba.getValid();
}
buf.append("not ready bytes: ").append(notAvailable);
@ -198,10 +199,10 @@ public class MessageInputStream extends InputStream {
*
* @return true if this is a new packet, false if it is a dup
*/
public boolean messageReceived(long messageId, byte payload[]) {
public boolean messageReceived(long messageId, ByteArray payload) {
synchronized (_dataLock) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("received " + messageId + " with " + payload.length);
_log.debug("received " + messageId + " with " + payload.getValid());
if (messageId <= _highestReadyBlockId) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("ignoring dup message " + messageId);
@ -212,17 +213,17 @@ public class MessageInputStream extends InputStream {
_highestBlockId = messageId;
if (_highestReadyBlockId + 1 == messageId) {
if (!_locallyClosed && payload.length > 0) {
if (!_locallyClosed && payload.getValid() > 0) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("accepting bytes as ready: " + payload.length);
_readyDataBlocks.add(new ByteArray(payload));
_log.debug("accepting bytes as ready: " + payload.getValid());
_readyDataBlocks.add(payload);
}
_highestReadyBlockId = messageId;
long cur = _highestReadyBlockId + 1;
// now pull in any previously pending blocks
while (_notYetReadyBlocks.containsKey(new Long(cur))) {
ByteArray ba = (ByteArray)_notYetReadyBlocks.remove(new Long(cur));
if ( (ba != null) && (ba.getData() != null) && (ba.getData().length > 0) ) {
if ( (ba != null) && (ba.getData() != null) && (ba.getValid() > 0) ) {
_readyDataBlocks.add(ba);
}
@ -238,7 +239,7 @@ public class MessageInputStream extends InputStream {
if (_locallyClosed) // dont need the payload, just the msgId in order
_notYetReadyBlocks.put(new Long(messageId), new ByteArray(null));
else
_notYetReadyBlocks.put(new Long(messageId), new ByteArray(payload));
_notYetReadyBlocks.put(new Long(messageId), payload);
_dataLock.notifyAll();
}
}
@ -324,21 +325,25 @@ public class MessageInputStream extends InputStream {
} else {
// either was already ready, or we wait()ed and it arrived
ByteArray cur = (ByteArray)_readyDataBlocks.get(0);
byte rv = cur.getData()[_readyDataBlockIndex];
byte rv = cur.getData()[cur.getOffset()+_readyDataBlockIndex];
_readyDataBlockIndex++;
if (cur.getData().length <= _readyDataBlockIndex) {
boolean removed = false;
if (cur.getValid() <= _readyDataBlockIndex) {
_readyDataBlockIndex = 0;
_readyDataBlocks.remove(0);
removed = true;
}
_readTotal++;
target[offset + i] = rv; // rv < 0 ? rv + 256 : rv
if ( (_readyDataBlockIndex <= 3) || (_readyDataBlockIndex >= cur.getData().length - 5) ) {
if ( (_readyDataBlockIndex <= 3) || (_readyDataBlockIndex >= cur.getValid() - 5) ) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("read(...," + offset+", " + length+ ")[" + i
+ "] after ready data: readyDataBlockIndex=" + _readyDataBlockIndex
+ " readyBlocks=" + _readyDataBlocks.size()
+ " readTotal=" + _readTotal);
}
//if (removed)
// _cache.release(cur);
}
} // for (int i = 0; i < length; i++) {
} // synchronized (_dataLock)
@ -357,9 +362,9 @@ public class MessageInputStream extends InputStream {
for (int i = 0; i < _readyDataBlocks.size(); i++) {
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
if (i == 0)
numBytes += cur.getData().length - _readyDataBlockIndex;
numBytes += cur.getValid() - _readyDataBlockIndex;
else
numBytes += cur.getData().length;
numBytes += cur.getValid();
}
}
if (_log.shouldLog(Log.DEBUG))
@ -380,13 +385,13 @@ public class MessageInputStream extends InputStream {
for (int i = 0; i < _readyDataBlocks.size(); i++) {
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
if (i == 0)
numBytes += cur.getData().length - _readyDataBlockIndex;
numBytes += cur.getValid() - _readyDataBlockIndex;
else
numBytes += cur.getData().length;
numBytes += cur.getValid();
}
for (Iterator iter = _notYetReadyBlocks.values().iterator(); iter.hasNext(); ) {
ByteArray cur = (ByteArray)iter.next();
numBytes += cur.getData().length;
numBytes += cur.getValid();
}
return numBytes;
}
@ -399,9 +404,9 @@ public class MessageInputStream extends InputStream {
for (int i = 0; i < _readyDataBlocks.size(); i++) {
ByteArray cur = (ByteArray)_readyDataBlocks.get(i);
if (i == 0)
numBytes += cur.getData().length - _readyDataBlockIndex;
numBytes += cur.getValid() - _readyDataBlockIndex;
else
numBytes += cur.getData().length;
numBytes += cur.getValid();
}
return numBytes;
}
@ -409,6 +414,8 @@ public class MessageInputStream extends InputStream {
public void close() {
synchronized (_dataLock) {
//while (_readyDataBlocks.size() > 0)
// _cache.release((ByteArray)_readyDataBlocks.remove(0));
_readyDataBlocks.clear();
// we don't need the data, but we do need to keep track of the messageIds
@ -416,6 +423,7 @@ public class MessageInputStream extends InputStream {
for (Iterator iter = _notYetReadyBlocks.values().iterator(); iter.hasNext(); ) {
ByteArray ba = (ByteArray)iter.next();
ba.setData(null);
//_cache.release(ba);
}
_locallyClosed = true;
_dataLock.notifyAll();

View File

@ -3,11 +3,13 @@ package net.i2p.client.streaming;
import java.util.Arrays;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Signature;
import net.i2p.data.SigningPrivateKey;
import net.i2p.util.ByteCache;
/**
* Contain a single packet transferred as part of a streaming connection.
@ -56,12 +58,13 @@ public class Packet {
private long _nacks[];
private int _resendDelay;
private int _flags;
private byte _payload[];
private ByteArray _payload;
// the next four are set only if the flags say so
private Signature _optionSignature;
private Destination _optionFrom;
private int _optionDelay;
private int _optionMaxSize;
private ByteCache _cache;
/**
* The receiveStreamId will be set to this when the packet doesn't know
@ -135,6 +138,10 @@ public class Packet {
public static final int DEFAULT_MAX_SIZE = 32*1024;
private static final int MAX_DELAY_REQUEST = 65535;
public Packet() {
_cache = ByteCache.getInstance(128, MAX_PAYLOAD_SIZE);
}
/** what stream is this packet a part of? */
public byte[] getSendStreamId() {
@ -200,14 +207,28 @@ public class Packet {
public static final int MAX_PAYLOAD_SIZE = 32*1024;
/** get the actual payload of the message. may be null */
public byte[] getPayload() { return _payload; }
public void setPayload(byte payload[]) {
public ByteArray getPayload() { return _payload; }
public void setPayload(ByteArray payload) {
//if ( (_payload != null) && (_payload != payload) )
// _cache.release(_payload);
_payload = payload;
if ( (payload != null) && (payload.length > MAX_PAYLOAD_SIZE) )
throw new IllegalArgumentException("Too large payload: " + payload.length);
if ( (payload != null) && (payload.getValid() > MAX_PAYLOAD_SIZE) )
throw new IllegalArgumentException("Too large payload: " + payload.getValid());
}
public int getPayloadSize() {
return (_payload == null ? 0 : _payload.length);
return (_payload == null ? 0 : _payload.getValid());
}
public void releasePayload() {
//if (_payload != null)
// _cache.release(_payload);
_payload = null;
}
public ByteArray acquirePayload() {
ByteArray old = _payload;
_payload = new ByteArray(new byte[Packet.MAX_PAYLOAD_SIZE]); //_cache.acquire();
//if (old != null)
// _cache.release(old);
return _payload;
}
/** is a particular flag set on this packet? */
@ -340,12 +361,12 @@ public class Packet {
if (_payload != null) {
try {
System.arraycopy(_payload, 0, buffer, cur, _payload.length);
System.arraycopy(_payload.getData(), _payload.getOffset(), buffer, cur, _payload.getValid());
} catch (ArrayIndexOutOfBoundsException aioobe) {
System.err.println("payload.length: " + _payload.length + " buffer.length: " + buffer.length + " cur: " + cur);
System.err.println("payload.length: " + _payload.getValid() + " buffer.length: " + buffer.length + " cur: " + cur);
throw aioobe;
}
cur += _payload.length;
cur += _payload.getValid();
}
return cur - offset;
@ -382,7 +403,7 @@ public class Packet {
size += 2; // option size
if (_payload != null) {
size += _payload.length;
size += _payload.getValid();
}
return size;
@ -445,8 +466,10 @@ public class Packet {
throw new IllegalArgumentException("length: " + length + " offset: " + offset + " begin: " + payloadBegin);
// skip ahead to the payload
_payload = new byte[payloadSize];
System.arraycopy(buffer, payloadBegin, _payload, 0, payloadSize);
_payload = new ByteArray(new byte[payloadSize]); //_cache.acquire();
System.arraycopy(buffer, payloadBegin, _payload.getData(), 0, payloadSize);
_payload.setValid(payloadSize);
_payload.setOffset(0);
// ok now lets go back and deal with the options
if (isFlagSet(FLAG_DELAY_REQUESTED)) {
@ -529,6 +552,11 @@ public class Packet {
}
public String toString() {
StringBuffer str = formatAsString();
return str.toString();
}
protected StringBuffer formatAsString() {
StringBuffer buf = new StringBuffer(64);
buf.append(toId(_sendStreamId));
//buf.append("<-->");
@ -545,9 +573,9 @@ public class Packet {
buf.append(" ").append(_nacks[i]);
}
}
if ( (_payload != null) && (_payload.length > 0) )
buf.append(" data: ").append(_payload.length);
return buf.toString();
if ( (_payload != null) && (_payload.getValid() > 0) )
buf.append(" data: ").append(_payload.getValid());
return buf;
}
private static final String toId(byte id[]) {

View File

@ -106,12 +106,16 @@ public class PacketHandler {
private static final SimpleDateFormat _fmt = new SimpleDateFormat("HH:mm:ss.SSS");
void displayPacket(Packet packet, String prefix, String suffix) {
String msg = null;
if (!_log.shouldLog(Log.DEBUG)) return;
StringBuffer buf = new StringBuffer(256);
synchronized (_fmt) {
msg = _fmt.format(new Date()) + ": " + prefix + " " + packet.toString() + (suffix != null ? " " + suffix : "");
buf.append(_fmt.format(new Date()));
}
if (_log.shouldLog(Log.DEBUG))
System.out.println(msg);
buf.append(": ").append(prefix).append(" ");
buf.append(packet.toString());
if (suffix != null)
buf.append(" ").append(suffix);
System.out.println(buf.toString());
}
private void receiveKnownCon(Connection con, Packet packet) {
@ -137,28 +141,33 @@ public class PacketHandler {
if (_log.shouldLog(Log.WARN))
_log.warn("Received forged reset for " + con, ie);
}
} else if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
} else {
if ( (con.getSendStreamId() == null) ||
(DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) ) {
byte oldId[] =con.getSendStreamId();
// con fully established, w00t
con.setSendStreamId(packet.getReceiveStreamId());
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) // con fully established, w00t
con.setSendStreamId(packet.getReceiveStreamId());
try {
con.getPacketHandler().receivePacket(packet, con);
} catch (I2PException ie) {
if (_log.shouldLog(Log.WARN))
_log.warn("Received forged syn for " + con, ie);
_log.warn("Received forged packet for " + con + ": " + packet, ie);
con.setSendStreamId(oldId);
}
} else {
} else if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Receive a syn packet with the wrong IDs, sending reset: " + packet);
sendReset(packet);
packet.releasePayload();
} else {
if (!con.getResetSent()) {
// someone is sending us a packet on the wrong stream
if (_log.shouldLog(Log.WARN))
_log.warn("Received a packet on the wrong stream: " + packet + " connection: " + con);
}
packet.releasePayload();
}
} else {
// someone is sending us a packet on the wrong stream
if (_log.shouldLog(Log.WARN))
_log.warn("Received a packet on the wrong stream: " + packet + " connection: " + con);
}
}
}
@ -184,6 +193,7 @@ public class PacketHandler {
if (_log.shouldLog(Log.WARN))
_log.warn("Echo packet received with no stream IDs: " + packet);
}
packet.releasePayload();
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Packet received on an unknown stream (and not an ECHO): " + packet);
@ -218,6 +228,7 @@ public class PacketHandler {
+ buf.toString() + " sendId: "
+ (sendId != null ? Base64.encode(sendId) : " unknown"));
}
packet.releasePayload();
}
}
}

View File

@ -5,6 +5,7 @@ import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.Destination;
import net.i2p.data.SessionKey;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
@ -26,6 +27,7 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
private long _ackOn;
private long _cancelledOn;
private SimpleTimer.TimedEvent _resendEvent;
private ByteCache _cache = ByteCache.getInstance(128, MAX_PAYLOAD_SIZE);
public PacketLocal(I2PAppContext ctx, Destination to) {
this(ctx, to, null);
@ -79,10 +81,11 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
_numSends++;
_lastSend = _context.clock().now();
}
public void ackReceived() {
public void ackReceived() {
synchronized (this) {
if (_ackOn <= 0)
_ackOn = _context.clock().now();
_ackOn = _context.clock().now();
releasePayload();
notifyAll();
}
SimpleTimer.getInstance().removeEvent(_resendEvent);
@ -90,6 +93,7 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
public void cancelled() {
synchronized (this) {
_cancelledOn = _context.clock().now();
releasePayload();
notifyAll();
}
SimpleTimer.getInstance().removeEvent(_resendEvent);
@ -110,16 +114,44 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
public void setResendPacketEvent(SimpleTimer.TimedEvent evt) { _resendEvent = evt; }
public String toString() {
String str = super.toString();
public StringBuffer formatAsString() {
StringBuffer buf = super.formatAsString();
Connection con = _connection;
if (con != null)
buf.append(" rtt ").append(con.getOptions().getRTT());
if ( (_tagsSent != null) && (_tagsSent.size() > 0) )
str = str + " with tags";
buf.append(" with tags");
if (_ackOn > 0)
return str + " ack after " + getAckTime() + (_numSends <= 1 ? "" : " sent " + _numSends + " times");
else
return str + (_numSends <= 1 ? "" : " sent " + _numSends + " times");
buf.append(" ack after ").append(getAckTime());
if (_numSends > 1)
buf.append(" sent ").append(_numSends).append(" times");
if (isFlagSet(Packet.FLAG_SYNCHRONIZE) ||
isFlagSet(Packet.FLAG_CLOSE) ||
isFlagSet(Packet.FLAG_RESET)) {
if (con != null) {
buf.append(" from ");
Destination local = con.getSession().getMyDestination();
if (local != null)
buf.append(local.calculateHash().toBase64().substring(0,4));
else
buf.append("unknown");
buf.append(" to ");
Destination remote = con.getRemotePeer();
if (remote != null)
buf.append(remote.calculateHash().toBase64().substring(0,4));
else
buf.append("unknown");
}
}
return buf;
}
public void waitForAccept(int maxWaitMs) {
@ -131,10 +163,12 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
int window = _connection.getOptions().getWindowSize();
boolean accepted = _connection.packetSendChoke(maxWaitMs);
long after = _context.clock().now();
if (accepted)
if (accepted) {
_acceptedOn = after;
else
} else {
_acceptedOn = -1;
releasePayload();
}
int afterQueued = _connection.getUnackedPacketsSent();
if ( (after - before > 1000) && (_log.shouldLog(Log.DEBUG)) )
_log.debug("Took " + (after-before) + "ms to get "
@ -149,11 +183,12 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
long expiration = _context.clock().now()+maxWaitMs;
while (true) {
long timeRemaining = expiration - _context.clock().now();
if ( (timeRemaining <= 0) && (maxWaitMs > 0) ) return;
if ( (timeRemaining <= 0) && (maxWaitMs > 0) ) break;
try {
synchronized (this) {
if (_ackOn > 0) return;
if (_cancelledOn > 0) return;
if (_ackOn > 0) break;
if (_cancelledOn > 0) break;
if (!_connection.getIsConnected()) break;
if (timeRemaining > 60*1000)
timeRemaining = 60*1000;
else if (timeRemaining <= 0)
@ -162,6 +197,8 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
}
} catch (InterruptedException ie) {}
}
if (!writeSuccessful())
releasePayload();
}
public boolean writeAccepted() { return _acceptedOn > 0 && _cancelledOn <= 0; }

View File

@ -1,6 +1,5 @@
package net.i2p.client.streaming;
import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
@ -49,12 +48,16 @@ class PacketQueue {
tagsSent = new HashSet(0);
// cache this from before sendMessage
String conStr = (packet.getConnection() != null ? packet.getConnection().toString() : "");
String conStr = null;
if (_log.shouldLog(Log.DEBUG))
conStr = (packet.getConnection() != null ? packet.getConnection().toString() : "");
if (packet.getAckTime() > 0) {
_log.debug("Not resending " + packet);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Not resending " + packet);
return;
} else {
_log.debug("Sending... " + packet);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending... " + packet);
}
ByteArray ba = _cache.acquire();
@ -125,6 +128,17 @@ class PacketQueue {
String suffix = (c != null ? "wsize " + c.getOptions().getWindowSize() : null);
_connectionManager.getPacketHandler().displayPacket(packet, "SEND", suffix);
}
if ( (packet.getSequenceNum() == 0) && (!packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) ) {
// ack only, so release it asap
packet.releasePayload();
} else if (packet.isFlagSet(Packet.FLAG_ECHO) && !packet.isFlagSet(Packet.FLAG_SIGNATURE_INCLUDED) ) {
// pong
packet.releasePayload();
} else if (packet.isFlagSet(Packet.FLAG_RESET)) {
// reset
packet.releasePayload();
}
}
}

View File

@ -38,7 +38,7 @@ class SchedulerConnectedBulk extends SchedulerImpl {
public boolean accept(Connection con) {
boolean ok = (con != null) &&
(con.getAckedPackets() > 0) &&
(con.getHighestAckedThrough() >= 0) &&
(con.getOptions().getProfile() == ConnectionOptions.PROFILE_BULK) &&
(!con.getResetReceived()) &&
( (con.getCloseSentOn() <= 0) || (con.getCloseReceivedOn() <= 0) );

View File

@ -39,7 +39,7 @@ class SchedulerConnecting extends SchedulerImpl {
boolean notYetConnected = (con.getIsConnected()) &&
//(con.getSendStreamId() == null) && // not null on recv
(con.getLastSendId() >= 0) &&
(con.getAckedPackets() <= 0) &&
(con.getHighestAckedThrough() < 0) &&
(!con.getResetReceived());
return notYetConnected;
}

View File

@ -32,19 +32,13 @@ class SchedulerDead extends SchedulerImpl {
public boolean accept(Connection con) {
if (con == null) return false;
long timeSinceClose = _context.clock().now() - con.getCloseSentOn();
if (con.getResetSent())
timeSinceClose = _context.clock().now() - con.getResetSentOn();
boolean nothingLeftToDo = (con.getCloseSentOn() > 0) &&
(con.getCloseReceivedOn() > 0) &&
(con.getUnackedPacketsReceived() <= 0) &&
(con.getUnackedPacketsSent() <= 0) &&
(con.getResetSent()) &&
long timeSinceClose = _context.clock().now() - con.getDisconnectScheduledOn();
boolean nothingLeftToDo = (con.getDisconnectScheduledOn() > 0) &&
(timeSinceClose >= Connection.DISCONNECT_TIMEOUT);
boolean timedOut = (con.getOptions().getConnectTimeout() < con.getLifetime()) &&
con.getSendStreamId() == null &&
con.getLifetime() >= Connection.DISCONNECT_TIMEOUT;
return con.getResetReceived() || nothingLeftToDo || timedOut;
return nothingLeftToDo || timedOut;
}
public void eventOccurred(Connection con) {

View File

@ -38,7 +38,7 @@ class SchedulerHardDisconnected extends SchedulerImpl {
timeSinceClose = _context.clock().now() - con.getResetSentOn();
boolean ok = (con.getHardDisconnected() || con.getResetSent()) &&
(timeSinceClose < Connection.DISCONNECT_TIMEOUT);
return ok;
return ok || con.getResetReceived();
}
public void eventOccurred(Connection con) {

View File

@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.Collections;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
@ -29,7 +30,7 @@ public class MessageInputStreamTest {
for (int i = 0; i < orig.length / 1024; i++) {
byte msg[] = new byte[1024];
System.arraycopy(orig, i*1024, msg, 0, 1024);
in.messageReceived(i, msg);
in.messageReceived(i, new ByteArray(msg));
}
byte read[] = new byte[orig.length];
@ -59,7 +60,7 @@ public class MessageInputStreamTest {
byte msg[] = new byte[1024];
Integer cur = (Integer)order.get(i);
System.arraycopy(orig, cur.intValue()*1024, msg, 0, 1024);
in.messageReceived(cur.intValue(), msg);
in.messageReceived(cur.intValue(), new ByteArray(msg));
_log.debug("Injecting " + cur);
}
@ -91,7 +92,7 @@ public class MessageInputStreamTest {
byte msg[] = new byte[1024];
Integer cur = (Integer)order.get(i);
System.arraycopy(orig, cur.intValue()*1024, msg, 0, 1024);
in.messageReceived(cur.intValue(), msg);
in.messageReceived(cur.intValue(), new ByteArray(msg));
_log.debug("Injecting " + cur);
}
}
@ -126,7 +127,7 @@ public class MessageInputStreamTest {
byte msg[] = new byte[1024];
Integer cur = (Integer)order.get(i);
System.arraycopy(orig, cur.intValue()*1024, msg, 0, 1024);
in.messageReceived(cur.intValue(), msg);
in.messageReceived(cur.intValue(), new ByteArray(msg));
_log.debug("Injecting " + cur);
try {

View File

@ -34,8 +34,10 @@
</target>
<target name="clean">
<delete>
<fileset dir="src/WEB-INF/classes/" includes="**/*.class, susimail.war" />
<fileset dir="src/WEB-INF/classes/" includes="**/*.class" />
</delete>
<delete dir="src/WEB-INF/classes/i2p"/>
<delete file="susimail.war"/>
</target>
<target name="cleandep" depends="clean" />
<target name="distclean" depends="clean" />

96
apps/susimail/src/css.css Normal file
View File

@ -0,0 +1,96 @@
body {
background-color:white;
}
li {
font-family:Verdana,Tahoma,Arial,Helvetica;
color:black;
line-height:12pt;
font-size:10pt;
margin-left:5mm;
margin-right:5mm;
}
p {
font-family:Verdana,Tahoma,Arial,Helvetica;
color:black;
line-height:12pt;
margin-left:5mm;
margin-right:5mm;
font-size:10pt;
}
p.hl {
font-size:12pt;
letter-spacing:2pt;
line-height:18pt;
font-weight:bold;
}
p.text {
margin-left:10mm;
margin-right:10mm;
}
p.error {
color:#ff0000;
}
p.info {
color:#327BBF;
}
span.coloured {
color:#327BBF;
}
p.footer {
margin-left:10mm;
margin-right:10mm;
font-size:8pt;
line-height:10pt;
}
p.mailbody {
font-family:Courier-Fixed;
margin-left:1cm;
margin-right:1cm;
}
a {
color:#327BBF;
text-decoration:none;
}
a:hover {
text-decoration:underline;
}
td {
font-family:Verdana,Tahoma,Arial,Helvetica;
color:black;
line-height:12pt;
margin-left:5mm;
margin-right:5mm;
font-size:10pt;
}
tr.list0 {
background-color:#e0e0e0;
}
tr.list1 {
background-color:#ffffff;
}
table.noborder {
margin-left:0mm;
margin-top:0mm;
margin-right:0mm;
}
pre {
font-family:Courier-Fixed;
margin-left:1cm;
margin-right:1cm;
}

View File

@ -19,11 +19,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.5 $
* $Revision: 1.1 $
*/
package i2p.susi.webmail;
import i2p.susi.debug.Debug;
import i2p.susi.util.Config;
import i2p.susi.util.ReadBuffer;
import i2p.susi.webmail.encoding.Encoding;

View File

@ -19,13 +19,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.3 $
* $Revision: 1.1 $
*/
package i2p.susi.webmail;
import java.util.Hashtable;
import i2p.susi.debug.Debug;
import i2p.susi.webmail.pop3.POP3MailBox;
/**

View File

@ -10,8 +10,6 @@
package net.i2p.apps.systray;
import java.awt.Frame;
import java.io.File;
import snoozesoft.systray4j.SysTrayMenu;
import snoozesoft.systray4j.SysTrayMenuEvent;
import snoozesoft.systray4j.SysTrayMenuIcon;

View File

@ -193,6 +193,7 @@
<copy file="installer/resources/osid" todir="pkg-temp/" />
<copy file="installer/resources/postinstall.bat" todir="pkg-temp/" />
<copy file="installer/resources/postinstall.sh" todir="pkg-temp/" />
<copy file="installer/resources/startRouter.sh" todir="pkg-temp/" />
<copy file="installer/resources/systray.config" todir="pkg-temp/" />
<!-- <copy file="installer/resources/uninstall_i2p_service_unix" todir="pkg-temp/" /> -->
<copy file="installer/resources/uninstall_i2p_service_winnt.bat" todir="pkg-temp/" />
@ -250,15 +251,19 @@
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
<!-- for the i2p 0.5 release, push jetty 5.2.1 -->
<!--
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
<copy file="build/commons-logging.jar" todir="pkg-temp/lib/" />
<copy file="build/commons-el.jar" todir="pkg-temp/lib/" />
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
<copy file="build/javax.servlet.jar" todir="pkg-temp/lib/" />
-->
<!-- requires commons-* to be added to the classpath (boo, hiss) -->
<!--
<copy file="installer/resources/wrapper.config" todir="pkg-temp/" />
<touch file="pkg-temp/wrapper.config.updated" />
-->
<copy file="build/i2ptunnel.war" todir="pkg-temp/webapps/" />
<copy file="build/routerconsole.war" todir="pkg-temp/webapps/" />

View File

@ -14,8 +14,8 @@ package net.i2p;
*
*/
public class CoreVersion {
public final static String ID = "$Revision: 1.27 $ $Date: 2005/02/16 17:23:50 $";
public final static String VERSION = "0.5";
public final static String ID = "$Revision: 1.30 $ $Date: 2005/03/06 19:07:28 $";
public final static String VERSION = "0.5.0.3";
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);

View File

@ -30,7 +30,6 @@ import net.i2p.data.i2cp.ReportAbuseMessage;
import net.i2p.data.i2cp.SendMessageMessage;
import net.i2p.data.i2cp.SessionConfig;
import net.i2p.util.Log;
import net.i2p.util.RandomSource;
/**
* Produce the various messages the session needs to send to the router.
@ -53,13 +52,17 @@ class I2CPMessageProducer {
CreateSessionMessage msg = new CreateSessionMessage();
SessionConfig cfg = new SessionConfig(session.getMyDestination());
cfg.setOptions(session.getOptions());
if (_log.shouldLog(Log.DEBUG)) _log.debug("config created");
try {
cfg.signSessionConfig(session.getPrivateKey());
} catch (DataFormatException dfe) {
throw new I2PSessionException("Unable to sign the session config", dfe);
}
if (_log.shouldLog(Log.DEBUG)) _log.debug("config signed");
msg.setSessionConfig(cfg);
if (_log.shouldLog(Log.DEBUG)) _log.debug("config loaded into message");
session.sendMessage(msg);
if (_log.shouldLog(Log.DEBUG)) _log.debug("config message sent");
}
/**

View File

@ -39,6 +39,7 @@ import net.i2p.data.i2cp.MessagePayloadMessage;
import net.i2p.data.i2cp.SessionId;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
/**
* Implementation of an I2P session running over TCP. This class is NOT thread safe -
@ -78,7 +79,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
/** class that generates new messages */
protected I2CPMessageProducer _producer;
/** map of integer --> MessagePayloadMessage */
Map _availableMessages;
private Map _availableMessages;
protected I2PClientMessageHandlerMap _handlerMap;
@ -225,6 +226,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
*/
public void connect() throws I2PSessionException {
_closed = false;
_availabilityNotifier.stopNotifying();
I2PThread notifier = new I2PThread(_availabilityNotifier);
notifier.setName("Notifier " + _myDestination.calculateHash().toBase64().substring(0,4));
notifier.setDaemon(true);
@ -289,7 +291,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
*
*/
public byte[] receiveMessage(int msgId) throws I2PSessionException {
MessagePayloadMessage msg = (MessagePayloadMessage) _availableMessages.remove(new Integer(msgId));
MessagePayloadMessage msg = null;
synchronized (_availableMessages) {
msg = (MessagePayloadMessage) _availableMessages.remove(new Integer(msgId));
}
if (msg == null) return null;
return msg.getPayload().getUnencryptedData();
}
@ -338,12 +343,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* Recieve a payload message and let the app know its available
*/
public void addNewMessage(MessagePayloadMessage msg) {
_availableMessages.put(new Integer(msg.getMessageId().getMessageId()), msg);
synchronized (_availableMessages) {
_availableMessages.put(new Integer(msg.getMessageId().getMessageId()), msg);
}
int id = msg.getMessageId().getMessageId();
byte data[] = msg.getPayload().getUnencryptedData();
if ((data == null) || (data.length <= 0)) {
if (_log.shouldLog(Log.ERROR))
_log.error(getPrefix() + "addNewMessage of a message with no unencrypted data",
if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, getPrefix() + "addNewMessage of a message with no unencrypted data",
new Exception("Empty message"));
} else {
int size = data.length;
@ -351,6 +358,20 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix() + "Notified availability for session " + _sessionId + ", message " + id);
}
SimpleTimer.getInstance().addEvent(new VerifyUsage(id), 30*1000);
}
private class VerifyUsage implements SimpleTimer.TimedEvent {
private int _msgId;
public VerifyUsage(int id) { _msgId = id; }
public void timeReached() {
MessagePayloadMessage removed = null;
synchronized (_availableMessages) {
removed = (MessagePayloadMessage)_availableMessages.remove(new Integer(_msgId));
}
if (removed != null)
_log.log(Log.CRIT, "Message NOT removed! id=" + _msgId + ": " + removed);
}
}
private class AvailabilityNotifier implements Runnable {
@ -401,6 +422,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
} catch (Exception e) {
_log.log(Log.CRIT, "Error notifying app of message availability", e);
}
} else {
_log.log(Log.CRIT, "Unable to notify an app that " + msgId + " of size " + size + " is available!");
}
}
}
@ -481,12 +504,15 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
long beforeSync = _context.clock().now();
long inSync = 0;
if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync to write");
try {
synchronized (_out) {
inSync = _context.clock().now();
if (_log.shouldLog(Log.DEBUG)) _log.debug("before writeMessage");
message.writeMessage(_out);
if (_log.shouldLog(Log.DEBUG)) _log.debug("after writeMessage");
_out.flush();
if (_log.shouldLog(Log.DEBUG)) _log.debug("after flush");
}
} catch (I2CPMessageException ime) {
throw new I2PSessionException(getPrefix() + "Error writing out the message", ime);
@ -504,7 +530,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* Pass off the error to the listener
*/
void propogateError(String msg, Throwable error) {
if (_log.shouldLog(Log.ERROR)) _log.error(getPrefix() + "Error occurred: " + msg, error);
if (_log.shouldLog(Log.ERROR))
_log.error(getPrefix() + "Error occurred: " + msg + " - " + error.getMessage());
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix() + " cause", error);
if (_sessionListener != null) _sessionListener.errorOccurred(this, msg, error);
}

View File

@ -73,10 +73,11 @@ class I2PSessionImpl2 extends I2PSessionImpl {
}
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent)
throws I2PSessionException {
if (_log.shouldLog(Log.DEBUG)) _log.debug("sending message");
if (isClosed()) throw new I2PSessionException("Already closed");
if (SHOULD_COMPRESS) payload = DataHelper.compress(payload, offset, size);
else throw new IllegalStateException("we need to update sendGuaranteed to support partial send");
if (_log.shouldLog(Log.DEBUG)) _log.debug("message compressed");
// we always send as guaranteed (so we get the session keys/tags acked),
// but only block until the appropriate event has been reached (guaranteed
// success or accepted). we may want to break this out into a seperate
@ -111,10 +112,12 @@ class I2PSessionImpl2 extends I2PSessionImpl {
private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent)
throws I2PSessionException {
long begin = _context.clock().now();
if (_log.shouldLog(Log.DEBUG)) _log.debug("begin sendBestEffort");
SessionKey key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey());
if (_log.shouldLog(Log.DEBUG)) _log.debug("key fetched");
if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey());
SessionTag tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key);
if (_log.shouldLog(Log.DEBUG)) _log.debug("tag consumed");
Set sentTags = null;
int oldTags = _context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key);
long availTimeLeft = _context.sessionKeyManager().getAvailableTimeLeft(dest.getPublicKey(), key);
@ -151,7 +154,10 @@ class I2PSessionImpl2 extends I2PSessionImpl {
sentTags.addAll(tagsSent);
}
if (_log.shouldLog(Log.DEBUG)) _log.debug("before creating nonce");
long nonce = _context.random().nextInt(Integer.MAX_VALUE);
if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync state");
MessageState state = new MessageState(nonce, getPrefix());
state.setKey(key);
state.setTags(sentTags);
@ -171,6 +177,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
}
}
if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync state");
long beforeSendingSync = _context.clock().now();
long inSendingSync = 0;
synchronized (_sendingStates) {

View File

@ -57,8 +57,8 @@ class MessagePayloadMessageHandler extends HandlerImpl {
Payload payload = msg.getPayload();
byte[] data = _context.elGamalAESEngine().decrypt(payload.getEncryptedData(), session.getDecryptionKey());
if (data == null) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error decrypting the payload");
if (_log.shouldLog(Log.WARN))
_log.warn("Error decrypting the payload");
throw new DataFormatException("Unable to decrypt the payload");
}
payload.setUnencryptedData(data);

View File

@ -1,9 +1,7 @@
package net.i2p.client;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.i2p.data.Destination;

View File

@ -41,7 +41,8 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
}
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
_log.debug("Handle message " + message);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handle message " + message);
RequestLeaseSetMessage msg = (RequestLeaseSetMessage) message;
LeaseSet leaseSet = new LeaseSet();
for (int i = 0; i < msg.getEndpoints(); i++) {

View File

@ -8,8 +8,6 @@
package net.i2p.client.naming;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

View File

@ -9,10 +9,7 @@ package net.i2p.crypto;
*
*/
import java.io.IOException;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;

View File

@ -14,9 +14,6 @@ import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;

View File

@ -9,8 +9,6 @@ package net.i2p.crypto;
*
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

View File

@ -29,7 +29,6 @@ package net.i2p.crypto;
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import net.i2p.I2PAppContext;

View File

@ -23,8 +23,8 @@ import net.i2p.data.DataHelper;
import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.util.Clock;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
/**
* Implement the session key management, but keep everything in memory (don't write
@ -53,7 +53,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
* can cause failed decrypts)
*
*/
public final static long SESSION_LIFETIME_MAX_MS = SESSION_TAG_DURATION_MS + 2 * 60 * 1000;
public final static long SESSION_LIFETIME_MAX_MS = SESSION_TAG_DURATION_MS + 5 * 60 * 1000;
public final static int MAX_INBOUND_SESSION_TAGS = 500 * 1000; // this will consume at most a few MB
/**
@ -66,10 +66,23 @@ class TransientSessionKeyManager extends SessionKeyManager {
super(context);
_log = context.logManager().getLog(TransientSessionKeyManager.class);
_context = context;
_outboundSessions = new HashMap(64);
_inboundTagSets = new HashMap(1024);
_outboundSessions = new HashMap(1024);
_inboundTagSets = new HashMap(64*1024);
context.statManager().createRateStat("crypto.sessionTagsExpired", "How many tags/sessions are expired?", "Encryption", new long[] { 10*60*1000, 60*60*1000, 3*60*60*1000 });
context.statManager().createRateStat("crypto.sessionTagsRemaining", "How many tags/sessions are remaining after a cleanup?", "Encryption", new long[] { 10*60*1000, 60*60*1000, 3*60*60*1000 });
SimpleTimer.getInstance().addEvent(new CleanupEvent(), 60*1000);
}
private TransientSessionKeyManager() { this(null); }
private class CleanupEvent implements SimpleTimer.TimedEvent {
public void timeReached() {
long beforeExpire = _context.clock().now();
int expired = aggressiveExpire();
long expireTime = _context.clock().now() - beforeExpire;
_context.statManager().addRateData("crypto.sessionTagsExpired", expired, expireTime);
SimpleTimer.getInstance().addEvent(CleanupEvent.this, 60*1000);
}
}
/** TagSet */
protected Set getInboundTagSets() {
@ -248,6 +261,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
overage = _inboundTagSets.size() - MAX_INBOUND_SESSION_TAGS;
}
}
if (overage > 0)
clearExcess(overage);
@ -362,45 +376,32 @@ class TransientSessionKeyManager extends SessionKeyManager {
*/
public int aggressiveExpire() {
int removed = 0;
int remaining = 0;
long now = _context.clock().now();
Set tagsToDrop = null; // new HashSet(64);
synchronized (_inboundTagSets) {
for (Iterator iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
SessionTag tag = (SessionTag) iter.next();
TagSet ts = (TagSet) _inboundTagSets.get(tag);
if (ts.getDate() < now - SESSION_LIFETIME_MAX_MS) {
if (tagsToDrop == null)
tagsToDrop = new HashSet(4);
tagsToDrop.add(tag);
iter.remove();
removed++;
}
}
if (tagsToDrop != null) {
removed += tagsToDrop.size();
for (Iterator iter = tagsToDrop.iterator(); iter.hasNext();)
_inboundTagSets.remove(iter.next());
}
remaining = _inboundTagSets.size();
}
_context.statManager().addRateData("crypto.sessionTagsRemaining", remaining, 0);
//_log.warn("Expiring tags: [" + tagsToDrop + "]");
synchronized (_outboundSessions) {
Set sessionsToDrop = null;
for (Iterator iter = _outboundSessions.keySet().iterator(); iter.hasNext();) {
PublicKey key = (PublicKey) iter.next();
OutboundSession sess = (OutboundSession) _outboundSessions.get(key);
removed += sess.expireTags();
if (sess.getTagSets().size() <= 0) {
if (sessionsToDrop == null)
sessionsToDrop = new HashSet(4);
sessionsToDrop.add(key);
}
}
if (sessionsToDrop != null) {
for (Iterator iter = sessionsToDrop.iterator(); iter.hasNext();) {
OutboundSession cur = (OutboundSession)_outboundSessions.remove(iter.next());
if ( (cur != null) && (_log.shouldLog(Log.WARN)) )
_log.warn("Removing session tags with " + cur.availableTags() + " available for "
+ (cur.getLastExpirationDate()-_context.clock().now())
+ "ms more", new Exception("Removed by"));
if (sess.availableTags() <= 0) {
iter.remove();
removed++;
}
}
}

View File

@ -10,7 +10,6 @@ package net.i2p.data;
*/
import java.io.BufferedReader;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -32,11 +31,12 @@ import java.util.List;
import java.util.Properties;
import java.util.TreeMap;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import net.i2p.util.ByteCache;
import net.i2p.util.CachingByteArrayOutputStream;
import net.i2p.util.OrderedProperties;
import net.i2p.util.ReusableGZIPInputStream;
import net.i2p.util.ReusableGZIPOutputStream;
/**
* Defines some simple IO routines for dealing with marshalling data structures
@ -361,7 +361,7 @@ public class DataHelper {
*/
public static void writeLong(OutputStream rawStream, int numBytes, long value)
throws DataFormatException, IOException {
if (value < 0) throw new DataFormatException("Value is negative (" + value + ")");
for (int i = numBytes - 1; i >= 0; i--) {
byte cur = (byte)( (value >>> (i*8) ) & 0xFF);
rawStream.write(cur);
@ -369,6 +369,7 @@ public class DataHelper {
}
public static byte[] toLong(int numBytes, long value) throws IllegalArgumentException {
if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
byte val[] = new byte[numBytes];
toLong(val, 0, numBytes, value);
return val;
@ -397,43 +398,6 @@ public class DataHelper {
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 + ")");
read = readLong(new ByteArrayInputStream(written), numBytes);
if (read != value)
throw new RuntimeException("testLong("+numBytes+","+value+") FAILED on readLong (" + 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
@ -863,20 +827,21 @@ public class DataHelper {
return rv;
}
private static final int MAX_UNCOMPRESSED = 40*1024;
/** compress the data and return a new GZIP compressed array */
public static byte[] compress(byte orig[]) {
return compress(orig, 0, orig.length);
}
public static byte[] compress(byte orig[], int offset, int size) {
if ((orig == null) || (orig.length <= 0)) return orig;
if (size >= MAX_UNCOMPRESSED)
throw new IllegalArgumentException("tell jrandom size=" + size);
ReusableGZIPOutputStream out = ReusableGZIPOutputStream.acquire();
try {
CachingByteArrayOutputStream baos = new CachingByteArrayOutputStream(16, 40*1024);
GZIPOutputStream out = new GZIPOutputStream(baos, size);
out.write(orig, offset, size);
out.finish();
out.flush();
byte rv[] = baos.toByteArray();
baos.releaseBuffer();
byte rv[] = out.getData();
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Compression of " + orig.length + " into " + rv.length + " (or " + 100.0d
// * (((double) orig.length) / ((double) rv.length)) + "% savings)");
@ -884,31 +849,35 @@ public class DataHelper {
} catch (IOException ioe) {
//_log.error("Error compressing?!", ioe);
return null;
} finally {
ReusableGZIPOutputStream.release(out);
}
}
/** decompress the GZIP compressed data (returning null on error) */
public static byte[] decompress(byte orig[]) throws IOException {
return (orig != null ? decompress(orig, 0, orig.length) : null);
}
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, offset, length), length);
CachingByteArrayOutputStream baos = new CachingByteArrayOutputStream(16, 40*1024);
ByteCache cache = ByteCache.getInstance(10, 4*1024);
ByteArray ba = cache.acquire();
byte buf[] = ba.getData(); // new byte[4 * 1024];
ReusableGZIPInputStream in = ReusableGZIPInputStream.acquire();
in.initialize(new ByteArrayInputStream(orig, offset, length));
ByteCache cache = ByteCache.getInstance(8, MAX_UNCOMPRESSED);
ByteArray outBuf = cache.acquire();
int written = 0;
while (true) {
int read = in.read(buf);
if (read == -1) break;
baos.write(buf, 0, read);
int read = in.read(outBuf.getData(), written, MAX_UNCOMPRESSED-written);
if (read == -1)
break;
written += read;
}
byte rv[] = baos.toByteArray();
cache.release(ba);
baos.releaseBuffer();
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Decompression of " + orig.length + " into " + rv.length + " (or " + 100.0d
// * (((double) rv.length) / ((double) orig.length)) + "% savings)");
byte rv[] = new byte[written];
System.arraycopy(outBuf.getData(), 0, rv, 0, written);
cache.release(outBuf);
ReusableGZIPInputStream.release(in);
return rv;
}

View File

@ -12,7 +12,6 @@ package net.i2p.data;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
/**
* Defines the class as a standard object with particular bit representation,
@ -20,7 +19,7 @@ import java.io.Serializable;
*
* @author jrandom
*/
public interface DataStructure extends Serializable {
public interface DataStructure /* extends Serializable */ {
/**
* Load up the current object with data from the given stream. Data loaded
* this way must match the I2P data structure specification.

View File

@ -298,6 +298,16 @@ public class LeaseSet extends DataStructureImpl {
}
_signature.writeBytes(out);
}
public int size() {
return PublicKey.KEYSIZE_BYTES //destination.pubKey
+ SigningPublicKey.KEYSIZE_BYTES // destination.signPubKey
+ 2 // destination.certificate
+ PublicKey.KEYSIZE_BYTES // encryptionKey
+ SigningPublicKey.KEYSIZE_BYTES // signingKey
+ 1
+ _leases.size() * (Hash.HASH_LENGTH + 4 + 8);
}
public boolean equals(Object object) {
if ((object == null) || !(object instanceof LeaseSet)) return false;

View File

@ -73,14 +73,16 @@ public class Payload extends DataStructureImpl {
_encryptedData = new byte[size];
int read = read(in, _encryptedData);
if (read != size) throw new DataFormatException("Incorrect number of bytes read in the payload structure");
_log.debug("read payload: " + read + " bytes");
if (_log.shouldLog(Log.DEBUG))
_log.debug("read payload: " + read + " bytes");
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_encryptedData == null) throw new DataFormatException("Not yet encrypted. Please set the encrypted data");
DataHelper.writeLong(out, 4, _encryptedData.length);
out.write(_encryptedData);
_log.debug("wrote payload: " + _encryptedData.length);
if (_log.shouldLog(Log.DEBUG))
_log.debug("wrote payload: " + _encryptedData.length);
}
public int writeBytes(byte target[], int offset) {
if (_encryptedData == null) throw new IllegalStateException("Not yet encrypted. Please set the encrypted data");

View File

@ -91,7 +91,11 @@ public class CreateLeaseSetMessage extends I2CPMessageImpl {
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
if ((_sessionId == null) || (_signingPrivateKey == null) || (_privateKey == null) || (_leaseSet == null))
throw new I2CPMessageException("Unable to write out the message as there is not enough data");
ByteArrayOutputStream os = new ByteArrayOutputStream(512);
int size = 4 // sessionId
+ SigningPrivateKey.KEYSIZE_BYTES
+ PrivateKey.KEYSIZE_BYTES
+ _leaseSet.size();
ByteArrayOutputStream os = new ByteArrayOutputStream(size);
try {
_sessionId.writeBytes(os);
_signingPrivateKey.writeBytes(os);

View File

@ -9,7 +9,6 @@ package net.i2p.data.i2cp;
*
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

View File

@ -64,14 +64,10 @@ public class ReceiveMessageBeginMessage extends I2CPMessageImpl {
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
if ((_sessionId == null) || (_messageId == null))
throw new I2CPMessageException("Unable to write out the message as there is not enough data");
ByteArrayOutputStream os = new ByteArrayOutputStream(64);
try {
_sessionId.writeBytes(os);
_messageId.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2CPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
byte rv[] = new byte[2+4];
DataHelper.toLong(rv, 0, 2, _sessionId.getSessionId());
DataHelper.toLong(rv, 2, 4, _messageId.getMessageId());
return rv;
}
public int getType() {

View File

@ -64,14 +64,10 @@ public class ReceiveMessageEndMessage extends I2CPMessageImpl {
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
if ((_sessionId == null) || (_messageId == null))
throw new I2CPMessageException("Unable to write out the message as there is not enough data");
ByteArrayOutputStream os = new ByteArrayOutputStream(64);
try {
_sessionId.writeBytes(os);
_messageId.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2CPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
byte rv[] = new byte[2+4];
DataHelper.toLong(rv, 0, 2, _sessionId.getSessionId());
DataHelper.toLong(rv, 2, 4, _messageId.getMessageId());
return rv;
}
public int getType() {

View File

@ -9,7 +9,6 @@ package net.i2p.data.i2cp;
*
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

View File

@ -99,7 +99,7 @@ public class BufferedStatLog implements StatLog {
if (_out != null) try { _out.close(); } catch (IOException ioe) {}
_outFile = filename;
try {
_out = new BufferedWriter(new FileWriter(_outFile, true));
_out = new BufferedWriter(new FileWriter(_outFile, true), 32*1024);
} catch (IOException ioe) { ioe.printStackTrace(); }
}
}
@ -147,12 +147,16 @@ public class BufferedStatLog implements StatLog {
_out.write(when);
_out.write(" ");
if (_events[cur].getScope() == null)
_out.write("noScope ");
_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");
_out.write(_events[cur].getScope());
_out.write(" ");
_out.write(_events[cur].getStat());
_out.write(" ");
_out.write(Long.toString(_events[cur].getValue()));
_out.write(" ");
_out.write(Long.toString(_events[cur].getDuration()));
_out.write("\n");
}
cur = (cur + 1) % _events.length;
}

View File

@ -26,10 +26,10 @@ public class Timestamper implements Runnable {
private boolean _initialized;
private static final int DEFAULT_QUERY_FREQUENCY = 5*60*1000;
private static final String DEFAULT_SERVER_LIST = "pool.ntp.org, pool.ntp.org";
private static final String DEFAULT_SERVER_LIST = "pool.ntp.org, pool.ntp.org, pool.ntp.org";
private static final boolean DEFAULT_DISABLED = true;
/** how many times do we have to query if we are changing the clock? */
private static final int DEFAULT_CONCURRING_SERVERS = 2;
private static final int DEFAULT_CONCURRING_SERVERS = 3;
public static final String PROP_QUERY_FREQUENCY = "time.queryFrequencyMs";
public static final String PROP_SERVER_LIST = "time.sntpServerList";
@ -101,6 +101,15 @@ public class Timestamper implements Runnable {
t.start();
}
public void waitForInitialization() {
try {
synchronized (this) {
if (!_initialized)
wait();
}
} catch (InterruptedException ie) {}
}
public void run() {
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
_log = _context.logManager().getLog(Timestamper.class);
@ -109,7 +118,7 @@ public class Timestamper implements Runnable {
if (_log.shouldLog(Log.INFO))
_log.info("Starting up timestamper");
boolean alreadyBitched = false;
boolean lastFailed = false;
try {
while (true) {
updateConfig();
@ -123,54 +132,82 @@ public class Timestamper implements Runnable {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Querying servers " + _servers);
try {
queryTime(serverList);
lastFailed = !queryTime(serverList);
} catch (IllegalArgumentException iae) {
if (!alreadyBitched)
_log.log(Log.CRIT, "Unable to reach any of the NTP servers - network disconnected?");
alreadyBitched = true;
if ( (!lastFailed) && (_log.shouldLog(Log.ERROR)) )
_log.error("Unable to reach any of the NTP servers - network disconnected?");
lastFailed = true;
}
}
_initialized = true;
synchronized (this) { notifyAll(); }
long sleepTime = _context.random().nextInt(_queryFrequency) + _queryFrequency;
if (lastFailed)
sleepTime = 30*1000;
try { Thread.sleep(sleepTime); } catch (InterruptedException ie) {}
}
} catch (Throwable t) {
_log.log(Log.CRIT, "Timestamper died!", t);
synchronized (this) { notifyAll(); }
}
}
private void queryTime(String serverList[]) throws IllegalArgumentException {
long localTime = -1;
/**
* True if the time was queried successfully, false if it couldn't be
*/
private boolean queryTime(String serverList[]) throws IllegalArgumentException {
long found[] = new long[_concurringServers];
long now = -1;
long expectedDelta = 0;
for (int i = 0; i < _concurringServers; i++) {
localTime = _context.clock().now();
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
now = NtpClient.currentTime(serverList);
long delta = now - localTime;
long delta = now - _context.clock().now();
found[i] = delta;
if (i == 0) {
if (Math.abs(delta) < MAX_VARIANCE) {
if (_log.shouldLog(Log.INFO))
_log.info("a single SNTP query was within the tolerance (" + delta + "ms)");
return;
break;
} else {
// outside the tolerance, lets iterate across the concurring queries
expectedDelta = delta;
}
} else {
if (Math.abs(delta - expectedDelta) > MAX_VARIANCE) {
if (_log.shouldLog(Log.ERROR))
_log.error("SNTP client variance exceeded at query " + i + ". expected = " + expectedDelta + ", found = " + delta);
return;
if (_log.shouldLog(Log.ERROR)) {
StringBuffer err = new StringBuffer(96);
err.append("SNTP client variance exceeded at query ").append(i);
err.append(". expected = ");
err.append(expectedDelta);
err.append(", found = ");
err.append(delta);
err.append(" all deltas: ");
for (int j = 0; j < found.length; j++)
err.append(found[j]).append(' ');
_log.error(err.toString());
}
return false;
}
}
}
stampTime(now);
if (_log.shouldLog(Log.DEBUG)) {
StringBuffer buf = new StringBuffer(64);
buf.append("Deltas: ");
for (int i = 0; i < found.length; i++)
buf.append(found[i]).append(' ');
_log.debug(buf.toString());
}
return true;
}
/**
* Send an HTTP request to a given URL specifying the current time
*/
private void stampTime(long now) {
long before = _context.clock().now();
synchronized (_listeners) {
for (int i = 0; i < _listeners.size(); i++) {
UpdateListener lsnr = (UpdateListener)_listeners.get(i);
@ -178,7 +215,7 @@ public class Timestamper implements Runnable {
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Stamped the time as " + now);
_log.debug("Stamped the time as " + now + " (delta=" + (now-before) + ")");
}
/**

View File

@ -25,11 +25,14 @@ public final class ByteCache {
*/
public static ByteCache getInstance(int cacheSize, int size) {
Integer sz = new Integer(size);
ByteCache cache = null;
synchronized (_caches) {
if (!_caches.containsKey(sz))
_caches.put(sz, new ByteCache(cacheSize, size));
return (ByteCache)_caches.get(sz);
cache = (ByteCache)_caches.get(sz);
}
cache.resize(cacheSize);
return cache;
}
private Log _log;
/** list of available and available entries */
@ -56,6 +59,11 @@ public final class ByteCache {
_log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class);
}
private void resize(int maxCachedEntries) {
if (_maxCached >= maxCachedEntries) return;
_maxCached = maxCachedEntries;
}
/**
* Get the next available structure, either from the cache or a brand new one
*

View File

@ -10,7 +10,6 @@ package net.i2p.util;
*/
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
/**
* Wrapper class for whatever logging system I2P uses. This class should be

View File

@ -12,10 +12,12 @@ import net.i2p.I2PAppContext;
public class LogConsoleBuffer {
private I2PAppContext _context;
private List _buffer;
private List _critBuffer;
public LogConsoleBuffer(I2PAppContext context) {
_context = context;
_buffer = new ArrayList();
_critBuffer = new ArrayList();
}
void add(String msg) {
@ -26,6 +28,14 @@ public class LogConsoleBuffer {
_buffer.add(msg);
}
}
void addCritical(String msg) {
int lim = _context.logManager().getConsoleBufferSize();
synchronized (_critBuffer) {
while (_critBuffer.size() >= lim)
_critBuffer.remove(0);
_critBuffer.add(msg);
}
}
/**
* Retrieve the currently bufferd messages, earlier values were generated...
@ -38,4 +48,15 @@ public class LogConsoleBuffer {
return new ArrayList(_buffer);
}
}
/**
* Retrieve the currently bufferd crutucak messages, earlier values were generated...
* earlier. All values are strings with no formatting (as they are written
* in the logs)
*
*/
public List getMostRecentCriticalMessages() {
synchronized (_critBuffer) {
return new ArrayList(_critBuffer);
}
}
}

View File

@ -101,6 +101,8 @@ class LogWriter implements Runnable {
// we always add to the console buffer, but only sometimes write to stdout
_manager.getBuffer().add(val);
if (rec.getPriority() >= Log.CRIT)
_manager.getBuffer().addCritical(val);
if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) {
if (_manager.displayOnScreen()) {
System.out.print(val);

View File

@ -0,0 +1,128 @@
package net.i2p.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.FilterInputStream;
import java.util.Arrays;
/**
* Simple lookahead buffer to keep the last K bytes in reserve,
* configured to easily be reused. Currently only used by the
* ResettableGZIPInputStream
*
*/
public class LookaheadInputStream extends FilterInputStream {
private boolean _eofReached;
private byte[] _footerLookahead;
private static final InputStream _fakeInputStream = new ByteArrayInputStream(new byte[0]);
public LookaheadInputStream(int lookaheadSize) {
super(_fakeInputStream);
_eofReached = false;
_footerLookahead = new byte[lookaheadSize];
}
public boolean getEOFReached() { return _eofReached; }
public void initialize(InputStream src) throws IOException {
in = src;
_eofReached = false;
Arrays.fill(_footerLookahead, (byte)0x00);
int footerRead = 0;
while (footerRead < _footerLookahead.length) {
int read = in.read(_footerLookahead);
if (read == -1) throw new IOException("EOF reading the footer lookahead");
footerRead += read;
}
boolean f = true;
}
public int read() throws IOException {
if (_eofReached)
return -1; //throw new IOException("Already past the EOF");
int c = in.read();
if (c == -1) {
_eofReached = true;
return -1;
}
int rv = _footerLookahead[0];
System.arraycopy(_footerLookahead, 1, _footerLookahead, 0, _footerLookahead.length-1);
_footerLookahead[_footerLookahead.length-1] = (byte)c;
if (rv < 0) rv += 256;
return rv;
}
public int read(byte buf[]) throws IOException {
return read(buf, 0, buf.length);
}
public int read(byte buf[], int off, int len) throws IOException {
if (_eofReached)
return -1;
for (int i = 0; i < len; i++) {
int c = read();
if (c == -1) {
if (i == 0)
return -1;
else
return i;
} else {
buf[off+i] = (byte)c;
}
}
return len;
}
/** grab the lookahead footer */
public byte[] getFooter() { return _footerLookahead; }
public static void main(String args[]) {
byte buf[] = new byte[32];
for (int i = 0; i < 32; i++)
buf[i] = (byte)i;
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
try {
LookaheadInputStream lis = new LookaheadInputStream(8);
lis.initialize(bais);
byte rbuf[] = new byte[32];
int read = lis.read(rbuf);
if (read != 24) throw new RuntimeException("Should have stopped (read=" + read + ")");
for (int i = 0; i < 24; i++)
if (rbuf[i] != (byte)i)
throw new RuntimeException("Error at " + i + " [" + rbuf[i] + "]");
for (int i = 0; i < 8; i++)
if (lis.getFooter()[i] != (byte)(i+24))
throw new RuntimeException("Error at footer " + i + " [" + lis.getFooter()[i] + "]");
System.out.println("Everything is fine in general");
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 9; i < 32*1024; i++) {
if (!test(i)) break;
}
}
private static boolean test(int size) {
byte buf[] = new byte[size];
new java.util.Random().nextBytes(buf);
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
try {
LookaheadInputStream lis = new LookaheadInputStream(8);
lis.initialize(bais);
byte rbuf[] = new byte[size];
int read = lis.read(rbuf);
if (read != (size-8)) throw new RuntimeException("Should have stopped (read=" + read + ")");
for (int i = 0; i < (size-8); i++)
if (rbuf[i] != buf[i])
throw new RuntimeException("Error at " + i + " [" + rbuf[i] + "]");
for (int i = 0; i < 8; i++)
if (lis.getFooter()[i] != buf[i+(size-8)])
throw new RuntimeException("Error at footer " + i + " [" + lis.getFooter()[i] + "]");
System.out.println("Everything is fine at size=" + size);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

View File

@ -238,8 +238,8 @@ public class OrderedProperties extends Properties {
public int compareTo(Object o) {
if (o == null) return -1;
if (o instanceof StringMapEntry) return ((String) getKey()).compareTo(((StringMapEntry) o).getKey());
if (o instanceof String) return ((String) getKey()).compareTo(o);
if (o instanceof StringMapEntry) return ((String) getKey()).compareTo((String)((StringMapEntry) o).getKey());
if (o instanceof String) return ((String) getKey()).compareTo((String)o);
return -2;
}

View File

@ -42,7 +42,7 @@ public class RandomSource extends SecureRandom {
* thats what it has been used for.
*
*/
public int nextInt(int n) {
public synchronized int nextInt(int n) {
if (n == 0) return 0;
int val = super.nextInt(n);
if (val < 0) val = 0 - val;
@ -54,19 +54,48 @@ public class RandomSource extends SecureRandom {
* Like the modified nextInt, nextLong(n) returns a random number from 0 through n,
* including 0, excluding n.
*/
public long nextLong(long n) {
public synchronized long nextLong(long n) {
long v = super.nextLong();
if (v < 0) v = 0 - v;
if (v >= n) v = v % n;
return v;
}
/** synchronized for older versions of kaffe */
public void nextBytes(byte bytes[]) {
synchronized (this) {
super.nextBytes(bytes);
}
}
/**
* override as synchronized, for those JVMs that don't always pull via
* nextBytes (cough ibm)
*/
public synchronized boolean nextBoolean() { return super.nextBoolean(); }
/**
* override as synchronized, for those JVMs that don't always pull via
* nextBytes (cough ibm)
*/
public synchronized void nextBytes(byte buf[]) { super.nextBytes(buf); }
/**
* override as synchronized, for those JVMs that don't always pull via
* nextBytes (cough ibm)
*/
public synchronized double nextDouble() { return super.nextDouble(); }
/**
* override as synchronized, for those JVMs that don't always pull via
* nextBytes (cough ibm)
*/
public synchronized float nextFloat() { return super.nextFloat(); }
/**
* override as synchronized, for those JVMs that don't always pull via
* nextBytes (cough ibm)
*/
public synchronized double nextGaussian() { return super.nextGaussian(); }
/**
* override as synchronized, for those JVMs that don't always pull via
* nextBytes (cough ibm)
*/
public synchronized int nextInt() { return super.nextInt(); }
/**
* override as synchronized, for those JVMs that don't always pull via
* nextBytes (cough ibm)
*/
public synchronized long nextLong() { return super.nextLong(); }
public EntropyHarvester harvester() { return _entropyHarvester; }

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