merge of '0738aeef8a1d4e9ca82dc5ba0077d83a57c47f81'
and '9625ea3e96d57df74bc62018bf64230a22c49ce0'
This commit is contained in:
@ -26,6 +26,7 @@ import net.i2p.util.ConcurrentHashSet;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.Translate;
|
||||
@ -77,7 +78,7 @@ public class I2PSnarkUtil {
|
||||
// This is used for both announce replies and .torrent file downloads,
|
||||
// so it must be available even if not connected to I2CP.
|
||||
// so much for multiple instances
|
||||
_tmpDir = new File(ctx.getTempDir(), "i2psnark");
|
||||
_tmpDir = new SecureDirectory(ctx.getTempDir(), "i2psnark");
|
||||
FileUtil.rmdir(_tmpDir, false);
|
||||
_tmpDir.mkdirs();
|
||||
}
|
||||
@ -196,11 +197,14 @@ public class I2PSnarkUtil {
|
||||
|
||||
/** connect to the given destination */
|
||||
I2PSocket connect(PeerID peer) throws IOException {
|
||||
Hash dest = peer.getAddress().calculateHash();
|
||||
Destination addr = peer.getAddress();
|
||||
if (addr == null)
|
||||
throw new IOException("Null address");
|
||||
Hash dest = addr.calculateHash();
|
||||
if (_shitlist.contains(dest))
|
||||
throw new IOException("Not trying to contact " + dest.toBase64() + ", as they are shitlisted");
|
||||
try {
|
||||
I2PSocket rv = _manager.connect(peer.getAddress());
|
||||
I2PSocket rv = _manager.connect(addr);
|
||||
if (rv != null)
|
||||
_shitlist.remove(dest);
|
||||
return rv;
|
||||
@ -224,7 +228,8 @@ public class I2PSnarkUtil {
|
||||
public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
|
||||
public File get(String url, int retries) { return get(url, true, retries); }
|
||||
public File get(String url, boolean rewrite, int retries) {
|
||||
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
|
||||
File out = null;
|
||||
try {
|
||||
// we could use the system tmp dir but deleteOnExit() doesn't seem to work on all platforms...
|
||||
@ -248,10 +253,12 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
EepGet get = new I2PSocketEepGet(_context, _manager, retries, out.getAbsolutePath(), fetchURL);
|
||||
if (get.fetch()) {
|
||||
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
||||
return out;
|
||||
} else {
|
||||
_log.warn("Fetch failed [" + url + "]");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Fetch failed [" + url + "]");
|
||||
out.delete();
|
||||
return null;
|
||||
}
|
||||
|
@ -109,7 +109,8 @@ public class MetaInfo
|
||||
*/
|
||||
public MetaInfo(Map m) throws InvalidBEncodingException
|
||||
{
|
||||
_log.debug("Creating a metaInfo: " + m, new Exception("source"));
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating a metaInfo: " + m, new Exception("source"));
|
||||
BEValue val = (BEValue)m.get("announce");
|
||||
if (val == null)
|
||||
throw new InvalidBEncodingException("Missing announce string");
|
||||
@ -446,14 +447,16 @@ public class MetaInfo
|
||||
else
|
||||
buf.append(val.toString());
|
||||
}
|
||||
_log.debug(buf.toString());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(buf.toString());
|
||||
byte[] infoBytes = BEncoder.bencode(info);
|
||||
//_log.debug("info bencoded: [" + Base64.encode(infoBytes, true) + "]");
|
||||
try
|
||||
{
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA");
|
||||
byte hash[] = digest.digest(infoBytes);
|
||||
_log.debug("info hash: [" + net.i2p.data.Base64.encode(hash) + "]");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("info hash: [" + net.i2p.data.Base64.encode(hash) + "]");
|
||||
return hash;
|
||||
}
|
||||
catch(NoSuchAlgorithmException nsa)
|
||||
|
@ -92,7 +92,8 @@ public class Peer implements Comparable
|
||||
byte[] id = handshake(in, out);
|
||||
this.peerID = new PeerID(id, sock.getPeerDestination());
|
||||
_id = ++__id;
|
||||
_log.debug("Creating a new peer with " + peerID.getAddress().calculateHash().toBase64(), new Exception("creating " + _id));
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating a new peer with " + peerID.getAddress().calculateHash().toBase64(), new Exception("creating " + _id));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,7 +130,7 @@ public class Peer implements Comparable
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return peerID.hashCode() ^ (2 << _id);
|
||||
return peerID.hashCode() ^ (7777 * (int)_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,6 +151,7 @@ public class Peer implements Comparable
|
||||
|
||||
/**
|
||||
* Compares the PeerIDs.
|
||||
* @deprecated unused?
|
||||
*/
|
||||
public int compareTo(Object o)
|
||||
{
|
||||
@ -181,14 +183,16 @@ public class Peer implements Comparable
|
||||
if (state != null)
|
||||
throw new IllegalStateException("Peer already started");
|
||||
|
||||
_log.debug("Running connection to " + peerID.getAddress().calculateHash().toBase64(), new Exception("connecting"));
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Running connection to " + peerID.getAddress().calculateHash().toBase64(), new Exception("connecting"));
|
||||
try
|
||||
{
|
||||
// Do we need to handshake?
|
||||
if (din == null)
|
||||
{
|
||||
sock = util.connect(peerID);
|
||||
_log.debug("Connected to " + peerID + ": " + sock);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Connected to " + peerID + ": " + sock);
|
||||
if ((sock == null) || (sock.isClosed())) {
|
||||
throw new IOException("Unable to reach " + peerID);
|
||||
}
|
||||
@ -207,14 +211,20 @@ public class Peer implements Comparable
|
||||
// = new BufferedOutputStream(sock.getOutputStream());
|
||||
byte [] id = handshake(in, out); //handshake(bis, bos);
|
||||
byte [] expected_id = peerID.getID();
|
||||
if (!Arrays.equals(expected_id, id))
|
||||
throw new IOException("Unexpected peerID '"
|
||||
if (expected_id == null) {
|
||||
peerID.setID(id);
|
||||
} else if (Arrays.equals(expected_id, id)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handshake got matching IDs with " + toString());
|
||||
} else {
|
||||
throw new IOException("Unexpected peerID '"
|
||||
+ PeerID.idencode(id)
|
||||
+ "' expected '"
|
||||
+ PeerID.idencode(expected_id) + "'");
|
||||
_log.debug("Handshake got matching IDs with " + toString());
|
||||
}
|
||||
} else {
|
||||
_log.debug("Already have din [" + sock + "] with " + toString());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Already have din [" + sock + "] with " + toString());
|
||||
}
|
||||
|
||||
PeerConnectionIn in = new PeerConnectionIn(this, din);
|
||||
@ -229,7 +239,8 @@ public class Peer implements Comparable
|
||||
state = s;
|
||||
listener.connected(this);
|
||||
|
||||
_log.debug("Start running the reader with " + toString());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Start running the reader with " + toString());
|
||||
// Use this thread for running the incomming connection.
|
||||
// The outgoing connection creates its own Thread.
|
||||
out.startup();
|
||||
@ -279,7 +290,8 @@ public class Peer implements Comparable
|
||||
dout.write(my_id);
|
||||
dout.flush();
|
||||
|
||||
_log.debug("Wrote my shared hash and ID to " + toString());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Wrote my shared hash and ID to " + toString());
|
||||
|
||||
// Handshake read - header
|
||||
byte b = din.readByte();
|
||||
@ -306,7 +318,8 @@ public class Peer implements Comparable
|
||||
|
||||
// Handshake read - peer id
|
||||
din.readFully(bs);
|
||||
_log.debug("Read the remote side's hash and peerID fully from " + toString());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read the remote side's hash and peerID fully from " + toString());
|
||||
return bs;
|
||||
}
|
||||
|
||||
|
@ -76,10 +76,12 @@ public class PeerAcceptor
|
||||
// is this working right?
|
||||
try {
|
||||
peerInfoHash = readHash(in);
|
||||
_log.info("infohash read from " + socket.getPeerDestination().calculateHash().toBase64()
|
||||
+ ": " + Base64.encode(peerInfoHash));
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("infohash read from " + socket.getPeerDestination().calculateHash().toBase64()
|
||||
+ ": " + Base64.encode(peerInfoHash));
|
||||
} catch (IOException ioe) {
|
||||
_log.info("Unable to read the infohash from " + socket.getPeerDestination().calculateHash().toBase64());
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Unable to read the infohash from " + socket.getPeerDestination().calculateHash().toBase64());
|
||||
throw ioe;
|
||||
}
|
||||
in = new SequenceInputStream(new ByteArrayInputStream(peerInfoHash), in);
|
||||
|
@ -375,7 +375,8 @@ public class PeerCoordinator implements PeerListener
|
||||
|
||||
if (need_more)
|
||||
{
|
||||
_log.debug("Adding a peer " + peer.getPeerID().getAddress().calculateHash().toBase64() + " for " + metainfo.getName(), new Exception("add/run"));
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Adding a peer " + peer.getPeerID().toString() + " for " + metainfo.getName(), new Exception("add/run"));
|
||||
|
||||
// Run the peer with us as listener and the current bitfield.
|
||||
final PeerListener listener = this;
|
||||
|
@ -24,19 +24,33 @@ import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
|
||||
import org.klomp.snark.bencode.BDecoder;
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
import org.klomp.snark.bencode.InvalidBEncodingException;
|
||||
|
||||
/**
|
||||
* Store the address information about a peer.
|
||||
* Prior to 0.8.1, an instantiation required a peer ID, and full Destination address.
|
||||
* Starting with 0.8.1, to support compact tracker responses,
|
||||
* a PeerID can be instantiated with a Destination Hash alone.
|
||||
* The full destination lookup is deferred until getAddress() is called,
|
||||
* and the PeerID is not required.
|
||||
* Equality is now determined solely by the dest hash.
|
||||
*/
|
||||
public class PeerID implements Comparable
|
||||
{
|
||||
private final byte[] id;
|
||||
private final Destination address;
|
||||
private byte[] id;
|
||||
private Destination address;
|
||||
private final int port;
|
||||
|
||||
private byte[] destHash;
|
||||
/** whether we have tried to get the dest from the hash - only do once */
|
||||
private boolean triedDestLookup;
|
||||
private final int hash;
|
||||
|
||||
public PeerID(byte[] id, Destination address)
|
||||
@ -44,7 +58,7 @@ public class PeerID implements Comparable
|
||||
this.id = id;
|
||||
this.address = address;
|
||||
this.port = 6881;
|
||||
|
||||
this.destHash = address.calculateHash().getData();
|
||||
hash = calculateHash();
|
||||
}
|
||||
|
||||
@ -77,17 +91,49 @@ public class PeerID implements Comparable
|
||||
throw new InvalidBEncodingException("Invalid destination [" + bevalue.getString() + "]");
|
||||
|
||||
port = 6881;
|
||||
|
||||
this.destHash = address.calculateHash().getData();
|
||||
hash = calculateHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PeerID from a destHash
|
||||
* @since 0.8.1
|
||||
*/
|
||||
public PeerID(byte[] dest_hash) throws InvalidBEncodingException
|
||||
{
|
||||
// id and address remain null
|
||||
port = 6881;
|
||||
if (dest_hash.length != 32)
|
||||
throw new InvalidBEncodingException("bad hash length");
|
||||
destHash = dest_hash;
|
||||
hash = DataHelper.hashCode(dest_hash);
|
||||
}
|
||||
|
||||
public byte[] getID()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public Destination getAddress()
|
||||
/** for connecting out to peer based on desthash @since 0.8.1 */
|
||||
public void setID(byte[] xid)
|
||||
{
|
||||
id = xid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination.
|
||||
* If this PeerId was instantiated with a destHash,
|
||||
* and we have not yet done so, lookup the full destination, which may take
|
||||
* up to 10 seconds.
|
||||
* @return Dest or null if unknown
|
||||
*/
|
||||
public synchronized Destination getAddress()
|
||||
{
|
||||
if (address == null && destHash != null && !triedDestLookup) {
|
||||
String b32 = Base32.encode(destHash) + ".b32.i2p";
|
||||
address = I2PAppContext.getGlobalContext().namingService().lookup(b32);
|
||||
triedDestLookup = true;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
@ -96,16 +142,19 @@ public class PeerID implements Comparable
|
||||
return port;
|
||||
}
|
||||
|
||||
/** @since 0.8.1 */
|
||||
public byte[] getDestHash()
|
||||
{
|
||||
return destHash;
|
||||
}
|
||||
|
||||
private int calculateHash()
|
||||
{
|
||||
int b = 0;
|
||||
for (int i = 0; i < id.length; i++)
|
||||
b ^= id[i];
|
||||
return (b ^ address.hashCode()) ^ port;
|
||||
return DataHelper.hashCode(destHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash code of a PeerID is the exclusive or of all id bytes.
|
||||
* The hash code of a PeerID is the hashcode of the desthash
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
@ -115,18 +164,15 @@ public class PeerID implements Comparable
|
||||
|
||||
/**
|
||||
* Returns true if and only if this peerID and the given peerID have
|
||||
* the same 20 bytes as ID.
|
||||
* the same destination hash
|
||||
*/
|
||||
public boolean sameID(PeerID pid)
|
||||
{
|
||||
boolean equal = true;
|
||||
for (int i = 0; equal && i < id.length; i++)
|
||||
equal = id[i] == pid.id[i];
|
||||
return equal;
|
||||
return DataHelper.eq(destHash, pid.getDestHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* Two PeerIDs are equal when they have the same id, address and port.
|
||||
* Two PeerIDs are equal when they have the same dest hash
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
@ -135,9 +181,7 @@ public class PeerID implements Comparable
|
||||
{
|
||||
PeerID pid = (PeerID)o;
|
||||
|
||||
return port == pid.port
|
||||
&& address.equals(pid.address)
|
||||
&& sameID(pid);
|
||||
return sameID(pid);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@ -145,6 +189,7 @@ public class PeerID implements Comparable
|
||||
|
||||
/**
|
||||
* Compares port, address and id.
|
||||
* @deprecated unused? and will NPE now that address can be null?
|
||||
*/
|
||||
public int compareTo(Object o)
|
||||
{
|
||||
@ -176,6 +221,8 @@ public class PeerID implements Comparable
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (id == null || address == null)
|
||||
return "unkn@" + Base64.encode(destHash).substring(0, 6);
|
||||
int nonZero = 0;
|
||||
for (int i = 0; i < id.length; i++) {
|
||||
if (id[i] != 0) {
|
||||
|
@ -437,7 +437,7 @@ public class Snark
|
||||
try { storage.close(); } catch (IOException ioee) {
|
||||
ioee.printStackTrace();
|
||||
}
|
||||
fatal("Could not create storage", ioe);
|
||||
fatal("Could not check or create storage", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -357,6 +357,7 @@ public class TrackerClient extends I2PAppThread
|
||||
+ "&uploaded=" + uploaded
|
||||
+ "&downloaded=" + downloaded
|
||||
+ "&left=" + left
|
||||
+ "&compact"
|
||||
+ ((! event.equals(NO_EVENT)) ? ("&event=" + event) : "");
|
||||
if (left <= 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
|
||||
s += "&numwant=0";
|
||||
|
@ -24,7 +24,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -33,11 +32,17 @@ import org.klomp.snark.bencode.BDecoder;
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
import org.klomp.snark.bencode.InvalidBEncodingException;
|
||||
|
||||
/**
|
||||
* The data structure for the tracker response.
|
||||
* Handles both traditional and compact formats.
|
||||
* Compact format 1 - a list of hashes - early format for testing
|
||||
* Compact format 2 - One big string of concatenated hashes - official format
|
||||
*/
|
||||
public class TrackerInfo
|
||||
{
|
||||
private final String failure_reason;
|
||||
private final int interval;
|
||||
private final Set peers;
|
||||
private final Set<Peer> peers;
|
||||
private int complete;
|
||||
private int incomplete;
|
||||
|
||||
@ -73,10 +78,19 @@ public class TrackerInfo
|
||||
interval = beInterval.getInt();
|
||||
|
||||
BEValue bePeers = (BEValue)m.get("peers");
|
||||
if (bePeers == null)
|
||||
if (bePeers == null) {
|
||||
peers = Collections.EMPTY_SET;
|
||||
else
|
||||
peers = getPeers(bePeers.getList(), my_id, metainfo);
|
||||
} else {
|
||||
Set<Peer> p;
|
||||
try {
|
||||
// One big string (the official compact format)
|
||||
p = getPeers(bePeers.getBytes(), my_id, metainfo);
|
||||
} catch (InvalidBEncodingException ibe) {
|
||||
// List of Dictionaries or List of Strings
|
||||
p = getPeers(bePeers.getList(), my_id, metainfo);
|
||||
}
|
||||
peers = p;
|
||||
}
|
||||
|
||||
BEValue bev = (BEValue)m.get("complete");
|
||||
if (bev != null) try {
|
||||
@ -94,32 +108,68 @@ public class TrackerInfo
|
||||
}
|
||||
}
|
||||
|
||||
public static Set getPeers(InputStream in, byte[] my_id, MetaInfo metainfo)
|
||||
/******
|
||||
public static Set<Peer> getPeers(InputStream in, byte[] my_id, MetaInfo metainfo)
|
||||
throws IOException
|
||||
{
|
||||
return getPeers(new BDecoder(in), my_id, metainfo);
|
||||
}
|
||||
|
||||
public static Set getPeers(BDecoder be, byte[] my_id, MetaInfo metainfo)
|
||||
public static Set<Peer> getPeers(BDecoder be, byte[] my_id, MetaInfo metainfo)
|
||||
throws IOException
|
||||
{
|
||||
return getPeers(be.bdecodeList().getList(), my_id, metainfo);
|
||||
}
|
||||
******/
|
||||
|
||||
public static Set getPeers(List l, byte[] my_id, MetaInfo metainfo)
|
||||
/** List of Dictionaries or List of Strings */
|
||||
private static Set<Peer> getPeers(List<BEValue> l, byte[] my_id, MetaInfo metainfo)
|
||||
throws IOException
|
||||
{
|
||||
Set peers = new HashSet(l.size());
|
||||
Set<Peer> peers = new HashSet(l.size());
|
||||
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
for (BEValue bev : l) {
|
||||
PeerID peerID;
|
||||
try {
|
||||
peerID = new PeerID(((BEValue)it.next()).getMap());
|
||||
// Case 1 - non-compact - A list of dictionaries (maps)
|
||||
peerID = new PeerID(bev.getMap());
|
||||
} catch (InvalidBEncodingException ibe) {
|
||||
// don't let one bad entry spoil the whole list
|
||||
//Snark.debug("Discarding peer from list: " + ibe, Snark.ERROR);
|
||||
try {
|
||||
// Case 2 - compact - A list of 32-byte binary strings (hashes)
|
||||
// This was just for testing and is not the official format
|
||||
peerID = new PeerID(bev.getBytes());
|
||||
} catch (InvalidBEncodingException ibe2) {
|
||||
// don't let one bad entry spoil the whole list
|
||||
//Snark.debug("Discarding peer from list: " + ibe, Snark.ERROR);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
peers.add(new Peer(peerID, my_id, metainfo));
|
||||
}
|
||||
|
||||
return peers;
|
||||
}
|
||||
|
||||
private static final int HASH_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* One big string of concatenated 32-byte hashes
|
||||
* @since 0.8.1
|
||||
*/
|
||||
private static Set<Peer> getPeers(byte[] l, byte[] my_id, MetaInfo metainfo)
|
||||
throws IOException
|
||||
{
|
||||
int count = l.length / HASH_LENGTH;
|
||||
Set<Peer> peers = new HashSet(count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
PeerID peerID;
|
||||
byte[] hash = new byte[HASH_LENGTH];
|
||||
System.arraycopy(l, i * HASH_LENGTH, hash, 0, HASH_LENGTH);
|
||||
try {
|
||||
peerID = new PeerID(hash);
|
||||
} catch (InvalidBEncodingException ibe) {
|
||||
// won't happen
|
||||
continue;
|
||||
}
|
||||
peers.add(new Peer(peerID, my_id, metainfo));
|
||||
@ -128,7 +178,7 @@ public class TrackerInfo
|
||||
return peers;
|
||||
}
|
||||
|
||||
public Set getPeers()
|
||||
public Set<Peer> getPeers()
|
||||
{
|
||||
return peers;
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ public class BEValue
|
||||
* succeeds when the BEValue is actually a List, otherwise it will
|
||||
* throw a InvalidBEncodingException.
|
||||
*/
|
||||
public List getList() throws InvalidBEncodingException
|
||||
public List<BEValue> getList() throws InvalidBEncodingException
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -157,7 +157,7 @@ public class BEValue
|
||||
* values. This operation only succeeds when the BEValue is actually
|
||||
* a Map, otherwise it will throw a InvalidBEncodingException.
|
||||
*/
|
||||
public Map getMap() throws InvalidBEncodingException
|
||||
public Map<BEValue, BEValue> getMap() throws InvalidBEncodingException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ import java.io.PrintWriter;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
@ -821,10 +822,10 @@ public class I2PSnarkServlet extends Default {
|
||||
out.write("</td>\n</tr>\n");
|
||||
|
||||
if(showPeers && isRunning && curPeers > 0) {
|
||||
List peers = snark.coordinator.peerList();
|
||||
Iterator it = peers.iterator();
|
||||
while (it.hasNext()) {
|
||||
Peer peer = (Peer)it.next();
|
||||
List<Peer> peers = snark.coordinator.peerList();
|
||||
if (!showDebug)
|
||||
Collections.sort(peers, new PeerComparator());
|
||||
for (Peer peer : peers) {
|
||||
if (!peer.isConnected())
|
||||
continue;
|
||||
out.write("<tr class=\"" + rowClass + "\">");
|
||||
@ -908,6 +909,19 @@ public class I2PSnarkServlet extends Default {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by completeness (seeds first), then by ID
|
||||
* @since 0.8.1
|
||||
*/
|
||||
private static class PeerComparator implements Comparator<Peer> {
|
||||
public int compare(Peer l, Peer r) {
|
||||
int diff = r.completed() - l.completed(); // reverse
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
return l.toString().substring(5, 9).compareTo(r.toString().substring(5, 9));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeAddForm(PrintWriter out, HttpServletRequest req) throws IOException {
|
||||
String uri = req.getRequestURI();
|
||||
String newURL = req.getParameter("newURL");
|
||||
|
Reference in New Issue
Block a user