merge of 'b002d4a942128fdd4994a2cfba1c554ba9cb81d8'

and 'e6547920e2da9f540c79fcafc7ca7c82d25eae23'
This commit is contained in:
zzz
2010-11-26 15:57:05 +00:00
37 changed files with 607 additions and 383 deletions

View File

@ -0,0 +1,102 @@
package org.klomp.snark;
/**
* This is the class passed from PeerCoordinator to PeerState so
* PeerState may start requests.
*
* It is also passed from PeerState to PeerCoordinator when
* a piece is not completely downloaded, for example
* when the Peer disconnects or chokes.
*/
class PartialPiece implements Comparable {
private final int piece;
private final byte[] bs;
private final int off;
private final long createdTime;
/**
* Used by PeerCoordinator.
* Creates a new PartialPiece, with no chunks yet downloaded.
* Allocates the data.
*
* @param piece Piece number requested.
* @param bs length must be equal to the piece length
*/
public PartialPiece (int piece, int len) throws OutOfMemoryError {
this.piece = piece;
this.bs = new byte[len];
this.off = 0;
this.createdTime = 0;
}
/**
* Used by PeerState.
* Creates a new PartialPiece, with chunks up to but not including
* firstOutstandingRequest already downloaded and stored in the Request byte array.
*
* Note that this cannot handle gaps; chunks after a missing chunk cannot be saved.
* That would be harder.
*
* @param firstOutstandingRequest the first request not fulfilled for the piece
*/
public PartialPiece (Request firstOutstandingRequest) {
this.piece = firstOutstandingRequest.piece;
this.bs = firstOutstandingRequest.bs;
this.off = firstOutstandingRequest.off;
this.createdTime = System.currentTimeMillis();
}
/**
* Convert this PartialPiece to a request for the next chunk.
* Used by PeerState only.
*/
public Request getRequest() {
return new Request(this.piece, this.bs, this.off, Math.min(this.bs.length - this.off, PeerState.PARTSIZE));
}
/** piece number */
public int getPiece() {
return this.piece;
}
/** how many bytes are good */
public int getDownloaded() {
return this.off;
}
public long getCreated() {
return this.createdTime;
}
/**
* Highest downloaded first
*/
public int compareTo(Object o) throws ClassCastException {
return ((PartialPiece)o).off - this.off; // reverse
}
@Override
public int hashCode() {
return piece * 7777;
}
/**
* Make this simple so PeerCoordinator can keep a List.
* Warning - compares piece number only!
*/
@Override
public boolean equals(Object o) {
if (o instanceof PartialPiece) {
PartialPiece pp = (PartialPiece)o;
return pp.piece == this.piece;
}
return false;
}
@Override
public String toString() {
return "Partial(" + piece + ',' + off + ',' + bs.length + ')';
}
}

View File

@ -27,6 +27,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.util.Log;
@ -368,8 +369,11 @@ public class Peer implements Comparable
if (this.deregister) {
PeerListener p = s.listener;
if (p != null) {
p.savePeerPartial(s);
p.markUnrequested(this);
List<PartialPiece> pcs = s.returnPartialPieces();
if (!pcs.isEmpty())
p.savePartialPieces(this, pcs);
// now covered by savePartialPieces
//p.markUnrequested(this);
}
}
state = null;

View File

