merge of 'b002d4a942128fdd4994a2cfba1c554ba9cb81d8'
and 'e6547920e2da9f540c79fcafc7ca7c82d25eae23'
This commit is contained in:
102
apps/i2psnark/java/src/org/klomp/snark/PartialPiece.java
Normal file
102
apps/i2psnark/java/src/org/klomp/snark/PartialPiece.java
Normal 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 + ')';
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import net.i2p.client.streaming.I2PSocket;
|
import net.i2p.client.streaming.I2PSocket;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
@ -368,8 +369,11 @@ public class Peer implements Comparable
|
|||||||
if (this.deregister) {
|
if (this.deregister) {
|
||||||
PeerListener p = s.listener;
|
PeerListener p = s.listener;
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
p.savePeerPartial(s);
|
List<PartialPiece> pcs = s.returnPartialPieces();
|
||||||
p.markUnrequested(this);
|
if (!pcs.isEmpty())
|
||||||
|
p.savePartialPieces(this, pcs);
|
||||||
|
// now covered by savePartialPieces
|
||||||
|
//p.markUnrequested(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state = null;
|
state = null;
|
||||||
|
@ -74,6 +74,9 @@ public class PeerCoordinator implements PeerListener
|
|||||||
// Some random wanted pieces
|
// Some random wanted pieces
|
||||||
private List<Piece> wantedPieces;
|
private List<Piece> wantedPieces;
|
||||||
|
|
||||||
|
/** partial pieces */
|
||||||
|
private final List<PartialPiece> partialPieces;
|
||||||
|
|
||||||
private boolean halted = false;
|
private boolean halted = false;
|
||||||
|
|
||||||
private final CoordinatorListener listener;
|
private final CoordinatorListener listener;
|
||||||
@ -94,6 +97,7 @@ public class PeerCoordinator implements PeerListener
|
|||||||
this.snark = torrent;
|
this.snark = torrent;
|
||||||
|
|
||||||
setWantedPieces();
|
setWantedPieces();
|
||||||
|
partialPieces = new ArrayList(getMaxConnections() + 1);
|
||||||
|
|
||||||
// Install a timer to check the uploaders.
|
// Install a timer to check the uploaders.
|
||||||
// Randomize the first start time so multiple tasks are spread out,
|
// Randomize the first start time so multiple tasks are spread out,
|
||||||
@ -293,7 +297,9 @@ public class PeerCoordinator implements PeerListener
|
|||||||
removePeerFromPieces(peer);
|
removePeerFromPieces(peer);
|
||||||
}
|
}
|
||||||
// delete any saved orphan partial piece
|
// delete any saved orphan partial piece
|
||||||
savedRequest = null;
|
synchronized (partialPieces) {
|
||||||
|
partialPieces.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connected(Peer peer)
|
public void connected(Peer peer)
|
||||||
@ -773,6 +779,9 @@ public class PeerCoordinator implements PeerListener
|
|||||||
wantedPieces.remove(p);
|
wantedPieces.remove(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// just in case
|
||||||
|
removePartialPiece(piece);
|
||||||
|
|
||||||
// Announce to the world we have it!
|
// Announce to the world we have it!
|
||||||
// Disconnect from other seeders when we get the last piece
|
// Disconnect from other seeders when we get the last piece
|
||||||
synchronized(peers)
|
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.
|
* and hopefully restart it later.
|
||||||
* Only one partial piece is saved at a time.
|
* Replace a partial piece in the List if the new one is bigger.
|
||||||
* Replace it if a new one is bigger or the old one is too old.
|
|
||||||
* Storage method is private so we can expand to save multiple partials
|
* Storage method is private so we can expand to save multiple partials
|
||||||
* if we wish.
|
* 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;
|
public void savePartialPieces(Peer peer, List<PartialPiece> partials)
|
||||||
private long savedRequestTime = 0;
|
|
||||||
public void savePeerPartial(PeerState state)
|
|
||||||
{
|
{
|
||||||
if (halted)
|
if (halted)
|
||||||
return;
|
return;
|
||||||
Request req = state.getPartialRequest();
|
if (_log.shouldLog(Log.INFO))
|
||||||
if (req == null)
|
_log.info("Partials received from " + peer + ": " + partials);
|
||||||
return;
|
synchronized(partialPieces) {
|
||||||
if (savedRequest == null ||
|
for (PartialPiece pp : partials) {
|
||||||
req.off > savedRequest.off ||
|
if (pp.getDownloaded() > 0) {
|
||||||
System.currentTimeMillis() > savedRequestTime + (15 * 60 * 1000)) {
|
// PartialPiece.equals() only compares piece number, which is what we want
|
||||||
if (savedRequest == null || (req.piece != savedRequest.piece && req.off != savedRequest.off)) {
|
int idx = partialPieces.indexOf(pp);
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
if (idx < 0) {
|
||||||
_log.debug(" Saving orphaned partial piece " + req);
|
partialPieces.add(pp);
|
||||||
if (savedRequest != null)
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.debug(" (Discarding previously saved orphan) " + savedRequest);
|
_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) {
|
public PartialPiece getPartialPiece(Peer peer, BitField havePieces) {
|
||||||
if (savedRequest == null)
|
// do it in this order to avoid deadlock (same order as in savePartialPieces())
|
||||||
return null;
|
synchronized(partialPieces) {
|
||||||
if (! havePieces.get(savedRequest.piece)) {
|
synchronized(wantedPieces) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
// sorts by remaining bytes, least first
|
||||||
_log.debug("Peer doesn't have orphaned piece " + savedRequest);
|
Collections.sort(partialPieces);
|
||||||
return null;
|
for (Iterator<PartialPiece> iter = partialPieces.iterator(); iter.hasNext(); ) {
|
||||||
}
|
PartialPiece pp = iter.next();
|
||||||
synchronized(wantedPieces)
|
int savedPiece = pp.getPiece();
|
||||||
{
|
if (havePieces.get(savedPiece)) {
|
||||||
for(Iterator<Piece> iter = wantedPieces.iterator(); iter.hasNext(); ) {
|
// this is just a double-check, it should be in there
|
||||||
Piece piece = iter.next();
|
for(Piece piece : wantedPieces) {
|
||||||
if (piece.getId() == savedRequest.piece) {
|
if (piece.getId() == savedPiece) {
|
||||||
Request req = savedRequest;
|
piece.setRequested(true);
|
||||||
piece.setRequested(true);
|
iter.remove();
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.INFO)) {
|
||||||
_log.debug("Restoring orphaned partial piece " + req);
|
_log.info("Restoring orphaned partial piece " + pp +
|
||||||
savedRequest = null;
|
" Partial list size now: " + partialPieces.size());
|
||||||
return req;
|
}
|
||||||
|
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
|
/** Clear the requested flag for a piece if the peer
|
||||||
@ -947,13 +1009,12 @@ public class PeerCoordinator implements PeerListener
|
|||||||
continue;
|
continue;
|
||||||
if (p.state == null)
|
if (p.state == null)
|
||||||
continue;
|
continue;
|
||||||
int[] arr = p.state.getRequestedPieces();
|
// FIXME don't go into the state
|
||||||
for (int i = 0; arr[i] >= 0; i++)
|
if (p.state.getRequestedPieces().contains(Integer.valueOf(piece))) {
|
||||||
if(arr[i] == piece) {
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Another peer is requesting piece " + piece);
|
_log.debug("Another peer is requesting piece " + piece);
|
||||||
return;
|
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.
|
/** Return number of allowed uploaders for this torrent.
|
||||||
** Check with Snark to see if we are over the total upload limit.
|
** Check with Snark to see if we are over the total upload limit.
|
||||||
*/
|
*/
|
||||||
|
@ -20,10 +20,12 @@
|
|||||||
|
|
||||||
package org.klomp.snark;
|
package org.klomp.snark;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for Peer events.
|
* Listener for Peer events.
|
||||||
*/
|
*/
|
||||||
public interface PeerListener
|
interface PeerListener
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Called when the connection to the peer has started and the
|
* 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
|
* @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
|
* 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)
|
* @return request (contains the partial data and valid length)
|
||||||
*/
|
*/
|
||||||
Request getPeerPartial(BitField havePieces); /* FIXME Exporting non-public type through public API FIXME */
|
PartialPiece getPartialPiece(Peer peer, BitField havePieces);
|
||||||
|
|
||||||
/** 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);
|
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,11 @@ package org.klomp.snark;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
@ -36,9 +38,9 @@ import org.klomp.snark.bencode.BEValue;
|
|||||||
class PeerState implements DataLoader
|
class PeerState implements DataLoader
|
||||||
{
|
{
|
||||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
|
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
|
||||||
final Peer peer;
|
private final Peer peer;
|
||||||
final PeerListener listener;
|
final PeerListener listener;
|
||||||
final MetaInfo metainfo;
|
private final MetaInfo metainfo;
|
||||||
|
|
||||||
// Interesting and choking describes whether we are interested in or
|
// Interesting and choking describes whether we are interested in or
|
||||||
// are choking the other side.
|
// are choking the other side.
|
||||||
@ -54,6 +56,7 @@ class PeerState implements DataLoader
|
|||||||
long downloaded;
|
long downloaded;
|
||||||
long uploaded;
|
long uploaded;
|
||||||
|
|
||||||
|
/** the pieces the peer has */
|
||||||
BitField bitfield;
|
BitField bitfield;
|
||||||
|
|
||||||
// Package local for use by Peer.
|
// Package local for use by Peer.
|
||||||
@ -102,6 +105,12 @@ class PeerState implements DataLoader
|
|||||||
|
|
||||||
if (interesting && !choked)
|
if (interesting && !choked)
|
||||||
request(resend);
|
request(resend);
|
||||||
|
|
||||||
|
if (choked) {
|
||||||
|
// TODO
|
||||||
|
// savePartialPieces
|
||||||
|
// clear request list
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void interestedMessage(boolean interest)
|
void interestedMessage(boolean interest)
|
||||||
@ -308,8 +317,11 @@ class PeerState implements DataLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return index in outstandingRequests or -1
|
||||||
|
*/
|
||||||
synchronized private int getFirstOutstandingRequest(int piece)
|
synchronized private int getFirstOutstandingRequest(int piece)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < outstandingRequests.size(); i++)
|
for (int i = 0; i < outstandingRequests.size(); i++)
|
||||||
if (outstandingRequests.get(i).piece == piece)
|
if (outstandingRequests.get(i).piece == piece)
|
||||||
return i;
|
return i;
|
||||||
@ -397,54 +409,56 @@ class PeerState implements DataLoader
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get longest partial piece
|
/**
|
||||||
synchronized Request getPartialRequest()
|
* @return lowest offset of any request for the piece
|
||||||
{
|
* @since 0.8.2
|
||||||
Request req = null;
|
*/
|
||||||
for (int i = 0; i < outstandingRequests.size(); i++) {
|
synchronized private Request getLowestOutstandingRequest(int piece) {
|
||||||
Request r1 = outstandingRequests.get(i);
|
Request rv = null;
|
||||||
int j = getFirstOutstandingRequest(r1.piece);
|
int lowest = Integer.MAX_VALUE;
|
||||||
if (j == -1)
|
for (Request r : outstandingRequests) {
|
||||||
continue;
|
if (r.piece == piece && r.off < lowest) {
|
||||||
Request r2 = outstandingRequests.get(j);
|
lowest = r.off;
|
||||||
if (r2.off > 0 && ((req == null) || (r2.off > req.off)))
|
rv = r;
|
||||||
req = r2;
|
}
|
||||||
}
|
}
|
||||||
if (pendingRequest != null && req != null && pendingRequest.off < req.off) {
|
if (pendingRequest != null &&
|
||||||
if (pendingRequest.off != 0)
|
pendingRequest.piece == piece && pendingRequest.off < lowest)
|
||||||
req = pendingRequest;
|
rv = pendingRequest;
|
||||||
else
|
|
||||||
req = null;
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
}
|
_log.debug(peer + " lowest for " + piece + " is " + rv + " out of " + pendingRequest + " and " + outstandingRequests);
|
||||||
return req;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return array of pieces terminated by -1
|
* get partial pieces, give them back to PeerCoordinator
|
||||||
* remove most duplicates
|
* @return List of PartialPieces, even those with an offset == 0, or empty list
|
||||||
* but still could be some duplicates, not guaranteed
|
* @since 0.8.2
|
||||||
* TODO rework this Java-style to return a Set or a List
|
|
||||||
*/
|
*/
|
||||||
synchronized int[] getRequestedPieces()
|
synchronized List<PartialPiece> returnPartialPieces()
|
||||||
{
|
{
|
||||||
int size = outstandingRequests.size();
|
Set<Integer> pcs = getRequestedPieces();
|
||||||
int[] arr = new int[size+2];
|
List<PartialPiece> rv = new ArrayList(pcs.size());
|
||||||
int pc = -1;
|
for (Integer p : pcs) {
|
||||||
int pos = 0;
|
Request req = getLowestOutstandingRequest(p.intValue());
|
||||||
if (pendingRequest != null) {
|
if (req != null)
|
||||||
pc = pendingRequest.piece;
|
rv.add(new PartialPiece(req));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
return rv;
|
||||||
arr[pos] = -1;
|
}
|
||||||
return(arr);
|
|
||||||
|
/**
|
||||||
|
* @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)
|
void cancelMessage(int piece, int begin, int length)
|
||||||
@ -555,6 +569,8 @@ class PeerState implements DataLoader
|
|||||||
{
|
{
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
out.sendRequests(outstandingRequests);
|
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)
|
if (bitfield != null)
|
||||||
{
|
{
|
||||||
// Check for adopting an orphaned partial piece
|
// Check for adopting an orphaned partial piece
|
||||||
Request r = listener.getPeerPartial(bitfield);
|
PartialPiece pp = listener.getPartialPiece(peer, bitfield);
|
||||||
if (r != null) {
|
if (pp != null) {
|
||||||
// Check that r not already in outstandingRequests
|
// Double-check that r not already in outstandingRequests
|
||||||
int[] arr = getRequestedPieces();
|
if (!getRequestedPieces().contains(Integer.valueOf(pp.getPiece()))) {
|
||||||
boolean found = false;
|
Request r = pp.getRequest();
|
||||||
for (int i = 0; arr[i] >= 0; i++) {
|
|
||||||
if (arr[i] == r.piece) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
outstandingRequests.add(r);
|
outstandingRequests.add(r);
|
||||||
if (!choked)
|
if (!choked)
|
||||||
out.sendRequest(r);
|
out.sendRequest(r);
|
||||||
lastRequest = r;
|
lastRequest = r;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that in addition to the bitfield, PeerCoordinator uses
|
// Note that in addition to the bitfield, PeerCoordinator uses
|
||||||
|
@ -5,7 +5,10 @@ import java.util.Set;
|
|||||||
|
|
||||||
import net.i2p.util.ConcurrentHashSet;
|
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 int id;
|
||||||
private Set<PeerID> peers;
|
private Set<PeerID> peers;
|
||||||
|
@ -22,6 +22,7 @@ package org.klomp.snark;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds all information needed for a partial piece request.
|
* Holds all information needed for a partial piece request.
|
||||||
|
* This class should be used only by PeerState, PeerConnectionIn, and PeerConnectionOut.
|
||||||
*/
|
*/
|
||||||
class Request
|
class Request
|
||||||
{
|
{
|
||||||
|
@ -92,6 +92,11 @@
|
|||||||
<!-- jar again to get the latest messages_*.class files -->
|
<!-- jar again to get the latest messages_*.class files -->
|
||||||
<jar destfile="./build/routerconsole.jar" basedir="./build/obj" includes="**/*.class" update="true" />
|
<jar destfile="./build/routerconsole.jar" basedir="./build/obj" includes="**/*.class" update="true" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<target name="jarWithJavadoc" depends="jar">
|
||||||
|
<jar destfile="build/routerconsole.war" basedir="../../../build/" includes="javadoc/**/*" update="true" />
|
||||||
|
</target>
|
||||||
|
|
||||||
<target name="poupdate" depends="build">
|
<target name="poupdate" depends="build">
|
||||||
<ant target="war" />
|
<ant target="war" />
|
||||||
<!-- Update the messages_*.po files.
|
<!-- Update the messages_*.po files.
|
||||||
|
@ -6,13 +6,11 @@ import java.util.Locale;
|
|||||||
import net.i2p.util.FileUtil;
|
import net.i2p.util.FileUtil;
|
||||||
|
|
||||||
public class ContentHelper extends HelperBase {
|
public class ContentHelper extends HelperBase {
|
||||||
private String _page;
|
protected String _page;
|
||||||
private int _maxLines;
|
private int _maxLines;
|
||||||
private boolean _startAtBeginning;
|
private boolean _startAtBeginning;
|
||||||
private String _lang;
|
private String _lang;
|
||||||
|
|
||||||
public ContentHelper() {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caution, use absolute paths only, do not assume files are in CWD
|
* Caution, use absolute paths only, do not assume files are in CWD
|
||||||
*/
|
*/
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,8 @@ if (System.getProperty("router.consoleNonce") == null) {
|
|||||||
|
|
||||||
<%@include file="summary.jsi" %><h1><%=intl._("I2P Router Console")%></h1>
|
<%@include file="summary.jsi" %><h1><%=intl._("I2P Router Console")%></h1>
|
||||||
<div class="news" id="news">
|
<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"); %>
|
<% 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="page" value="<%=fpath.getAbsolutePath()%>" />
|
||||||
<jsp:setProperty name="newshelper" property="maxLines" value="300" />
|
<jsp:setProperty name="newshelper" property="maxLines" value="300" />
|
||||||
|
11
build.xml
11
build.xml
@ -413,8 +413,6 @@
|
|||||||
<copy file="history.txt" todir="pkg-temp/" overwrite="true" />
|
<copy file="history.txt" todir="pkg-temp/" overwrite="true" />
|
||||||
<mkdir dir="pkg-temp/scripts" />
|
<mkdir dir="pkg-temp/scripts" />
|
||||||
<copy file="apps/proxyscript/i2pProxy.pac" todir="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/startconsole.html" todir="pkg-temp/docs/" />
|
||||||
<copy file="installer/resources/start.ico" todir="pkg-temp/docs/" />
|
<copy file="installer/resources/start.ico" todir="pkg-temp/docs/" />
|
||||||
<copy file="installer/resources/console.ico" todir="pkg-temp/docs/" />
|
<copy file="installer/resources/console.ico" todir="pkg-temp/docs/" />
|
||||||
@ -476,8 +474,12 @@
|
|||||||
<delete dir="pkg-temp" />
|
<delete dir="pkg-temp" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<!-- readme and proxy error page files, GeoIP files, and flag icons -->
|
<!-- readme and proxy error page files, initialNews.xml files, GeoIP files, and flag icons -->
|
||||||
<target name="prepConsoleDocs" depends="prepConsoleDocUpdates, prepgeoupdate" />
|
<target name="prepConsoleDocs" depends="prepConsoleDocUpdates, prepgeoupdate" >
|
||||||
|
<copy todir="pkg-temp/docs/" >
|
||||||
|
<fileset dir="installer/resources/initialNews/" />
|
||||||
|
</copy>
|
||||||
|
</target>
|
||||||
|
|
||||||
<!-- readme and proxy error page files -->
|
<!-- readme and proxy error page files -->
|
||||||
<target name="prepConsoleDocUpdates">
|
<target name="prepConsoleDocUpdates">
|
||||||
@ -766,7 +768,6 @@
|
|||||||
<exec executable="ls" failonerror="true">
|
<exec executable="ls" failonerror="true">
|
||||||
<arg value="-l" />
|
<arg value="-l" />
|
||||||
<arg value="history.txt" />
|
<arg value="history.txt" />
|
||||||
<arg value="installer/resources/initialNews.xml" />
|
|
||||||
<arg value="installer/install.xml" />
|
<arg value="installer/install.xml" />
|
||||||
<arg value="installer/resources/news.xml" />
|
<arg value="installer/resources/news.xml" />
|
||||||
<arg value="core/java/src/net/i2p/CoreVersion.java" />
|
<arg value="core/java/src/net/i2p/CoreVersion.java" />
|
||||||
|
@ -19,6 +19,10 @@ import net.i2p.util.Log;
|
|||||||
* Defines the actual payload of a message being delivered, including the
|
* Defines the actual payload of a message being delivered, including the
|
||||||
* standard encryption wrapping, as defined by the I2P data structure spec.
|
* 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
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class Payload extends DataStructureImpl {
|
public class Payload extends DataStructureImpl {
|
||||||
@ -32,6 +36,9 @@ public class Payload extends DataStructureImpl {
|
|||||||
/**
|
/**
|
||||||
* Retrieve the unencrypted body of the message.
|
* 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
|
* @return body of the message, or null if the message has either not been
|
||||||
* decrypted yet or if the hash is not correct
|
* 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
|
* Populate the message body with data. This does not automatically encrypt
|
||||||
* yet.
|
* yet.
|
||||||
*
|
*
|
||||||
|
* Deprecated.
|
||||||
|
* Unless you are doing encryption, use setEncryptedData() instead.
|
||||||
*/
|
*/
|
||||||
public void setUnencryptedData(byte[] data) {
|
public void setUnencryptedData(byte[] data) {
|
||||||
_unencryptedData = data;
|
_unencryptedData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** the real data */
|
||||||
public byte[] getEncryptedData() {
|
public byte[] getEncryptedData() {
|
||||||
return _encryptedData;
|
return _encryptedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** the real data */
|
||||||
public void setEncryptedData(byte[] data) {
|
public void setEncryptedData(byte[] data) {
|
||||||
_encryptedData = data;
|
_encryptedData = data;
|
||||||
}
|
}
|
||||||
@ -100,7 +111,7 @@ public class Payload extends DataStructureImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return DataHelper.hashCode(_unencryptedData);
|
return DataHelper.hashCode(_encryptedData != null ? _encryptedData : _unencryptedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -23,6 +23,7 @@ import net.i2p.crypto.DSAEngine;
|
|||||||
* This helper class reads and writes files in the
|
* This helper class reads and writes files in the
|
||||||
* same "eepPriv.dat" format used by the client code.
|
* same "eepPriv.dat" format used by the client code.
|
||||||
* The format is:
|
* The format is:
|
||||||
|
*<pre>
|
||||||
* - Destination (387 bytes if no certificate, otherwise longer)
|
* - Destination (387 bytes if no certificate, otherwise longer)
|
||||||
* - Public key (256 bytes)
|
* - Public key (256 bytes)
|
||||||
* - Signing Public key (128 bytes)
|
* - Signing Public key (128 bytes)
|
||||||
@ -32,6 +33,7 @@ import net.i2p.crypto.DSAEngine;
|
|||||||
* - Private key (256 bytes)
|
* - Private key (256 bytes)
|
||||||
* - Signing Private key (20 bytes)
|
* - Signing Private key (20 bytes)
|
||||||
* Total 663 bytes
|
* Total 663 bytes
|
||||||
|
*</pre>
|
||||||
*
|
*
|
||||||
* @author welterde, zzz
|
* @author welterde, zzz
|
||||||
*/
|
*/
|
||||||
|
@ -66,8 +66,8 @@ public class LogManager {
|
|||||||
public final static String DEFAULT_DEFAULTLEVEL = Log.STR_ERROR;
|
public final static String DEFAULT_DEFAULTLEVEL = Log.STR_ERROR;
|
||||||
public final static String DEFAULT_ONSCREENLEVEL = Log.STR_CRIT;
|
public final static String DEFAULT_ONSCREENLEVEL = Log.STR_CRIT;
|
||||||
|
|
||||||
private I2PAppContext _context;
|
private final I2PAppContext _context;
|
||||||
private Log _log;
|
private final Log _log;
|
||||||
|
|
||||||
/** when was the config file last read (or -1 if never) */
|
/** when was the config file last read (or -1 if never) */
|
||||||
private long _configLastRead;
|
private long _configLastRead;
|
||||||
@ -75,11 +75,11 @@ public class LogManager {
|
|||||||
/** the config file */
|
/** the config file */
|
||||||
private File _locationFile;
|
private File _locationFile;
|
||||||
/** Ordered list of LogRecord elements that have not been written out yet */
|
/** 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) */
|
/** 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 */
|
/** 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 */
|
/** who clears and writes our records */
|
||||||
private LogWriter _writer;
|
private LogWriter _writer;
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ public class LogManager {
|
|||||||
/** how many records we want to buffer in the "recent logs" list */
|
/** how many records we want to buffer in the "recent logs" list */
|
||||||
private int _consoleBufferSize;
|
private int _consoleBufferSize;
|
||||||
/** the actual "recent logs" list */
|
/** the actual "recent logs" list */
|
||||||
private LogConsoleBuffer _consoleBuffer;
|
private final LogConsoleBuffer _consoleBuffer;
|
||||||
|
|
||||||
private boolean _alreadyNoticedMissingConfig;
|
private boolean _alreadyNoticedMissingConfig;
|
||||||
|
|
||||||
@ -119,17 +119,17 @@ public class LogManager {
|
|||||||
_limits = new ConcurrentHashSet();
|
_limits = new ConcurrentHashSet();
|
||||||
_logs = new ConcurrentHashMap(128);
|
_logs = new ConcurrentHashMap(128);
|
||||||
_defaultLimit = Log.ERROR;
|
_defaultLimit = Log.ERROR;
|
||||||
_configLastRead = 0;
|
|
||||||
_context = context;
|
_context = context;
|
||||||
_log = getLog(LogManager.class);
|
_log = getLog(LogManager.class);
|
||||||
String location = context.getProperty(CONFIG_LOCATION_PROP, CONFIG_LOCATION_DEFAULT);
|
String location = context.getProperty(CONFIG_LOCATION_PROP, CONFIG_LOCATION_DEFAULT);
|
||||||
setConfig(location);
|
setConfig(location);
|
||||||
_consoleBuffer = new LogConsoleBuffer(context);
|
_consoleBuffer = new LogConsoleBuffer(context);
|
||||||
_writer = new LogWriter(this);
|
// If we aren't in the router context, delay creating the LogWriter until required,
|
||||||
Thread t = new I2PThread(_writer);
|
// so it doesn't create a log directory and log files unless there is output.
|
||||||
t.setName("LogWriter");
|
// In the router context, we have to rotate to a new log file at startup or the logs.jsp
|
||||||
t.setDaemon(true);
|
// page will display the old log.
|
||||||
t.start();
|
if (context.isRouterContext())
|
||||||
|
startLogWriter();
|
||||||
try {
|
try {
|
||||||
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
||||||
} catch (IllegalStateException ise) {
|
} catch (IllegalStateException ise) {
|
||||||
@ -138,9 +138,16 @@ public class LogManager {
|
|||||||
//System.out.println("Created logManager " + this + " with context: " + context);
|
//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); }
|
public Log getLog(Class cls) { return getLog(cls, null); }
|
||||||
public Log getLog(String name) { return getLog(null, name); }
|
public Log getLog(String name) { return getLog(null, name); }
|
||||||
public Log getLog(Class cls, String name) {
|
public Log getLog(Class cls, String name) {
|
||||||
@ -169,6 +176,7 @@ public class LogManager {
|
|||||||
|
|
||||||
public LogConsoleBuffer getBuffer() { return _consoleBuffer; }
|
public LogConsoleBuffer getBuffer() { return _consoleBuffer; }
|
||||||
|
|
||||||
|
/** @deprecated unused */
|
||||||
public void setDisplayOnScreen(boolean yes) {
|
public void setDisplayOnScreen(boolean yes) {
|
||||||
_displayOnScreen = yes;
|
_displayOnScreen = yes;
|
||||||
}
|
}
|
||||||
@ -181,6 +189,7 @@ public class LogManager {
|
|||||||
return _onScreenLimit;
|
return _onScreenLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated unused */
|
||||||
public void setDisplayOnScreenLevel(int level) {
|
public void setDisplayOnScreenLevel(int level) {
|
||||||
_onScreenLimit = level;
|
_onScreenLimit = level;
|
||||||
}
|
}
|
||||||
@ -189,6 +198,7 @@ public class LogManager {
|
|||||||
return _consoleBufferSize;
|
return _consoleBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated unused */
|
||||||
public void setConsoleBufferSize(int numRecords) {
|
public void setConsoleBufferSize(int numRecords) {
|
||||||
_consoleBufferSize = numRecords;
|
_consoleBufferSize = numRecords;
|
||||||
}
|
}
|
||||||
@ -201,6 +211,8 @@ public class LogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String currentFile() {
|
public String currentFile() {
|
||||||
|
if (_writer == null)
|
||||||
|
return ("No log file created yet");
|
||||||
return _writer.currentFile();
|
return _writer.currentFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +221,9 @@ public class LogManager {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void addRecord(LogRecord record) {
|
void addRecord(LogRecord record) {
|
||||||
|
if ((!_context.isRouterContext()) && _writer == null)
|
||||||
|
startLogWriter();
|
||||||
|
|
||||||
_records.offer(record);
|
_records.offer(record);
|
||||||
int numRecords = _records.size();
|
int numRecords = _records.size();
|
||||||
|
|
||||||
@ -617,9 +632,11 @@ public class LogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
_log.log(Log.WARN, "Shutting down logger");
|
if (_writer != null) {
|
||||||
_writer.flushRecords(false);
|
_log.log(Log.WARN, "Shutting down logger");
|
||||||
_writer.stopWriting();
|
_writer.flushRecords(false);
|
||||||
|
_writer.stopWriting();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int __id = 0;
|
private static int __id = 0;
|
||||||
|
@ -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
|
2010-11-26 dr|z3d
|
||||||
* Readme: Overhaul (English) layout and text.
|
* Readme: Overhaul (English) layout and text.
|
||||||
|
|
||||||
|
@ -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ä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>¡Felicidades!, has instalado el enrutador I2P con éxito.</li></ul></h4>
|
|
||||||
<p>
|
|
||||||
<b>¡Bienvenido a I2P!</b><br>
|
|
||||||
¡Ten todavía <b>paciencia</b> mientras I2P esté arrancando y encontrando otros enrutadores I2P!
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Este es el momento ideal para adaptar tu <b>configuración de ancho de banda</b> en la
|
|
||||||
<a href="config.jsp">página de configuración</a>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
En cuanto veas a la izquierda una conexión llamada "shared clients", puedes visitar nuestros <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
¡Coné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>
|
|
20
installer/resources/initialNews/initialNews.xml
Normal file
20
installer/resources/initialNews/initialNews.xml
Normal 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>
|
21
installer/resources/initialNews/initialNews_br.xml
Normal file
21
installer/resources/initialNews/initialNews_br.xml
Normal 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>
|
21
installer/resources/initialNews/initialNews_de.xml
Normal file
21
installer/resources/initialNews/initialNews_de.xml
Normal 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ä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>
|
21
installer/resources/initialNews/initialNews_es.xml
Normal file
21
installer/resources/initialNews/initialNews_es.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<div lang="es">
|
||||||
|
<h4><ul><li>¡Felicidades!, has instalado el enrutador I2P con éxito.</li></ul></h4>
|
||||||
|
<p>
|
||||||
|
<b>¡Bienvenido a I2P!</b><br>
|
||||||
|
¡Ten todavía <b>paciencia</b> mientras I2P esté arrancando y encontrando otros enrutadores I2P!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Este es el momento ideal para adaptar tu <b>configuración de ancho de banda</b> en la
|
||||||
|
<a href="config.jsp">página de configuración</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
En cuanto veas a la izquierda una conexión llamada "shared clients", puedes visitar nuestros <a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
¡Coné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>
|
19
installer/resources/initialNews/initialNews_nl.xml
Normal file
19
installer/resources/initialNews/initialNews_nl.xml
Normal 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>
|
16
installer/resources/initialNews/initialNews_ru.xml
Normal file
16
installer/resources/initialNews/initialNews_ru.xml
Normal 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>
|
@ -191,7 +191,9 @@ public class Router {
|
|||||||
|
|
||||||
// This is here so that we can get the directory location from the context
|
// This is here so that we can get the directory location from the context
|
||||||
// for the ping file
|
// 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("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(" 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,");
|
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.
|
// overwrite an existing running router's jar files. Other than ours.
|
||||||
installUpdates();
|
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
|
// Apps may use this as an easy way to determine if they are in the router JVM
|
||||||
// But context.isRouterContext() is even easier...
|
// But context.isRouterContext() is even easier...
|
||||||
// Both of these as of 0.7.9
|
// Both of these as of 0.7.9
|
||||||
@ -1163,38 +1170,50 @@ public class Router {
|
|||||||
// verify the whole thing first
|
// verify the whole thing first
|
||||||
// we could remember this fails, and not bother restarting, but who cares...
|
// we could remember this fails, and not bother restarting, but who cares...
|
||||||
boolean ok = FileUtil.verifyZip(updateFile);
|
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) {
|
if (ok) {
|
||||||
// This may be useful someday. First added in 0.8.2
|
// 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());
|
_config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
|
||||||
saveConfig();
|
saveConfig();
|
||||||
boolean deleted = updateFile.delete();
|
ok = FileUtil.extractZip(updateFile, _context.getBaseDir());
|
||||||
if (!deleted) {
|
}
|
||||||
System.out.println("ERROR: Unable to delete the update file!");
|
|
||||||
updateFile.deleteOnExit();
|
// 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);
|
System.exit(EXIT_HARD_RESTART);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1230,13 +1249,14 @@ public class Router {
|
|||||||
static final long LIVELINESS_DELAY = 60*1000;
|
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
|
* 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
|
* @return true if the router is the only one running
|
||||||
|
* @since 0.8.2
|
||||||
*/
|
*/
|
||||||
private boolean beginMarkingLiveliness() {
|
private boolean isOnlyRouterRunning() {
|
||||||
File f = getPingFile();
|
File f = getPingFile();
|
||||||
if (f.exists()) {
|
if (f.exists()) {
|
||||||
long lastWritten = f.lastModified();
|
long lastWritten = f.lastModified();
|
||||||
@ -1247,12 +1267,20 @@ public class Router {
|
|||||||
return false;
|
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
|
// not an I2PThread for context creation issues
|
||||||
Thread t = new Thread(new MarkLiveliness(_context, this, f));
|
Thread t = new Thread(new MarkLiveliness(_context, this, f));
|
||||||
t.setName("Mark router liveliness");
|
t.setName("Mark router liveliness");
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.start();
|
t.start();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String PROP_BANDWIDTH_SHARE_PERCENTAGE = "router.sharePercentage";
|
public static final String PROP_BANDWIDTH_SHARE_PERCENTAGE = "router.sharePercentage";
|
||||||
|
@ -686,6 +686,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final int MIN_ROUTERS = 90;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether this routerInfo will be accepted as valid and current
|
* Determine whether this routerInfo will be accepted as valid and current
|
||||||
* given what we know now.
|
* given what we know now.
|
||||||
@ -694,9 +696,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
|||||||
String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
|
String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
|
||||||
long now = _context.clock().now();
|
long now = _context.clock().now();
|
||||||
boolean upLongEnough = _context.router().getUptime() > 60*60*1000;
|
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.
|
// 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
|
// And if we're floodfill, we can keep the expiration really short, since
|
||||||
// we are always getting the latest published to us.
|
// we are always getting the latest published to us.
|
||||||
// As the net grows this won't be sufficient, and we'll have to implement
|
// 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
|
// _kb.size() includes leasesets but that's ok
|
||||||
adjustedExpiration = Math.min(ROUTER_INFO_EXPIRATION,
|
adjustedExpiration = Math.min(ROUTER_INFO_EXPIRATION,
|
||||||
ROUTER_INFO_EXPIRATION_MIN +
|
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 (!key.equals(routerInfo.getIdentity().getHash())) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
@ -149,7 +149,8 @@ public class WorkingDir {
|
|||||||
// this one must be after MIGRATE_BASE
|
// this one must be after MIGRATE_BASE
|
||||||
success &= migrateJettyXml(oldDirf, dirf);
|
success &= migrateJettyXml(oldDirf, dirf);
|
||||||
success &= migrateClientsConfig(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
|
// Report success or failure
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -234,7 +234,7 @@ public class EstablishState {
|
|||||||
System.arraycopy(_X, 0, xy, 0, _X.length);
|
System.arraycopy(_X, 0, xy, 0, _X.length);
|
||||||
System.arraycopy(_Y, 0, xy, _X.length, _Y.length);
|
System.arraycopy(_Y, 0, xy, _X.length, _Y.length);
|
||||||
Hash hxy = _context.sha().calculateHash(xy);
|
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
|
byte padding[] = new byte[12]; // the encrypted data needs an extra 12 bytes
|
||||||
_context.random().nextBytes(padding);
|
_context.random().nextBytes(padding);
|
||||||
byte toEncrypt[] = new byte[hxy.getData().length+4+padding.length];
|
byte toEncrypt[] = new byte[hxy.getData().length+4+padding.length];
|
||||||
@ -387,7 +387,7 @@ public class EstablishState {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_tsB = DataHelper.fromLong(hXY_tsB, Hash.HASH_LENGTH, 4); // their (Bob's) timestamp in seconds
|
_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))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug(prefix()+"h(X+Y) is correct, tsA-tsB=" + (_tsA-_tsB));
|
_log.debug(prefix()+"h(X+Y) is correct, tsA-tsB=" + (_tsA-_tsB));
|
||||||
|
|
||||||
|
@ -1035,7 +1035,7 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void readMeta(byte unencrypted[]) {
|
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);
|
long ts = DataHelper.fromLong(unencrypted, 2, 4);
|
||||||
Adler32 crc = new Adler32();
|
Adler32 crc = new Adler32();
|
||||||
crc.update(unencrypted, 0, unencrypted.length-4);
|
crc.update(unencrypted, 0, unencrypted.length-4);
|
||||||
@ -1068,7 +1068,7 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
|
|||||||
synchronized (_meta) {
|
synchronized (_meta) {
|
||||||
_context.random().nextBytes(_meta); // randomize the uninterpreted, then overwrite w/ data
|
_context.random().nextBytes(_meta); // randomize the uninterpreted, then overwrite w/ data
|
||||||
DataHelper.toLong(_meta, 0, 2, 0);
|
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();
|
Adler32 crc = new Adler32();
|
||||||
crc.update(_meta, 0, _meta.length-4);
|
crc.update(_meta, 0, _meta.length-4);
|
||||||
DataHelper.toLong(_meta, _meta.length-4, 4, crc.getValue());
|
DataHelper.toLong(_meta, _meta.length-4, 4, crc.getValue());
|
||||||
|
@ -72,9 +72,6 @@ class InboundEstablishState {
|
|||||||
_alicePort = remotePort;
|
_alicePort = remotePort;
|
||||||
_remoteHostId = new RemoteHostId(_aliceIP, _alicePort);
|
_remoteHostId = new RemoteHostId(_aliceIP, _alicePort);
|
||||||
_bobPort = localPort;
|
_bobPort = localPort;
|
||||||
_keyBuilder = null;
|
|
||||||
_verificationAttempted = false;
|
|
||||||
_complete = false;
|
|
||||||
_currentState = STATE_UNKNOWN;
|
_currentState = STATE_UNKNOWN;
|
||||||
_establishBegin = ctx.clock().now();
|
_establishBegin = ctx.clock().now();
|
||||||
}
|
}
|
||||||
|
@ -86,13 +86,11 @@ class OutboundEstablishState {
|
|||||||
}
|
}
|
||||||
_remotePeer = remotePeer;
|
_remotePeer = remotePeer;
|
||||||
_introKey = introKey;
|
_introKey = introKey;
|
||||||
_keyBuilder = null;
|
|
||||||
_queuedMessages = new LinkedBlockingQueue();
|
_queuedMessages = new LinkedBlockingQueue();
|
||||||
_currentState = STATE_UNKNOWN;
|
_currentState = STATE_UNKNOWN;
|
||||||
_establishBegin = ctx.clock().now();
|
_establishBegin = ctx.clock().now();
|
||||||
_remoteAddress = addr;
|
_remoteAddress = addr;
|
||||||
_introductionNonce = -1;
|
_introductionNonce = -1;
|
||||||
_complete = false;
|
|
||||||
prepareSessionRequest();
|
prepareSessionRequest();
|
||||||
if ( (addr != null) && (addr.getIntroducerCount() > 0) ) {
|
if ( (addr != null) && (addr.getIntroducerCount() > 0) ) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
@ -47,7 +47,6 @@ class OutboundMessageFragments {
|
|||||||
_transport = transport;
|
_transport = transport;
|
||||||
// _throttle = throttle;
|
// _throttle = throttle;
|
||||||
_activePeers = new ArrayList(256);
|
_activePeers = new ArrayList(256);
|
||||||
_nextPeer = 0;
|
|
||||||
_builder = new PacketBuilder(ctx, transport);
|
_builder = new PacketBuilder(ctx, transport);
|
||||||
_alive = true;
|
_alive = true;
|
||||||
// _allowExcess = false;
|
// _allowExcess = false;
|
||||||
|
@ -47,9 +47,6 @@ class OutboundMessageState {
|
|||||||
public OutboundMessageState(I2PAppContext context) {
|
public OutboundMessageState(I2PAppContext context) {
|
||||||
_context = context;
|
_context = context;
|
||||||
_log = _context.logManager().getLog(OutboundMessageState.class);
|
_log = _context.logManager().getLog(OutboundMessageState.class);
|
||||||
_pushCount = 0;
|
|
||||||
_maxSends = 0;
|
|
||||||
// _nextSendFragment = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean initialize(OutNetMessage msg) {
|
public boolean initialize(OutNetMessage msg) {
|
||||||
|
@ -1084,7 +1084,7 @@ class PacketBuilder {
|
|||||||
// header
|
// header
|
||||||
data[off] = flagByte;
|
data[off] = flagByte;
|
||||||
off++;
|
off++;
|
||||||
long now = _context.clock().now() / 1000;
|
long now = (_context.clock().now() + 500) / 1000;
|
||||||
DataHelper.toLong(data, off, 4, now);
|
DataHelper.toLong(data, off, 4, now);
|
||||||
// todo: add support for rekeying and extended options
|
// todo: add support for rekeying and extended options
|
||||||
return packet;
|
return packet;
|
||||||
|
@ -63,8 +63,13 @@ class PeerState {
|
|||||||
private boolean _rekeyBeganLocally;
|
private boolean _rekeyBeganLocally;
|
||||||
/** when were the current cipher and MAC keys established/rekeyed? */
|
/** when were the current cipher and MAC keys established/rekeyed? */
|
||||||
private long _keyEstablishedTime;
|
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;
|
private long _clockSkew;
|
||||||
|
|
||||||
/** what is the current receive second, for congestion control? */
|
/** what is the current receive second, for congestion control? */
|
||||||
private long _currentReceiveSecond;
|
private long _currentReceiveSecond;
|
||||||
/** when did we last send them a packet? */
|
/** when did we last send them a packet? */
|
||||||
@ -241,36 +246,19 @@ class PeerState {
|
|||||||
_context = ctx;
|
_context = ctx;
|
||||||
_log = ctx.logManager().getLog(PeerState.class);
|
_log = ctx.logManager().getLog(PeerState.class);
|
||||||
_transport = transport;
|
_transport = transport;
|
||||||
_remotePeer = null;
|
|
||||||
_currentMACKey = null;
|
|
||||||
_currentCipherKey = null;
|
|
||||||
_nextMACKey = null;
|
|
||||||
_nextCipherKey = null;
|
|
||||||
_nextKeyingMaterial = null;
|
|
||||||
_rekeyBeganLocally = false;
|
|
||||||
_keyEstablishedTime = -1;
|
_keyEstablishedTime = -1;
|
||||||
_clockSkew = 0;
|
|
||||||
_currentReceiveSecond = -1;
|
_currentReceiveSecond = -1;
|
||||||
_lastSendTime = -1;
|
_lastSendTime = -1;
|
||||||
_lastReceiveTime = -1;
|
_lastReceiveTime = -1;
|
||||||
_currentACKs = new ConcurrentHashSet();
|
_currentACKs = new ConcurrentHashSet();
|
||||||
_currentACKsResend = new LinkedBlockingQueue();
|
_currentACKsResend = new LinkedBlockingQueue();
|
||||||
_currentSecondECNReceived = false;
|
|
||||||
_remoteWantsPreviousACKs = false;
|
|
||||||
_sendWindowBytes = DEFAULT_SEND_WINDOW_BYTES;
|
_sendWindowBytes = DEFAULT_SEND_WINDOW_BYTES;
|
||||||
_sendWindowBytesRemaining = DEFAULT_SEND_WINDOW_BYTES;
|
_sendWindowBytesRemaining = DEFAULT_SEND_WINDOW_BYTES;
|
||||||
_slowStartThreshold = MAX_SEND_WINDOW_BYTES/2;
|
_slowStartThreshold = MAX_SEND_WINDOW_BYTES/2;
|
||||||
_lastSendRefill = _context.clock().now();
|
_lastSendRefill = _context.clock().now();
|
||||||
_receivePeriodBegin = _lastSendRefill;
|
_receivePeriodBegin = _lastSendRefill;
|
||||||
_sendBps = 0;
|
|
||||||
_sendBytes = 0;
|
|
||||||
_receiveBps = 0;
|
|
||||||
_lastCongestionOccurred = -1;
|
_lastCongestionOccurred = -1;
|
||||||
_remoteIP = null;
|
|
||||||
_remotePort = -1;
|
_remotePort = -1;
|
||||||
_remoteRequiresIntroduction = false;
|
|
||||||
_weRelayToThemAs = 0;
|
|
||||||
_theyRelayToUsAs = 0;
|
|
||||||
_mtu = getDefaultMTU();
|
_mtu = getDefaultMTU();
|
||||||
_mtuReceive = _mtu;
|
_mtuReceive = _mtu;
|
||||||
_mtuLastChecked = -1;
|
_mtuLastChecked = -1;
|
||||||
@ -278,19 +266,8 @@ class PeerState {
|
|||||||
_rto = MIN_RTO;
|
_rto = MIN_RTO;
|
||||||
_rtt = _rto/2;
|
_rtt = _rto/2;
|
||||||
_rttDeviation = _rtt;
|
_rttDeviation = _rtt;
|
||||||
_messagesReceived = 0;
|
|
||||||
_messagesSent = 0;
|
|
||||||
_packetsTransmitted = 0;
|
|
||||||
_packetsRetransmitted = 0;
|
|
||||||
_packetRetransmissionRate = 0;
|
|
||||||
_retransmissionPeriodStart = 0;
|
|
||||||
_packetsReceived = 0;
|
|
||||||
_packetsReceivedDuplicate = 0;
|
|
||||||
_inboundMessages = new HashMap(8);
|
_inboundMessages = new HashMap(8);
|
||||||
_outboundMessages = new ArrayList(32);
|
_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.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.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);
|
_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; }
|
public boolean getRekeyBeganLocally() { return _rekeyBeganLocally; }
|
||||||
/** when were the current cipher and MAC keys established/rekeyed? */
|
/** when were the current cipher and MAC keys established/rekeyed? */
|
||||||
public long getKeyEstablishedTime() { return _keyEstablishedTime; }
|
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 ; }
|
public long getClockSkew() { return _clockSkew ; }
|
||||||
|
|
||||||
/** what is the current receive second, for congestion control? */
|
/** what is the current receive second, for congestion control? */
|
||||||
public long getCurrentReceiveSecond() { return _currentReceiveSecond; }
|
public long getCurrentReceiveSecond() { return _currentReceiveSecond; }
|
||||||
/** when did we last send them a packet? */
|
/** when did we last send them a packet? */
|
||||||
@ -444,10 +426,17 @@ class PeerState {
|
|||||||
public void setRekeyBeganLocally(boolean local) { _rekeyBeganLocally = local; }
|
public void setRekeyBeganLocally(boolean local) { _rekeyBeganLocally = local; }
|
||||||
/** when were the current cipher and MAC keys established/rekeyed? */
|
/** when were the current cipher and MAC keys established/rekeyed? */
|
||||||
public void setKeyEstablishedTime(long when) { _keyEstablishedTime = when; }
|
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) {
|
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? */
|
/** what is the current receive second, for congestion control? */
|
||||||
public void setCurrentReceiveSecond(long sec) { _currentReceiveSecond = sec; }
|
public void setCurrentReceiveSecond(long sec) { _currentReceiveSecond = sec; }
|
||||||
/** when did we last send them a packet? */
|
/** when did we last send them a packet? */
|
||||||
@ -679,6 +668,7 @@ class PeerState {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public List<Long> getCurrentFullACKs() {
|
public List<Long> getCurrentFullACKs() {
|
||||||
|
// no such element exception seen here
|
||||||
ArrayList<Long> rv = new ArrayList(_currentACKs);
|
ArrayList<Long> rv = new ArrayList(_currentACKs);
|
||||||
// include some for retransmission
|
// include some for retransmission
|
||||||
rv.addAll(_currentACKsResend);
|
rv.addAll(_currentACKsResend);
|
||||||
|
@ -118,8 +118,6 @@ class PeerTestManager {
|
|||||||
_activeTests = new ConcurrentHashMap();
|
_activeTests = new ConcurrentHashMap();
|
||||||
_recentTests = new LinkedBlockingQueue();
|
_recentTests = new LinkedBlockingQueue();
|
||||||
_packetBuilder = new PacketBuilder(context, transport);
|
_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.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.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);
|
_context.statManager().createRateStat("udp.receiveTest", "How often we get a packet requesting us to participate in a peer test?", "udp", UDPTransport.RATES);
|
||||||
|
@ -76,7 +76,6 @@ class TimedWeightedPriorityMessageQueue implements MessageQueue, OutboundMessage
|
|||||||
}
|
}
|
||||||
_alive = true;
|
_alive = true;
|
||||||
_nextLock = this;
|
_nextLock = this;
|
||||||
_nextQueue = 0;
|
|
||||||
_chokedPeers = Collections.synchronizedSet(new HashSet(16));
|
_chokedPeers = Collections.synchronizedSet(new HashSet(16));
|
||||||
_listener = lsnr;
|
_listener = lsnr;
|
||||||
_context.statManager().createRateStat("udp.timeToEntrance", "Message lifetime until it reaches the UDP system", "udp", UDPTransport.RATES);
|
_context.statManager().createRateStat("udp.timeToEntrance", "Message lifetime until it reaches the UDP system", "udp", UDPTransport.RATES);
|
||||||
|
@ -177,7 +177,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
|||||||
_peersByIdent = new ConcurrentHashMap(128);
|
_peersByIdent = new ConcurrentHashMap(128);
|
||||||
_peersByRemoteHost = new ConcurrentHashMap(128);
|
_peersByRemoteHost = new ConcurrentHashMap(128);
|
||||||
_dropList = new ConcurrentHashSet(2);
|
_dropList = new ConcurrentHashSet(2);
|
||||||
_endpoint = null;
|
|
||||||
|
|
||||||
// See comments in DQAT.java
|
// See comments in DQAT.java
|
||||||
if (USE_PRIORITY) {
|
if (USE_PRIORITY) {
|
||||||
|
Reference in New Issue
Block a user