@ -74,6 +74,9 @@ public class PeerCoordinator implements PeerListener
// Some random wanted pieces
private List<Piece> wantedPieces;
/** partial pieces */
private final List<PartialPiece> partialPieces;
private boolean halted = false;
private final CoordinatorListener listener;
@ -94,6 +97,7 @@ public class PeerCoordinator implements PeerListener
this.snark = torrent;
setWantedPieces();
partialPieces = new ArrayList(getMaxConnections() + 1);
// Install a timer to check the uploaders.
// Randomize the first start time so multiple tasks are spread out,
@ -293,7 +297,9 @@ public class PeerCoordinator implements PeerListener
removePeerFromPieces(peer);
}
// delete any saved orphan partial piece
savedRequest = null;
synchronized (partialPieces) {
partialPieces.clear();
}
}
public void connected(Peer peer)
@ -773,6 +779,9 @@ public class PeerCoordinator implements PeerListener
wantedPieces.remove(p);
}
// just in case
removePartialPiece(piece);
// Announce to the world we have it!
// Disconnect from other seeders when we get the last piece
synchronized(peers)
@ -866,70 +875,123 @@ public class PeerCoordinator implements PeerListener
}
}
/** Simple method to save a partial piece on peer disconnection
/**
* Save partial pieces on peer disconnection
* and hopefully restart it later.
* Only one partial piece is saved at a time.
* Replace it if a new one is bigger or the old one is too old.
* Replace a partial piece in the List if the new one is bigger.
* Storage method is private so we can expand to save multiple partials
* if we wish.
*
* Also mark the piece unrequested if this peer was the only one.
*
* @param peer partials, must include the zero-offset (empty) ones too
* @since 0.8.2
*/
private Request savedRequest = null;
private long savedRequestTime = 0;
public void savePeerPartial(PeerState state)
public void savePartialPieces(Peer peer, List<PartialPiece> partials)
{
if (halted)
return;
Request req = state.getPartialRequest();
if (req == null)
return;
if (savedRequest == null ||
req.off > savedRequest.off ||
System.currentTimeMillis() > savedRequestTime + (15 * 60 * 1000)) {
if (savedRequest == null || (req.piece != savedRequest.piece && req.off != savedRequest.off)) {
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(" Saving orphaned partial piece " + req);
if (savedRequest != null)
_log.debug(" (Discarding previously saved orphan) " + savedRequest);
}
if (halted)
return;
if (_log.shouldLog(Log.INFO))
_log.info("Partials received from " + peer + ": " + partials);
synchronized(partialPieces) {
for (PartialPiece pp : partials) {
if (pp.getDownloaded() > 0) {
// PartialPiece.equals() only compares piece number, which is what we want
int idx = partialPieces.indexOf(pp);
if (idx < 0) {
partialPieces.add(pp);
if (_log.shouldLog(Log.INFO))
_log.info("Saving orphaned partial piece (new) " + pp);
} else if (idx >= 0 && pp.getDownloaded() > partialPieces.get(idx).getDownloaded()) {
// replace what's there now
partialPieces.set(idx, pp);
if (_log.shouldLog(Log.INFO))
_log.info("Saving orphaned partial piece (bigger) " + pp);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Discarding partial piece (not bigger)" + pp);
}
int max = getMaxConnections();
if (partialPieces.size() > max) {
// sorts by remaining bytes, least first
Collections.sort(partialPieces);
PartialPiece gone = partialPieces.remove(max);
if (_log.shouldLog(Log.INFO))
_log.info("Discarding orphaned partial piece (list full)" + gone);
}
} // else drop the empty partial piece
// synchs on wantedPieces...
markUnrequestedIfOnlyOne(peer, pp.getPiece());
}
if (_log.shouldLog(Log.INFO))
_log.info("Partial list size now: " + partialPieces.size());
}
savedRequest = req;
savedRequestTime = System.currentTimeMillis();
} else {
if (req.piece != savedRequest.piece)
if (_log.shouldLog(Log.DEBUG))
_log.debug(" Discarding orphaned partial piece " + req);
}
}
/** Return partial piece if it's still wanted and peer has it.
/**
* Return partial piece to the PeerState if it's still wanted and peer has it.
* @param havePieces pieces the peer has, the rv will be one of these
*
* @return PartialPiece or null
* @since 0.8.2
*/
public Request getPeerPartial(BitField havePieces) {
if (savedRequest == null)
return null;
if (! havePieces.get(savedRequest.piece)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer doesn't have orphaned piece " + savedRequest);
return null;
}
synchronized(wantedPieces)
{
for(Iterator<Piece> iter = wantedPieces.iterator(); iter.hasNext(); ) {
Piece piece = iter.next();
if (piece.getId() == savedRequest.piece) {
Request req = savedRequest;
piece.setRequested(true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Restoring orphaned partial piece " + req);
savedRequest = null;
return req;
public PartialPiece getPartialPiece(Peer peer, BitField havePieces) {
// do it in this order to avoid deadlock (same order as in savePartialPieces())
synchronized(partialPieces) {
synchronized(wantedPieces) {
// sorts by remaining bytes, least first
Collections.sort(partialPieces);
for (Iterator<PartialPiece> iter = partialPieces.iterator(); iter.hasNext(); ) {
PartialPiece pp = iter.next();
int savedPiece = pp.getPiece();
if (havePieces.get(savedPiece)) {
// this is just a double-check, it should be in there
for(Piece piece : wantedPieces) {
if (piece.getId() == savedPiece) {
piece.setRequested(true);
iter.remove();
if (_log.shouldLog(Log.INFO)) {
_log.info("Restoring orphaned partial piece " + pp +
" Partial list size now: " + partialPieces.size());
}
return pp;
}
}
}
}
}
}
// ...and this section turns this into the general move-requests-around code!
// Temporary? So PeerState never calls wantPiece() directly for now...
int piece = wantPiece(peer, havePieces);
if (piece >= 0) {
try {
return new PartialPiece(piece, metainfo.getPieceLength(piece));
} catch (OutOfMemoryError oom) {
if (_log.shouldLog(Log.WARN))
_log.warn("OOM creating new partial piece");
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("We have no partial piece to return");
return null;
}
/**
* Remove saved state for this piece.
* Unless we are in the end game there shouldnt be anything in there.
* Do not call with wantedPieces lock held (deadlock)
*/
private void removePartialPiece(int piece) {
synchronized(partialPieces) {
for (Iterator<PartialPiece> iter = partialPieces.iterator(); iter.hasNext(); ) {
PartialPiece pp = iter.next();
if (pp.getPiece() == piece) {
iter.remove();
// there should be only one but keep going to be sure
}
}
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("We no longer want orphaned piece " + savedRequest);
savedRequest = null;
return null;
}
/** Clear the requested flag for a piece if the peer
@ -947,13 +1009,12 @@ public class PeerCoordinator implements PeerListener
continue;
if (p.state == null)
continue;
int[] arr = p.state.getRequestedPieces();
for (int i = 0; arr[i] >= 0; i++)
if(arr[i] == piece) {
// FIXME don't go into the state
if (p.state.getRequestedPieces().contains(Integer.valueOf(piece))) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Another peer is requesting piece " + piece);
return;
}
}
}
}
@ -973,20 +1034,6 @@ public class PeerCoordinator implements PeerListener
}
}
/** Mark a peer's requested pieces unrequested when it is disconnected
** Once for each piece
** This is enough trouble, maybe would be easier just to regenerate
** the requested list from scratch instead.
*/
public void markUnrequested(Peer peer)
{
if (halted || peer.state == null)
return;
int[] arr = peer.state.getRequestedPieces();
for (int i = 0; arr[i] >= 0; i++)
markUnrequestedIfOnlyOne(peer, arr[i]);
}
/** Return number of allowed uploaders for this torrent.
** Check with Snark to see if we are over the total upload limit.
*/

View File

@ -20,10 +20,12 @@
package org.klomp.snark;
import java.util.List;
/**
* Listener for Peer events.
*/
public interface PeerListener
interface PeerListener
{
/**
* Called when the connection to the peer has started and the
@ -151,7 +153,7 @@ public interface PeerListener
*
* @param state the PeerState for the peer
*/
void savePeerPartial(PeerState state); /* FIXME Exporting non-public type through public API FIXME */
void savePartialPieces(Peer peer, List<PartialPiece> pcs);
/**
* Called when a peer has connected and there may be a partially
@ -161,12 +163,5 @@ public interface PeerListener
*
* @return request (contains the partial data and valid length)
*/
Request getPeerPartial(BitField havePieces); /* FIXME Exporting non-public type through public API FIXME */
/** Mark a peer's requested pieces unrequested when it is disconnected
* This prevents premature end game
*
* @param peer the peer that is disconnecting
*/
void markUnrequested(Peer peer);
PartialPiece getPartialPiece(Peer peer, BitField havePieces);
}

View File

@ -23,9 +23,11 @@ package org.klomp.snark;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
@ -36,9 +38,9 @@ import org.klomp.snark.bencode.BEValue;
class PeerState implements DataLoader
{
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
final Peer peer;
private final Peer peer;
final PeerListener listener;
final MetaInfo metainfo;
private final MetaInfo metainfo;
// Interesting and choking describes whether we are interested in or
// are choking the other side.
@ -54,6 +56,7 @@ class PeerState implements DataLoader
long downloaded;
long uploaded;
/** the pieces the peer has */
BitField bitfield;
// Package local for use by Peer.
@ -102,6 +105,12 @@ class PeerState implements DataLoader
if (interesting && !choked)
request(resend);
if (choked) {
// TODO
// savePartialPieces
// clear request list
}
}
void interestedMessage(boolean interest)
@ -308,8 +317,11 @@ class PeerState implements DataLoader
}
}
/**
* @return index in outstandingRequests or -1
*/
synchronized private int getFirstOutstandingRequest(int piece)
{
{
for (int i = 0; i < outstandingRequests.size(); i++)
if (outstandingRequests.get(i).piece == piece)
return i;
@ -397,54 +409,56 @@ class PeerState implements DataLoader
}
// get longest partial piece
synchronized Request getPartialRequest()
{
Request req = null;
for (int i = 0; i < outstandingRequests.size(); i++) {
Request r1 = outstandingRequests.get(i);
int j = getFirstOutstandingRequest(r1.piece);
if (j == -1)
continue;
Request r2 = outstandingRequests.get(j);
if (r2.off > 0 && ((req == null) || (r2.off > req.off)))
req = r2;
}
if (pendingRequest != null && req != null && pendingRequest.off < req.off) {
if (pendingRequest.off != 0)
req = pendingRequest;
else
req = null;
}
return req;
/**
* @return lowest offset of any request for the piece
* @since 0.8.2
*/
synchronized private Request getLowestOutstandingRequest(int piece) {
Request rv = null;
int lowest = Integer.MAX_VALUE;
for (Request r : outstandingRequests) {
if (r.piece == piece && r.off < lowest) {
lowest = r.off;
rv = r;
}
}
if (pendingRequest != null &&
pendingRequest.piece == piece && pendingRequest.off < lowest)
rv = pendingRequest;
if (_log.shouldLog(Log.DEBUG))
_log.debug(peer + " lowest for " + piece + " is " + rv + " out of " + pendingRequest + " and " + outstandingRequests);
return rv;
}
/**
* return array of pieces terminated by -1
* remove most duplicates
* but still could be some duplicates, not guaranteed
* TODO rework this Java-style to return a Set or a List
* get partial pieces, give them back to PeerCoordinator
* @return List of PartialPieces, even those with an offset == 0, or empty list
* @since 0.8.2
*/
synchronized int[] getRequestedPieces()
synchronized List<PartialPiece> returnPartialPieces()
{
int size = outstandingRequests.size();
int[] arr = new int[size+2];
int pc = -1;
int pos = 0;
if (pendingRequest != null) {
pc = pendingRequest.piece;
arr[pos++] = pc;
}
Request req = null;
for (int i = 0; i < size; i++) {
Request r1 = outstandingRequests.get(i);
if (pc != r1.piece) {
pc = r1.piece;
arr[pos++] = pc;
Set<Integer> pcs = getRequestedPieces();
List<PartialPiece> rv = new ArrayList(pcs.size());
for (Integer p : pcs) {
Request req = getLowestOutstandingRequest(p.intValue());
if (req != null)
rv.add(new PartialPiece(req));
}
}
arr[pos] = -1;
return(arr);
return rv;
}
/**
* @return all pieces we are currently requesting, or empty Set
*/
synchronized Set<Integer> getRequestedPieces() {
Set<Integer> rv = new HashSet(outstandingRequests.size() + 1);
for (Request req : outstandingRequests) {
rv.add(Integer.valueOf(req.piece));
if (pendingRequest != null)
rv.add(Integer.valueOf(pendingRequest.piece));
}
return rv;
}
void cancelMessage(int piece, int begin, int length)
@ -555,6 +569,8 @@ class PeerState implements DataLoader
{
synchronized (this) {
out.sendRequests(outstandingRequests);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Resending requests to " + peer + outstandingRequests);
}
}
@ -620,24 +636,17 @@ class PeerState implements DataLoader
if (bitfield != null)
{
// Check for adopting an orphaned partial piece
Request r = listener.getPeerPartial(bitfield);
if (r != null) {
// Check that r not already in outstandingRequests
int[] arr = getRequestedPieces();
boolean found = false;
for (int i = 0; arr[i] >= 0; i++) {
if (arr[i] == r.piece) {
found = true;
break;
}
}
if (!found) {
PartialPiece pp = listener.getPartialPiece(peer, bitfield);
if (pp != null) {
// Double-check that r not already in outstandingRequests
if (!getRequestedPieces().contains(Integer.valueOf(pp.getPiece()))) {
Request r = pp.getRequest();
outstandingRequests.add(r);
if (!choked)
out.sendRequest(r);
lastRequest = r;
return true;
}
}
}
// Note that in addition to the bitfield, PeerCoordinator uses

View File

@ -5,7 +5,10 @@ import java.util.Set;
import net.i2p.util.ConcurrentHashSet;
public class Piece implements Comparable {
/**
* This class is used solely by PeerCoordinator.
*/
class Piece implements Comparable {
private int id;
private Set<PeerID> peers;

View File

@ -22,6 +22,7 @@ package org.klomp.snark;
/**
* Holds all information needed for a partial piece request.
* This class should be used only by PeerState, PeerConnectionIn, and PeerConnectionOut.
*/
class Request
{

View File

@ -92,6 +92,11 @@
<!-- jar again to get the latest messages_*.class files -->
<jar destfile="./build/routerconsole.jar" basedir="./build/obj" includes="**/*.class" update="true" />
</target>
<target name="jarWithJavadoc" depends="jar">
<jar destfile="build/routerconsole.war" basedir="../../../build/" includes="javadoc/**/*" update="true" />
</target>
<target name="poupdate" depends="build">
<ant target="war" />
<!-- Update the messages_*.po files.

View File

@ -6,13 +6,11 @@ import java.util.Locale;
import net.i2p.util.FileUtil;
public class ContentHelper extends HelperBase {
private String _page;
protected String _page;
private int _maxLines;
private boolean _startAtBeginning;
private String _lang;
public ContentHelper() {}
/**
* Caution, use absolute paths only, do not assume files are in CWD
*/

View File

@ -0,0 +1,20 @@
package net.i2p.router.web;
import java.io.File;
/**
* If news file does not exist, use file from the initialNews directory
* in $I2P
*
* @since 0.8.2
*/
public class NewsHelper extends ContentHelper {
@Override
public String getContent() {
File news = new File(_page);
if (!news.exists())
_page = (new File(_context.getBaseDir(), "docs/initialNews/initialNews.xml")).getAbsolutePath();
return super.getContent();
}
}

View File

@ -14,7 +14,8 @@ if (System.getProperty("router.consoleNonce") == null) {
<%@include file="summary.jsi" %><h1><%=intl._("I2P Router Console")%></h1>
<div class="news" id="news">
<jsp:useBean class="net.i2p.router.web.ContentHelper" id="newshelper" scope="request" />
<jsp:useBean class="net.i2p.router.web.NewsHelper" id="newshelper" scope="request" />
<jsp:setProperty name="newshelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<% java.io.File fpath = new java.io.File(net.i2p.I2PAppContext.getGlobalContext().getRouterDir(), "docs/news.xml"); %>
<jsp:setProperty name="newshelper" property="page" value="<%=fpath.getAbsolutePath()%>" />
<jsp:setProperty name="newshelper" property="maxLines" value="300" />

View File

@ -413,8 +413,6 @@
<copy file="history.txt" todir="pkg-temp/" overwrite="true" />
<mkdir dir="pkg-temp/scripts" />
<copy file="apps/proxyscript/i2pProxy.pac" todir="pkg-temp/scripts/" />
<!-- overwrite the news put in by the updater -->
<copy file="installer/resources/initialNews.xml" tofile="pkg-temp/docs/news.xml" overwrite="true" />
<copy file="installer/resources/startconsole.html" todir="pkg-temp/docs/" />
<copy file="installer/resources/start.ico" todir="pkg-temp/docs/" />
<copy file="installer/resources/console.ico" todir="pkg-temp/docs/" />
@ -476,8 +474,12 @@
<delete dir="pkg-temp" />
</target>
<!-- readme and proxy error page files, GeoIP files, and flag icons -->
<target name="prepConsoleDocs" depends="prepConsoleDocUpdates, prepgeoupdate" />
<!-- readme and proxy error page files, initialNews.xml files, GeoIP files, and flag icons -->
<target name="prepConsoleDocs" depends="prepConsoleDocUpdates, prepgeoupdate" >
<copy todir="pkg-temp/docs/" >
<fileset dir="installer/resources/initialNews/" />
</copy>
</target>
<!-- readme and proxy error page files -->
<target name="prepConsoleDocUpdates">
@ -766,7 +768,6 @@
<exec executable="ls" failonerror="true">
<arg value="-l" />
<arg value="history.txt" />
<arg value="installer/resources/initialNews.xml" />
<arg value="installer/install.xml" />
<arg value="installer/resources/news.xml" />
<arg value="core/java/src/net/i2p/CoreVersion.java" />

View File

@ -19,6 +19,10 @@ import net.i2p.util.Log;
* Defines the actual payload of a message being delivered, including the
* standard encryption wrapping, as defined by the I2P data structure spec.
*
* This is used mostly in I2CP, where we used to do end-to-end encryption.
* Since we don't any more, you probably just want to use the
* get/set EncryptedData methods.
*
* @author jrandom
*/
public class Payload extends DataStructureImpl {
@ -32,6 +36,9 @@ public class Payload extends DataStructureImpl {
/**
* Retrieve the unencrypted body of the message.
*
* Deprecated.
* Unless you are doing encryption, use getEncryptedData() instead.
*
* @return body of the message, or null if the message has either not been
* decrypted yet or if the hash is not correct
*/
@ -43,15 +50,19 @@ public class Payload extends DataStructureImpl {
* Populate the message body with data. This does not automatically encrypt
* yet.
*
* Deprecated.
* Unless you are doing encryption, use setEncryptedData() instead.
*/
public void setUnencryptedData(byte[] data) {
_unencryptedData = data;
}
/** the real data */
public byte[] getEncryptedData() {
return _encryptedData;
}
/** the real data */
public void setEncryptedData(byte[] data) {
_encryptedData = data;
}
@ -100,7 +111,7 @@ public class Payload extends DataStructureImpl {
@Override
public int hashCode() {
return DataHelper.hashCode(_unencryptedData);
return DataHelper.hashCode(_encryptedData != null ? _encryptedData : _unencryptedData);
}
@Override

View File

@ -23,6 +23,7 @@ import net.i2p.crypto.DSAEngine;
* This helper class reads and writes files in the
* same "eepPriv.dat" format used by the client code.
* The format is:
*<pre>
* - Destination (387 bytes if no certificate, otherwise longer)
* - Public key (256 bytes)
* - Signing Public key (128 bytes)
@ -32,6 +33,7 @@ import net.i2p.crypto.DSAEngine;
* - Private key (256 bytes)
* - Signing Private key (20 bytes)
* Total 663 bytes
*</pre>
*
* @author welterde, zzz
*/

View File

@ -66,8 +66,8 @@ public class LogManager {
public final static String DEFAULT_DEFAULTLEVEL = Log.STR_ERROR;
public final static String DEFAULT_ONSCREENLEVEL = Log.STR_CRIT;
private I2PAppContext _context;
private Log _log;
private final I2PAppContext _context;
private final Log _log;
/** when was the config file last read (or -1 if never) */
private long _configLastRead;
@ -75,11 +75,11 @@ public class LogManager {
/** the config file */
private File _locationFile;
/** Ordered list of LogRecord elements that have not been written out yet */
private LinkedBlockingQueue<LogRecord> _records;
private final LinkedBlockingQueue<LogRecord> _records;
/** List of explicit overrides of log levels (LogLimit objects) */
private Set<LogLimit> _limits;
private final Set<LogLimit> _limits;
/** String (scope) or Log.LogScope to Log object */
private ConcurrentHashMap<Object, Log> _logs;
private final ConcurrentHashMap<Object, Log> _logs;
/** who clears and writes our records */
private LogWriter _writer;
@ -108,7 +108,7 @@ public class LogManager {
/** how many records we want to buffer in the "recent logs" list */
private int _consoleBufferSize;
/** the actual "recent logs" list */
private LogConsoleBuffer _consoleBuffer;
private final LogConsoleBuffer _consoleBuffer;
private boolean _alreadyNoticedMissingConfig;
@ -119,17 +119,17 @@ public class LogManager {
_limits = new ConcurrentHashSet();
_logs = new ConcurrentHashMap(128);
_defaultLimit = Log.ERROR;
_configLastRead = 0;
_context = context;
_log = getLog(LogManager.class);
String location = context.getProperty(CONFIG_LOCATION_PROP, CONFIG_LOCATION_DEFAULT);
setConfig(location);
_consoleBuffer = new LogConsoleBuffer(context);
_writer = new LogWriter(this);
Thread t = new I2PThread(_writer);
t.setName("LogWriter");
t.setDaemon(true);
t.start();
// If we aren't in the router context, delay creating the LogWriter until required,
// so it doesn't create a log directory and log files unless there is output.
// In the router context, we have to rotate to a new log file at startup or the logs.jsp
// page will display the old log.
if (context.isRouterContext())
startLogWriter();
try {
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
} catch (IllegalStateException ise) {
@ -138,7 +138,14 @@ public class LogManager {
//System.out.println("Created logManager " + this + " with context: " + context);
}
private LogManager() { // nop
/** @since 0.8.2 */
private synchronized void startLogWriter() {
// yeah, this doesn't always work, _writer should be volatile
if (_writer != null)
return;
_writer = new LogWriter(this);
Thread t = new I2PThread(_writer, "LogWriter", true);
t.start();
}
public Log getLog(Class cls) { return getLog(cls, null); }
@ -169,6 +176,7 @@ public class LogManager {
public LogConsoleBuffer getBuffer() { return _consoleBuffer; }
/** @deprecated unused */
public void setDisplayOnScreen(boolean yes) {
_displayOnScreen = yes;
}
@ -181,6 +189,7 @@ public class LogManager {
return _onScreenLimit;
}
/** @deprecated unused */
public void setDisplayOnScreenLevel(int level) {
_onScreenLimit = level;
}
@ -189,6 +198,7 @@ public class LogManager {
return _consoleBufferSize;
}
/** @deprecated unused */
public void setConsoleBufferSize(int numRecords) {
_consoleBufferSize = numRecords;
}
@ -201,6 +211,8 @@ public class LogManager {
}
public String currentFile() {
if (_writer == null)
return ("No log file created yet");
return _writer.currentFile();
}
@ -209,6 +221,9 @@ public class LogManager {
*
*/
void addRecord(LogRecord record) {
if ((!_context.isRouterContext()) && _writer == null)
startLogWriter();
_records.offer(record);
int numRecords = _records.size();
@ -617,9 +632,11 @@ public class LogManager {
}
public void shutdown() {
_log.log(Log.WARN, "Shutting down logger");
_writer.flushRecords(false);
_writer.stopWriting();
if (_writer != null) {
_log.log(Log.WARN, "Shutting down logger");
_writer.flushRecords(false);
_writer.stopWriting();
}
}
private static int __id = 0;

View File

@ -1,3 +1,12 @@
2010-11-27 zzz
* Console: Split initialNews.xml into a file for each language
don't copy to config dir at install.
* i2psnark: Clean up and enhance the PeerCoordinator's partial piece handling,
in preparation for more improvements
* LogManager: When not in router context, delay creating log file until required
* NetDb: Lower RouterInfo expiration time again
* Router: Prevent NCDFE after unzipping update file
2010-11-26 dr|z3d
* Readme: Overhaul (English) layout and text.

View File

@ -1,127 +0,0 @@
<!--
<i2p.news date="$Date: 2010-11-15 00:00:00 $">
<i2p.release version="0.8.1" date="2010/11/15" minVersion="0.6"/>
-->
<div lang="en">
<h4><ul><li>Congratulations on getting I2P installed!</li></ul></h4>
<p>
<b>Welcome to I2P!</b>
Please <b>have patience</b> as I2P boots up and finds peers.
</p>
<p>
While you are waiting, please <b>adjust your bandwidth settings</b> on the
<a href="config.jsp">configuration page</a>.
</p>
<p>
Once you have a "shared clients" destination listed on the left,
please <b>check out</b> our
<a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
Point your IRC client to <b>localhost:6668</b> and say hi to us on
<a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> or <a href="irc://127.0.0.1:6668/i2p">#i2p</a>.
</p>
</div>
<div lang="de">
<h4><ul><li>Wir gratulieren zur erfolgreichen Installation von I2P!</li></ul></h4>
<p>
<b>Willkommen im I2P!</b>
Hab noch <b>etwas Geduld</b>, w&auml;hrend I2P startet und weitere I2P-Router findet.
</p>
<p>
Passe bitte in der Zwischenzeit <b>deine Einstellungen zur Bandbreite</b> auf der
<a href="config.jsp">Einstellungsseite</a> an!
</p>
<p>
Sobald auf der linken Seite eine Verbindung namens "versch. Klienten" aufgelistet ist, kannst Du unsere <a href="http://www.i2p2.i2p/faq_de.html">FAQ</a> besuchen.
</p>
<p>
Verbinde deinen IRC-Klienten mit dem Server auf <b>localhost:6668</b> und schau bei uns im Kanal
<a href="irc://127.0.0.1:6668/i2p-de">#i2p-de</a>, <a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> oder <a href="irc://127.0.0.1:6668/i2p">#i2p</a> vorbei!
</p>
<p>
Wir wünschen Dir viel Freude an unserem Netz und hoffen, Deine Erwartungen zu erfüllen.
</p>
</div>
<div lang="es">
<h4><ul><li>&iexcl;Felicidades!, has instalado el enrutador I2P con &eacute;xito.</li></ul></h4>
<p>
<b>&iexcl;Bienvenido a I2P!</b><br>
&iexcl;Ten todav&iacute;a <b>paciencia</b> mientras I2P est&eacute; arrancando y encontrando otros enrutadores I2P!
</p>
<p>
Este es el momento ideal para adaptar tu <b>configuraci&oacute;n de ancho de banda</b> en la
<a href="config.jsp">p&aacute;gina de configuraci&oacute;n</a>.
</p>
<p>
En cuanto veas a la izquierda una conexi&oacute;n llamada "shared clients", puedes visitar nuestros <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
&iexcl;Con&eacute;cta tu cliente IRC con el servidor <b>localhost:6668</b> y ven a saludarnos en los canales
<a href="irc://127.0.0.1:6668/i2p-es">#i2p-es</a>, <a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> o <a href="irc://127.0.0.1:6668/i2p">#i2p</a>!
</p>
<p>
Esperemos que tengas una buena experiencia con y en I2P.
</p>
</div>
<div lang="br">
<h4><ul><li>Parabéns, você instalou o roteador I2P com êxito!</li></ul></h4>
<p>
<b>Bem-vindo ao I2P!</b><br>
Seja <b>paciente</b> enquanto I2P ainda está iniciando-se e enquanto continuam sendo encontrados outros roteadores I2P!
</p>
<p>
Este é o momento ideal para personalizar a <b>configuração de largura de banda</b> na
<a href="config.jsp">página de configuração</a>.
</p>
<p>
Quando você vê uma conexão no lado esquerdo chamada "shared clients", você pode visitar os nossos <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
Conecte seu cliente de IRC para o servidor <b>localhost:6668</b> e vem para nos cumprimentar aos canais
<a href="irc://127.0.0.1:6668/i2p-br">#i2p-br</a>, <a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> ou <a href="irc://127.0.0.1:6668/i2p">#i2p</a>!
</p>
<p>
Esperamos que você tenha uma boa experiência e I2P.
</p>
</div>
<div lang="nl">
<h4><ul><li>Gefeliciteerd met de installatie van I2P!</li></ul></h4>
<p>
<b>Welkom bij I2P!</b>
Heb <b>wat geduld</b> terwijl I2P opstart en peers zoekt.
</p>
<p>
Terwijl je wacht, <b>pas je bandbreedte instellingen aan</b> op de
<a href="config.jsp">configuratie pagina</a>.
</p>
<p>
Wanneer je een "gedeelde clients" destination in de linker lijst hebt,
<b>lees dan aub</b> onze <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
Verbind je IRC client met <b>localhost:6668</b> en zeg Hallo in
<a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> of <a href="irc://127.0.0.1:6668/i2p">#i2p</a>.
</p>
</div>
<div lang="ru">
<h4><ul><li>Поздравляем с успешным завершением установки I2P!</li></ul></h4>
<p>
<b>Добро пожаловать в I2P!</b> Немного терпения! I2P-маршрутизатору потребуется пара минут для запуска модулей и первого подключения к сети I2P.
</p>
<p>
Пока Вы ждете, самое время зайти в <a href="config.jsp">сетевые настройки</a> и <b>выставить ограничение скорости</b> в соответствии со скоростью Вашего подключения к интернету.
</p>
<p>
Как только в панели слева в разделе «Локальные туннели» появится запись «коллективные клиенты» — I2P готов к работе. Подключайте Ваш IRC-клиент к серверу <b>localhost:6668</b> и заходите сказать нам привет на канал
<a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> и <a href="irc://127.0.0.1:6668/i2p">#i2p</a>.
</p>
<p>
<b>Не забудьте заглянуть</b> в наш <a href="http://www.i2p2.i2p/faq_ru.html">FAQ</a>.
</p>
</div>

View File

@ -0,0 +1,20 @@
<div lang="en">
<h4><ul><li>Congratulations on getting I2P installed!</li></ul></h4>
<p>
<b>Welcome to I2P!</b>
Please <b>have patience</b> as I2P boots up and finds peers.
</p>
<p>
While you are waiting, please <b>adjust your bandwidth settings</b> on the
<a href="config.jsp">configuration page</a>.
</p>
<p>
Once you have a "shared clients" destination listed on the left,
please <b>check out</b> our
<a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
Point your IRC client to <b>localhost:6668</b> and say hi to us on
<a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> or <a href="irc://127.0.0.1:6668/i2p">#i2p</a>.
</p>
</div>

View File

@ -0,0 +1,21 @@
<div lang="br">
<h4><ul><li>Parabéns, você instalou o roteador I2P com êxito!</li></ul></h4>
<p>
<b>Bem-vindo ao I2P!</b><br>
Seja <b>paciente</b> enquanto I2P ainda está iniciando-se e enquanto continuam sendo encontrados outros roteadores I2P!
</p>
<p>
Este é o momento ideal para personalizar a <b>configuração de largura de banda</b> na
<a href="config.jsp">página de configuração</a>.
</p>
<p>
Quando você vê uma conexão no lado esquerdo chamada "shared clients", você pode visitar os nossos <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
Conecte seu cliente de IRC para o servidor <b>localhost:6668</b> e vem para nos cumprimentar aos canais
<a href="irc://127.0.0.1:6668/i2p-br">#i2p-br</a>, <a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> ou <a href="irc://127.0.0.1:6668/i2p">#i2p</a>!
</p>
<p>
Esperamos que você tenha uma boa experiência e I2P.
</p>
</div>

View File

@ -0,0 +1,21 @@
<div lang="de">
<h4><ul><li>Wir gratulieren zur erfolgreichen Installation von I2P!</li></ul></h4>
<p>
<b>Willkommen im I2P!</b>
Hab noch <b>etwas Geduld</b>, w&auml;hrend I2P startet und weitere I2P-Router findet.
</p>
<p>
Passe bitte in der Zwischenzeit <b>deine Einstellungen zur Bandbreite</b> auf der
<a href="config.jsp">Einstellungsseite</a> an!
</p>
<p>
Sobald auf der linken Seite eine Verbindung namens "versch. Klienten" aufgelistet ist, kannst Du unsere <a href="http://www.i2p2.i2p/faq_de.html">FAQ</a> besuchen.
</p>
<p>
Verbinde deinen IRC-Klienten mit dem Server auf <b>localhost:6668</b> und schau bei uns im Kanal
<a href="irc://127.0.0.1:6668/i2p-de">#i2p-de</a>, <a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> oder <a href="irc://127.0.0.1:6668/i2p">#i2p</a> vorbei!
</p>
<p>
Wir wünschen Dir viel Freude an unserem Netz und hoffen, Deine Erwartungen zu erfüllen.
</p>
</div>

View File

@ -0,0 +1,21 @@
<div lang="es">
<h4><ul><li>&iexcl;Felicidades!, has instalado el enrutador I2P con &eacute;xito.</li></ul></h4>
<p>
<b>&iexcl;Bienvenido a I2P!</b><br>
&iexcl;Ten todav&iacute;a <b>paciencia</b> mientras I2P est&eacute; arrancando y encontrando otros enrutadores I2P!
</p>
<p>
Este es el momento ideal para adaptar tu <b>configuraci&oacute;n de ancho de banda</b> en la
<a href="config.jsp">p&aacute;gina de configuraci&oacute;n</a>.
</p>
<p>
En cuanto veas a la izquierda una conexi&oacute;n llamada "shared clients", puedes visitar nuestros <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
&iexcl;Con&eacute;cta tu cliente IRC con el servidor <b>localhost:6668</b> y ven a saludarnos en los canales
<a href="irc://127.0.0.1:6668/i2p-es">#i2p-es</a>, <a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> o <a href="irc://127.0.0.1:6668/i2p">#i2p</a>!
</p>
<p>
Esperemos que tengas una buena experiencia con y en I2P.
</p>
</div>

View File

@ -0,0 +1,19 @@
<div lang="nl">
<h4><ul><li>Gefeliciteerd met de installatie van I2P!</li></ul></h4>
<p>
<b>Welkom bij I2P!</b>
Heb <b>wat geduld</b> terwijl I2P opstart en peers zoekt.
</p>
<p>
Terwijl je wacht, <b>pas je bandbreedte instellingen aan</b> op de
<a href="config.jsp">configuratie pagina</a>.
</p>
<p>
Wanneer je een "gedeelde clients" destination in de linker lijst hebt,
<b>lees dan aub</b> onze <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
</p>
<p>
Verbind je IRC client met <b>localhost:6668</b> en zeg Hallo in
<a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> of <a href="irc://127.0.0.1:6668/i2p">#i2p</a>.
</p>
</div>

View File

@ -0,0 +1,16 @@
<div lang="ru">
<h4><ul><li>Поздравляем с успешным завершением установки I2P!</li></ul></h4>
<p>
<b>Добро пожаловать в I2P!</b> Немного терпения! I2P-маршрутизатору потребуется пара минут для запуска модулей и первого подключения к сети I2P.
</p>
<p>
Пока Вы ждете, самое время зайти в <a href="config.jsp">сетевые настройки</a> и <b>выставить ограничение скорости</b> в соответствии со скоростью Вашего подключения к интернету.
</p>
<p>
Как только в панели слева в разделе «Локальные туннели» появится запись «коллективные клиенты» — I2P готов к работе. Подключайте Ваш IRC-клиент к серверу <b>localhost:6668</b> и заходите сказать нам привет на канал
<a href="irc://127.0.0.1:6668/i2p-help">#i2p-help</a> и <a href="irc://127.0.0.1:6668/i2p">#i2p</a>.
</p>
<p>
<b>Не забудьте заглянуть</b> в наш <a href="http://www.i2p2.i2p/faq_ru.html">FAQ</a>.
</p>
</div>

View File

@ -191,7 +191,9 @@ public class Router {
// This is here so that we can get the directory location from the context
// for the ping file
if (!beginMarkingLiveliness()) {
// Check for other router but do not start a thread yet so the update doesn't cause
// a NCDFE
if (!isOnlyRouterRunning()) {
System.err.println("ERROR: There appears to be another router already running!");
System.err.println(" Please make sure to shut down old instances before starting up");
System.err.println(" a new one. If you are positive that no other instance is running,");
@ -215,6 +217,11 @@ public class Router {
// overwrite an existing running router's jar files. Other than ours.
installUpdates();
// ********* Start no threads before here ********* //
//
// NOW we can start the ping file thread.
beginMarkingLiveliness();
// Apps may use this as an easy way to determine if they are in the router JVM
// But context.isRouterContext() is even easier...
// Both of these as of 0.7.9
@ -1163,38 +1170,50 @@ public class Router {
// verify the whole thing first
// we could remember this fails, and not bother restarting, but who cares...
boolean ok = FileUtil.verifyZip(updateFile);
if (ok)
ok = FileUtil.extractZip(updateFile, _context.getBaseDir());
if (ok)
System.out.println("INFO: Update installed");
else
System.out.println("ERROR: Update failed!");
if (!ok) {
// we can't leave the file in place or we'll continually restart, so rename it
File bad = new File(_context.getRouterDir(), "BAD-" + UPDATE_FILE);
boolean renamed = updateFile.renameTo(bad);
if (renamed) {
System.out.println("Moved update file to " + bad.getAbsolutePath());
} else {
System.out.println("Deleting file " + updateFile.getAbsolutePath());
ok = true; // so it will be deleted
}
}
if (ok) {
// This may be useful someday. First added in 0.8.2
// Moved above the extract so we don't NCDFE
_config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
saveConfig();
boolean deleted = updateFile.delete();
if (!deleted) {
System.out.println("ERROR: Unable to delete the update file!");
updateFile.deleteOnExit();
}
ok = FileUtil.extractZip(updateFile, _context.getBaseDir());
}
// Very important - we have now trashed our jars.
// After this point, do not use any new I2P classes, or they will fail to load
// and we will die with NCDFE.
// Ideally, do not use I2P classes at all, new or not.
try {
if (ok)
System.out.println("INFO: Update installed");
else
System.out.println("ERROR: Update failed!");
if (!ok) {
// we can't leave the file in place or we'll continually restart, so rename it
File bad = new File(_context.getRouterDir(), "BAD-" + UPDATE_FILE);
boolean renamed = updateFile.renameTo(bad);
if (renamed) {
System.out.println("Moved update file to " + bad.getAbsolutePath());
} else {
System.out.println("Deleting file " + updateFile.getAbsolutePath());
ok = true; // so it will be deleted
}
}
if (ok) {
boolean deleted = updateFile.delete();
if (!deleted) {
System.out.println("ERROR: Unable to delete the update file!");
updateFile.deleteOnExit();
}
}
// exit whether ok or not
if (System.getProperty("wrapper.version") != null)
System.out.println("INFO: Restarting after update");
else
System.out.println("WARNING: Exiting after update, restart I2P");
} catch (Throwable t) {
// hide the NCDFE
// hopefully the update file got deleted or we will loop
}
// exit whether ok or not
if (System.getProperty("wrapper.version") != null)
System.out.println("INFO: Restarting after update");
else
System.out.println("WARNING: Exiting after update, restart I2P");
System.exit(EXIT_HARD_RESTART);
}
}
@ -1230,13 +1249,14 @@ public class Router {
static final long LIVELINESS_DELAY = 60*1000;
/**
* Start a thread that will periodically update the file "router.ping", but if
* Check the file "router.ping", but if
* that file already exists and was recently written to, return false as there is
* another instance running
* another instance running.
*
* @return true if the router is the only one running
* @since 0.8.2
*/
private boolean beginMarkingLiveliness() {
private boolean isOnlyRouterRunning() {
File f = getPingFile();
if (f.exists()) {
long lastWritten = f.lastModified();
@ -1247,12 +1267,20 @@ public class Router {
return false;
}
}
return true;
}
/**
* Start a thread that will periodically update the file "router.ping".
* isOnlyRouterRunning() MUST have been called previously.
*/
private void beginMarkingLiveliness() {
File f = getPingFile();
// not an I2PThread for context creation issues
Thread t = new Thread(new MarkLiveliness(_context, this, f));
t.setName("Mark router liveliness");
t.setDaemon(true);
t.start();
return true;
}
public static final String PROP_BANDWIDTH_SHARE_PERCENTAGE = "router.sharePercentage";

View File

@ -686,6 +686,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
return rv;
}
private static final int MIN_ROUTERS = 90;
/**
* Determine whether this routerInfo will be accepted as valid and current
* given what we know now.
@ -694,9 +696,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
long now = _context.clock().now();
boolean upLongEnough = _context.router().getUptime() > 60*60*1000;
// Once we're over 120 routers, reduce the expiration time down from the default,
// Once we're over MIN_ROUTERS routers, reduce the expiration time down from the default,
// as a crude way of limiting memory usage.
// i.e. at 300 routers the expiration time will be about half the default, etc.
// i.e. at 2*MIN_ROUTERS routers the expiration time will be about half the default, etc.
// And if we're floodfill, we can keep the expiration really short, since
// we are always getting the latest published to us.
// As the net grows this won't be sufficient, and we'll have to implement
@ -708,7 +710,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
// _kb.size() includes leasesets but that's ok
adjustedExpiration = Math.min(ROUTER_INFO_EXPIRATION,
ROUTER_INFO_EXPIRATION_MIN +
((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * 120 / (_kb.size() + 1)));
((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * MIN_ROUTERS / (_kb.size() + 1)));
if (!key.equals(routerInfo.getIdentity().getHash())) {
if (_log.shouldLog(Log.WARN))

View File

@ -149,7 +149,8 @@ public class WorkingDir {
// this one must be after MIGRATE_BASE
success &= migrateJettyXml(oldDirf, dirf);
success &= migrateClientsConfig(oldDirf, dirf);
success &= copy(new File(oldDirf, "docs/news.xml"), new SecureDirectory(dirf, "docs"));
// for later news.xml updates (we don't copy initialNews.xml over anymore)
success &= (new SecureDirectory(dirf, "docs")) .mkdir();
// Report success or failure
if (success) {

View File

@ -234,7 +234,7 @@ public class EstablishState {
System.arraycopy(_X, 0, xy, 0, _X.length);
System.arraycopy(_Y, 0, xy, _X.length, _Y.length);
Hash hxy = _context.sha().calculateHash(xy);
_tsB = _context.clock().now()/1000l; // our (Bob's) timestamp in seconds
_tsB = (_context.clock().now() + 500) / 1000l; // our (Bob's) timestamp in seconds
byte padding[] = new byte[12]; // the encrypted data needs an extra 12 bytes
_context.random().nextBytes(padding);
byte toEncrypt[] = new byte[hxy.getData().length+4+padding.length];
@ -387,7 +387,7 @@ public class EstablishState {
return;
}
_tsB = DataHelper.fromLong(hXY_tsB, Hash.HASH_LENGTH, 4); // their (Bob's) timestamp in seconds
_tsA = _context.clock().now()/1000; // our (Alice's) timestamp in seconds
_tsA = (_context.clock().now() + 500) / 1000; // our (Alice's) timestamp in seconds
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix()+"h(X+Y) is correct, tsA-tsB=" + (_tsA-_tsB));

View File

@ -1035,7 +1035,7 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
*
*/
private void readMeta(byte unencrypted[]) {
long ourTs = _context.clock().now()/1000;
long ourTs = (_context.clock().now() + 500) / 1000;
long ts = DataHelper.fromLong(unencrypted, 2, 4);
Adler32 crc = new Adler32();
crc.update(unencrypted, 0, unencrypted.length-4);
@ -1068,7 +1068,7 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
synchronized (_meta) {
_context.random().nextBytes(_meta); // randomize the uninterpreted, then overwrite w/ data
DataHelper.toLong(_meta, 0, 2, 0);
DataHelper.toLong(_meta, 2, 4, _context.clock().now()/1000);
DataHelper.toLong(_meta, 2, 4, (_context.clock().now() + 500) / 1000);
Adler32 crc = new Adler32();
crc.update(_meta, 0, _meta.length-4);
DataHelper.toLong(_meta, _meta.length-4, 4, crc.getValue());

View File

@ -72,9 +72,6 @@ class InboundEstablishState {
_alicePort = remotePort;
_remoteHostId = new RemoteHostId(_aliceIP, _alicePort);
_bobPort = localPort;
_keyBuilder = null;
_verificationAttempted = false;
_complete = false;
_currentState = STATE_UNKNOWN;
_establishBegin = ctx.clock().now();
}

View File

@ -86,13 +86,11 @@ class OutboundEstablishState {
}
_remotePeer = remotePeer;
_introKey = introKey;
_keyBuilder = null;
_queuedMessages = new LinkedBlockingQueue();
_currentState = STATE_UNKNOWN;
_establishBegin = ctx.clock().now();
_remoteAddress = addr;
_introductionNonce = -1;
_complete = false;
prepareSessionRequest();
if ( (addr != null) && (addr.getIntroducerCount() > 0) ) {
if (_log.shouldLog(Log.DEBUG))

View File

@ -47,7 +47,6 @@ class OutboundMessageFragments {
_transport = transport;
// _throttle = throttle;
_activePeers = new ArrayList(256);
_nextPeer = 0;
_builder = new PacketBuilder(ctx, transport);
_alive = true;
// _allowExcess = false;

View File

@ -47,9 +47,6 @@ class OutboundMessageState {
public OutboundMessageState(I2PAppContext context) {
_context = context;
_log = _context.logManager().getLog(OutboundMessageState.class);
_pushCount = 0;
_maxSends = 0;
// _nextSendFragment = 0;
}
public boolean initialize(OutNetMessage msg) {

View File

@ -1084,7 +1084,7 @@ class PacketBuilder {
// header
data[off] = flagByte;
off++;
long now = _context.clock().now() / 1000;
long now = (_context.clock().now() + 500) / 1000;
DataHelper.toLong(data, off, 4, now);
// todo: add support for rekeying and extended options
return packet;

View File

@ -63,8 +63,13 @@ class PeerState {
private boolean _rekeyBeganLocally;
/** when were the current cipher and MAC keys established/rekeyed? */
private long _keyEstablishedTime;
/** how far off is the remote peer from our clock, in milliseconds? */
/**
* How far off is the remote peer from our clock, in milliseconds?
* A positive number means our clock is ahead of theirs.
*/
private long _clockSkew;
/** what is the current receive second, for congestion control? */
private long _currentReceiveSecond;
/** when did we last send them a packet? */
@ -241,36 +246,19 @@ class PeerState {
_context = ctx;
_log = ctx.logManager().getLog(PeerState.class);
_transport = transport;
_remotePeer = null;
_currentMACKey = null;
_currentCipherKey = null;
_nextMACKey = null;
_nextCipherKey = null;
_nextKeyingMaterial = null;
_rekeyBeganLocally = false;
_keyEstablishedTime = -1;
_clockSkew = 0;
_currentReceiveSecond = -1;
_lastSendTime = -1;
_lastReceiveTime = -1;
_currentACKs = new ConcurrentHashSet();
_currentACKsResend = new LinkedBlockingQueue();
_currentSecondECNReceived = false;
_remoteWantsPreviousACKs = false;
_sendWindowBytes = DEFAULT_SEND_WINDOW_BYTES;
_sendWindowBytesRemaining = DEFAULT_SEND_WINDOW_BYTES;
_slowStartThreshold = MAX_SEND_WINDOW_BYTES/2;
_lastSendRefill = _context.clock().now();
_receivePeriodBegin = _lastSendRefill;
_sendBps = 0;
_sendBytes = 0;
_receiveBps = 0;
_lastCongestionOccurred = -1;
_remoteIP = null;
_remotePort = -1;
_remoteRequiresIntroduction = false;
_weRelayToThemAs = 0;
_theyRelayToUsAs = 0;
_mtu = getDefaultMTU();
_mtuReceive = _mtu;
_mtuLastChecked = -1;
@ -278,19 +266,8 @@ class PeerState {
_rto = MIN_RTO;
_rtt = _rto/2;
_rttDeviation = _rtt;
_messagesReceived = 0;
_messagesSent = 0;
_packetsTransmitted = 0;
_packetsRetransmitted = 0;
_packetRetransmissionRate = 0;
_retransmissionPeriodStart = 0;
_packetsReceived = 0;
_packetsReceivedDuplicate = 0;
_inboundMessages = new HashMap(8);
_outboundMessages = new ArrayList(32);
_dead = false;
_isInbound = false;
_lastIntroducerTime = 0;
_context.statManager().createRateStat("udp.congestionOccurred", "How large the cwin was when congestion occurred (duration == sendBps)", "udp", UDPTransport.RATES);
_context.statManager().createRateStat("udp.congestedRTO", "retransmission timeout after congestion (duration == rtt dev)", "udp", UDPTransport.RATES);
_context.statManager().createRateStat("udp.sendACKPartial", "Number of partial ACKs sent (duration == number of full ACKs in that ack packet)", "udp", UDPTransport.RATES);
@ -346,8 +323,13 @@ class PeerState {
public boolean getRekeyBeganLocally() { return _rekeyBeganLocally; }
/** when were the current cipher and MAC keys established/rekeyed? */
public long getKeyEstablishedTime() { return _keyEstablishedTime; }
/** how far off is the remote peer from our clock, in milliseconds? */
/**
* How far off is the remote peer from our clock, in milliseconds?
* A positive number means our clock is ahead of theirs.
*/
public long getClockSkew() { return _clockSkew ; }
/** what is the current receive second, for congestion control? */
public long getCurrentReceiveSecond() { return _currentReceiveSecond; }
/** when did we last send them a packet? */
@ -444,10 +426,17 @@ class PeerState {
public void setRekeyBeganLocally(boolean local) { _rekeyBeganLocally = local; }
/** when were the current cipher and MAC keys established/rekeyed? */
public void setKeyEstablishedTime(long when) { _keyEstablishedTime = when; }
/** how far off is the remote peer from our clock, in milliseconds? */
/**
* Update the moving-average clock skew based on the current difference.
* The raw skew will be adjusted for RTT/2 here.
* @param skew milliseconds, NOT adjusted for RTT.
* A positive number means our clock is ahead of theirs.
*/
public void adjustClockSkew(long skew) {
_clockSkew = (long) (0.9*(float)_clockSkew + 0.1*(float)skew);
_clockSkew = (long) (0.9*(float)_clockSkew + 0.1*(float)(skew - (_rtt / 2)));
}
/** what is the current receive second, for congestion control? */
public void setCurrentReceiveSecond(long sec) { _currentReceiveSecond = sec; }
/** when did we last send them a packet? */
@ -679,6 +668,7 @@ class PeerState {
*
*/
public List<Long> getCurrentFullACKs() {
// no such element exception seen here
ArrayList<Long> rv = new ArrayList(_currentACKs);
// include some for retransmission
rv.addAll(_currentACKsResend);

View File

@ -118,8 +118,6 @@ class PeerTestManager {
_activeTests = new ConcurrentHashMap();
_recentTests = new LinkedBlockingQueue();
_packetBuilder = new PacketBuilder(context, transport);
_currentTest = null;
_currentTestComplete = false;
_context.statManager().createRateStat("udp.statusKnownCharlie", "How often the bob we pick passes us to a charlie we already have a session with?", "udp", UDPTransport.RATES);
_context.statManager().createRateStat("udp.receiveTestReply", "How often we get a reply to our peer test?", "udp", UDPTransport.RATES);
_context.statManager().createRateStat("udp.receiveTest", "How often we get a packet requesting us to participate in a peer test?", "udp", UDPTransport.RATES);

View File

@ -76,7 +76,6 @@ class TimedWeightedPriorityMessageQueue implements MessageQueue, OutboundMessage
}
_alive = true;
_nextLock = this;
_nextQueue = 0;
_chokedPeers = Collections.synchronizedSet(new HashSet(16));
_listener = lsnr;
_context.statManager().createRateStat("udp.timeToEntrance", "Message lifetime until it reaches the UDP system", "udp", UDPTransport.RATES);

View File

@ -177,7 +177,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_peersByIdent = new ConcurrentHashMap(128);
_peersByRemoteHost = new ConcurrentHashMap(128);
_dropList = new ConcurrentHashSet(2);
_endpoint = null;
// See comments in DQAT.java
if (USE_PRIORITY) {