- Hide I2CP settings when in router context

- Better BEValue.toString()

(most of the following got missed in the last checkin)
- Fix about 9 NPEs
- Fix numwant in magnet mode
- Send metadata size in extension handshake
- Open trackers are primary if we don't have primary trackers
- Add missing break in port message handling
- Increase max msg size to account for metadata msg
- Remember magnets across restarts
- Drop peers w/o extensions if we need metainfo
- Fix DATA messages
- Fix tracker transition to non-magnet
- Fix infohash for non-magnet
- Fix up peer transition to non-magnet
- More logging
This commit is contained in:
zzz
2010-12-27 17:13:24 +00:00
parent bebd6b2022
commit 71043c41f1
14 changed files with 213 additions and 77 deletions

View File

@ -21,7 +21,6 @@ import org.klomp.snark.bencode.InvalidBEncodingException;
*/
abstract class ExtensionHandler {
private static final byte[] _handshake = buildHandshake();
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ExtensionHandler.class);
public static final int ID_METADATA = 3;
@ -32,17 +31,15 @@ abstract class ExtensionHandler {
/**
* @param metasize -1 if unknown
* @return bencoded outgoing handshake message
*/
public static byte[] getHandshake() {
return _handshake;
}
/** outgoing handshake message */
private static byte[] buildHandshake() {
public static byte[] getHandshake(int metasize) {
Map<String, Object> handshake = new HashMap();
Map<String, Integer> m = new HashMap();
m.put(TYPE_METADATA, Integer.valueOf(ID_METADATA));
if (metasize >= 0)
handshake.put("metadata_size", Integer.valueOf(metasize));
handshake.put("m", m);
handshake.put("p", Integer.valueOf(6881));
handshake.put("v", "I2PSnark");
@ -51,6 +48,8 @@ abstract class ExtensionHandler {
}
public static void handleMessage(Peer peer, PeerListener listener, int id, byte[] bs) {
if (_log.shouldLog(Log.INFO))
_log.info("Got extension msg " + id + " length " + bs.length + " from " + peer);
if (id == 0)
handleHandshake(peer, listener, bs);
else if (id == ID_METADATA)
@ -71,10 +70,24 @@ abstract class ExtensionHandler {
peer.setHandshakeMap(map);
Map<String, BEValue> msgmap = map.get("m").getMap();
// rv not used, just to throw an NPE to get out of here
msgmap.get(TYPE_METADATA).getInt();
if (msgmap.get(TYPE_METADATA) == null) {
if (_log.shouldLog(Log.WARN))
_log.debug("Peer does not support metadata extension: " + peer);
// drop if we need metainfo ?
return;
}
BEValue msize = map.get("metadata_size");
if (msize == null) {
if (_log.shouldLog(Log.WARN))
_log.debug("Peer does not have the metainfo size yet: " + peer);
// drop if we need metainfo ?
return;
}
int metaSize = msize.getInt();
if (_log.shouldLog(Log.WARN))
_log.debug("Got the metainfo size: " + metaSize);
int metaSize = map.get("metadata_size").getInt();
MagnetState state = peer.getMagnetState();
int remaining;
synchronized(state) {
@ -83,12 +96,16 @@ abstract class ExtensionHandler {
if (state.isInitialized()) {
if (state.getSize() != metaSize) {
if (_log.shouldLog(Log.WARN))
_log.debug("Wrong metainfo size " + metaSize + " from: " + peer);
peer.disconnect();
return;
}
} else {
// initialize it
if (metaSize > MAX_METADATA_SIZE) {
if (_log.shouldLog(Log.WARN))
_log.debug("Huge metainfo size " + metaSize + " from: " + peer);
peer.disconnect(false);
return;
}
@ -112,8 +129,7 @@ abstract class ExtensionHandler {
}
} catch (Exception e) {
if (_log.shouldLog(Log.WARN))
_log.info("Handshake exception from " + peer, e);
//peer.disconnect(false);
_log.warn("Handshake exception from " + peer, e);
}
}
@ -140,6 +156,8 @@ abstract class ExtensionHandler {
MagnetState state = peer.getMagnetState();
if (type == TYPE_REQUEST) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got request for " + piece + " from: " + peer);
byte[] pc;
synchronized(state) {
pc = state.getChunk(piece);
@ -150,12 +168,19 @@ abstract class ExtensionHandler {
listener.uploaded(peer, pc.length);
} else if (type == TYPE_DATA) {
int size = map.get("total_size").getInt();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got data for " + piece + " length " + size + " from: " + peer);
boolean done;
int chk = -1;
synchronized(state) {
if (state.isComplete())
return;
int len = is.available();
if (len != size) {
// probably fatal
if (_log.shouldLog(Log.WARN))
_log.warn("total_size " + size + " but avail data " + len);
}
peer.downloaded(len);
listener.downloaded(peer, len);
done = state.saveChunk(piece, bs, bs.length - len, len);
@ -219,15 +244,15 @@ abstract class ExtensionHandler {
private static void sendPiece(Peer peer, int piece, byte[] data) {
Map<String, Object> map = new HashMap();
map.put("msg_type", Integer.valueOf(TYPE_REQUEST));
map.put("msg_type", Integer.valueOf(TYPE_DATA));
map.put("piece", Integer.valueOf(piece));
map.put("total_size", Integer.valueOf(data.length));
byte[] dict = BEncoder.bencode(map);
byte[] payload = new byte[dict.length + data.length];
System.arraycopy(dict, 0, payload, 0, dict.length);
System.arraycopy(data, 0, payload, dict.length, payload.length);
System.arraycopy(data, 0, payload, dict.length, data.length);
try {
int hisMsgCode = peer.getHandshakeMap().get("m").getMap().get("METADATA").getInt();
int hisMsgCode = peer.getHandshakeMap().get("m").getMap().get(TYPE_METADATA).getInt();
peer.sendExtension(hisMsgCode, payload);
} catch (Exception e) {
// NPE, no metadata caps

View File

@ -446,6 +446,21 @@ public class I2PSnarkUtil {
return Boolean.valueOf(rv).booleanValue();
}
/**
* Like DataHelper.toHexString but ensures no loss of leading zero bytes
* @since 0.8.4
*/
public static String toHex(byte[] b) {
StringBuilder buf = new StringBuilder(40);
for (int i = 0; i < b.length; i++) {
int bi = b[i] & 0xff;
if (bi < 16)
buf.append('0');
buf.append(Integer.toHexString(bi));
}
return buf.toString();
}
/** hook between snark's logger and an i2p log */
void debug(String msg, int snarkDebugLevel) {
debug(msg, snarkDebugLevel, null);

View File

@ -53,8 +53,6 @@ class MagnetState {
metainfo = meta;
initialize(meta.getInfoBytes().length);
complete = true;
} else {
metainfoBytes = new byte[metaSize];
}
}
@ -68,10 +66,13 @@ class MagnetState {
isInitialized = true;
metaSize = size;
totalChunks = (size + (CHUNK_SIZE - 1)) / CHUNK_SIZE;
if (metainfo == null) {
if (metainfo != null) {
metainfoBytes = metainfo.getInfoBytes();
} else {
// we don't need these if complete
have = new BitField(totalChunks);
requested = new BitField(totalChunks);
metainfoBytes = new byte[metaSize];
}
}
@ -194,8 +195,7 @@ class MagnetState {
InputStream is = new ByteArrayInputStream(metainfoBytes);
BDecoder dec = new BDecoder(is);
BEValue bev = dec.bdecodeMap();
Map<String, BEValue> info = bev.getMap();
map.put("info", info);
map.put("info", bev);
MetaInfo newmeta = new MetaInfo(map);
if (!DataHelper.eq(newmeta.getInfoHash(), infohash))
throw new IOException("info hash mismatch");

View File

@ -104,7 +104,7 @@ class Message
if (type == REQUEST || type == CANCEL)
datalen += 4;
// length is 1 byte
// msg type is 1 byte
if (type == EXTENSION)
datalen += 1;
@ -167,6 +167,8 @@ class Message
return "PIECE(" + piece + "," + begin + "," + length + ")";
case CANCEL:
return "CANCEL(" + piece + "," + begin + "," + length + ")";
case PORT:
return "PORT(" + piece + ")";
case EXTENSION:
return "EXTENSION(" + piece + ',' + data.length + ')';
default:

View File

@ -120,7 +120,7 @@ public class Peer implements Comparable
this.peerID = new PeerID(id, sock.getPeerDestination());
_id = ++__id;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating " + _id));
_log.debug("Creating a new peer " + peerID.toString(), new Exception("creating " + _id));
}
/**
@ -261,14 +261,22 @@ public class Peer implements Comparable
_log.debug("Already have din [" + sock + "] with " + toString());
}
// bad idea?
if (metainfo == null && (options & OPTION_EXTENSION) == 0) {
if (_log.shouldLog(Log.INFO))
_log.info("Peer does not support extensions and we need metainfo, dropping");
throw new IOException("Peer does not support extensions and we need metainfo, dropping");
}
PeerConnectionIn in = new PeerConnectionIn(this, din);
PeerConnectionOut out = new PeerConnectionOut(this, dout);
PeerState s = new PeerState(this, listener, metainfo, in, out);
if ((options & OPTION_EXTENSION) != 0) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer supports extensions, sending test message");
out.sendExtension(0, ExtensionHandler.getHandshake());
_log.debug("Peer supports extensions, sending reply message");
int metasize = metainfo != null ? metainfo.getInfoBytes().length : -1;
out.sendExtension(0, ExtensionHandler.getHandshake(metasize));
}
if ((options & OPTION_DHT) != 0 && util.getDHT() != null) {
@ -423,6 +431,7 @@ public class Peer implements Comparable
* @since 0.8.4
*/
public void setMetaInfo(MetaInfo meta) {
metainfo = meta;
PeerState s = state;
if (s != null)
s.setMetaInfo(meta);

View File

@ -32,6 +32,13 @@ class PeerConnectionIn implements Runnable
private final Peer peer;
private final DataInputStream din;
// The max length of a complete message in bytes.
// The biggest is the piece message, for which the length is the
// request size (32K) plus 9. (we could also check if Storage.MAX_PIECES / 8
// in the bitfield message is bigger but it's currently 5000/8 = 625 so don't bother)
private static final int MAX_MSG_SIZE = Math.max(PeerState.PARTSIZE + 9,
MagnetState.CHUNK_SIZE + 100); // 100 for the ext msg dictionary
private Thread thread;
private volatile boolean quit;
@ -77,13 +84,9 @@ class PeerConnectionIn implements Runnable
int len;
// Wait till we hear something...
// The length of a complete message in bytes.
// The biggest is the piece message, for which the length is the
// request size (32K) plus 9. (we could also check if Storage.MAX_PIECES / 8
// in the bitfield message is bigger but it's currently 5000/8 = 625 so don't bother)
int i = din.readInt();
lastRcvd = System.currentTimeMillis();
if (i < 0 || i > PeerState.PARTSIZE + 9)
if (i < 0 || i > MAX_MSG_SIZE)
throw new IOException("Unexpected length prefix: " + i);
if (i == 0)
@ -176,13 +179,14 @@ class PeerConnectionIn implements Runnable
ps.portMessage(port);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received port message from " + peer);
break;
case 20: // Extension message
int id = din.readUnsignedByte();
byte[] payload = new byte[i-2];
din.readFully(payload);
ps.extensionMessage(id, payload);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received extension message from " + peer);
ps.extensionMessage(id, payload);
break;
default:
byte[] bs = new byte[i-1];

View File

@ -410,7 +410,7 @@ public class PeerCoordinator implements PeerListener
name = "Magnet";
else
name = metainfo.getName();
_log.info("New connection to peer: " + peer + " for " + metainfo.getName());
_log.info("New connection to peer: " + peer + " for " + name);
}
// Add it to the beginning of the list.
@ -1169,9 +1169,6 @@ public class PeerCoordinator implements PeerListener
_log.warn("Got completed metainfo via extension");
metainfo = magnetState.getMetaInfo();
listener.gotMetaInfo(this, metainfo);
for (Peer p : peers) {
p.setMetaInfo(metainfo);
}
}
}
}
@ -1184,6 +1181,11 @@ public class PeerCoordinator implements PeerListener
*/
public void setStorage(Storage stg) {
storage = stg;
setWantedPieces();
// ok we should be in business
for (Peer p : peers) {
p.setMetaInfo(metainfo);
}
}
/**

View File

@ -511,6 +511,8 @@ class PeerState implements DataLoader
//bitfield = new BitField(meta.getPieces());
}
metainfo = meta;
if (bitfield.count() > 0)
setInteresting(true);
}
/** @since 0.8.4 */

View File

@ -243,7 +243,7 @@ public class Snark
public static final String PROP_MAX_CONNECTIONS = "i2psnark.maxConnections";
/** most of these used to be public, use accessors below instead */
private final String torrent;
private String torrent;
private MetaInfo meta;
private Storage storage;
private PeerCoordinator coordinator;
@ -360,6 +360,7 @@ public class Snark
}
}
meta = new MetaInfo(new BDecoder(in));
infoHash = meta.getInfoHash();
}
catch(IOException ioe)
{
@ -1028,8 +1029,13 @@ public class Snark
meta = metainfo;
try {
storage = new Storage(_util, meta, this);
if (completeListener != null)
completeListener.gotMetaInfo(this);
storage.check(rootDataDir);
if (completeListener != null) {
String newName = completeListener.gotMetaInfo(this);
if (newName != null)
torrent = newName;
// else some horrible problem
}
coordinator.setStorage(storage);
} catch (IOException ioe) {
if (storage != null) {
@ -1125,9 +1131,10 @@ public class Snark
* metainfo and storage. The listener should now call getMetaInfo()
* and save the data to disk.
*
* @return the new name for the torrent or null on error
* @since 0.8.4
*/
public void gotMetaInfo(Snark snark);
public String gotMetaInfo(Snark snark);
// not really listeners but the easiest way to get back to an optional SnarkManager
public long getSavedTorrentTime(Snark snark);

View File

@ -68,7 +68,7 @@ public class SnarkManager implements Snark.CompleteListener {
public static final String PROP_META_PREFIX = "i2psnark.zmeta.";
public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
public static final String PROP_META_PRIORITY_SUFFIX = ".priority";
public static final String PROP_META_MAGNET_SUFFIX = ".magnet";
public static final String PROP_META_MAGNET_PREFIX = "i2psnark.magnet.";
private static final String CONFIG_FILE = "i2psnark.config";
public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops
@ -340,7 +340,9 @@ public class SnarkManager implements Snark.CompleteListener {
int oldI2CPPort = _util.getI2CPPort();
String oldI2CPHost = _util.getI2CPHost();
int port = oldI2CPPort;
try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {}
if (i2cpPort != null) {
try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {}
}
String host = oldI2CPHost;
Map opts = new HashMap();
if (i2cpOpts == null) i2cpOpts = "";
@ -627,7 +629,7 @@ public class SnarkManager implements Snark.CompleteListener {
* @throws RuntimeException via Snark.fatal()
* @since 0.8.4
*/
public void addMagnet(String name, byte[] ih) {
public void addMagnet(String name, byte[] ih, boolean updateStatus) {
Snark torrent = new Snark(_util, name, ih, this,
_peerCoordinatorSet, _connectionAcceptor,
false, getDataDir().getPath());
@ -640,6 +642,8 @@ public class SnarkManager implements Snark.CompleteListener {
}
// Tell the dir monitor not to delete us
_magnets.add(name);
if (updateStatus)
saveMagnetStatus(ih);
_snarks.put(name, torrent);
}
if (shouldAutoStart()) {
@ -667,6 +671,7 @@ public class SnarkManager implements Snark.CompleteListener {
}
snark.stopTorrent();
_magnets.remove(snark.getName());
removeMagnetStatus(snark.getInfoHash());
}
/**
@ -914,6 +919,28 @@ public class SnarkManager implements Snark.CompleteListener {
saveConfig();
}
/**
* Just remember we have it
* @since 0.8.4
*/
public void saveMagnetStatus(byte[] ih) {
String infohash = Base64.encode(ih);
infohash = infohash.replace('=', '$');
_config.setProperty(PROP_META_MAGNET_PREFIX + infohash, ".");
saveConfig();
}
/**
* Remove the magnet marker from the config file.
* @since 0.8.4
*/
public void removeMagnetStatus(byte[] ih) {
String infohash = Base64.encode(ih);
infohash = infohash.replace('=', '$');
_config.remove(PROP_META_MAGNET_PREFIX + infohash);
saveConfig();
}
/**
* Does not really delete on failure, that's the caller's responsibility.
* Warning - does not validate announce URL - use TrackerClient.isValidAnnounce()
@ -1032,12 +1059,10 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
//start magnets
// here because we need to delay until I2CP is up
// although the user will see the default until then
getBWLimit();
boolean doMagnets = true;
while (true) {
File dir = getDataDir();
if (_log.shouldLog(Log.DEBUG))
@ -1050,6 +1075,10 @@ public class SnarkManager implements Snark.CompleteListener {
} catch (Exception e) {
_log.error("Error in the DirectoryMonitor", e);
}
if (doMagnets) {
addMagnets();
doMagnets = false;
}
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
}
}
@ -1090,9 +1119,10 @@ public class SnarkManager implements Snark.CompleteListener {
* and save the data to disk.
* A Snark.CompleteListener method.
*
* @return the new name for the torrent or null on error
* @since 0.8.4
*/
public void gotMetaInfo(Snark snark) {
public String gotMetaInfo(Snark snark) {
MetaInfo meta = snark.getMetaInfo();
Storage storage = snark.getStorage();
if (meta != null && storage != null) {
@ -1100,23 +1130,51 @@ public class SnarkManager implements Snark.CompleteListener {
if (rejectMessage != null) {
addMessage(rejectMessage);
snark.stopTorrent();
return;
return null;
}
saveTorrentStatus(meta, storage.getBitField(), null); // no file priorities
String name = (new File(getDataDir(), storage.getBaseName() + ".torrent")).getAbsolutePath();
try {
synchronized (_snarks) {
locked_writeMetaInfo(meta, name);
// put it in the list under the new name
_snarks.remove(snark.getName());
_snarks.put(name, snark);
}
_magnets.remove(snark.getName());
removeMagnetStatus(snark.getInfoHash());
addMessage(_("Metainfo received for {0}", snark.getName()));
addMessage(_("Starting up torrent {0}", storage.getBaseName()));
return name;
} catch (IOException ioe) {
addMessage(_("Failed to copy torrent file to {0}", name));
_log.error("Failed to write torrent file", ioe);
}
}
return null;
}
// End Snark.CompleteListeners
/**
* Add all magnets from the config file
* @since 0.8.4
*/
private void addMagnets() {
for (Object o : _config.keySet()) {
String k = (String) o;
if (k.startsWith(PROP_META_MAGNET_PREFIX)) {
String b64 = k.substring(PROP_META_MAGNET_PREFIX.length());
b64 = b64.replace('$', '=');
byte[] ih = Base64.decode(b64);
// ignore value
if (ih != null && ih.length == 20)
addMagnet("Magnet: " + I2PSnarkUtil.toHex(ih), ih, false);
// else remove from config?
}
}
}
private void monitorTorrents(File dir) {
String fileNames[] = dir.list(TorrentFilenameFilter.instance());
List<String> foundNames = new ArrayList(0);

View File

@ -173,7 +173,8 @@ public class TrackerClient extends I2PAppThread
continue;
if (primary.startsWith("http://i2p/" + dest))
continue;
trackers.add(new Tracker(url, false));
// opentrackers are primary if we don't have primary
trackers.add(new Tracker(url, primary.equals("")));
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
}
}
@ -238,7 +239,7 @@ public class TrackerClient extends I2PAppThread
uploaded = coordinator.getUploaded();
downloaded = coordinator.getDownloaded();
left = coordinator.getLeft();
left = coordinator.getLeft(); // -1 in magnet mode
// First time we got a complete download?
String event;
@ -289,7 +290,7 @@ public class TrackerClient extends I2PAppThread
}
}
if ( (left > 0) && (!completed) ) {
if ( (left != 0) && (!completed) ) {
// we only want to talk to new people if we need things
// from them (duh)
List<Peer> ordered = new ArrayList(peers);
@ -344,7 +345,7 @@ public class TrackerClient extends I2PAppThread
// FIXME this needs to be in its own thread
if (_util.getDHT() != null && !stop) {
int numwant;
if (left <= 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
numwant = 1;
else
numwant = _util.getMaxConnections();
@ -362,7 +363,7 @@ public class TrackerClient extends I2PAppThread
List<Peer> peers = new ArrayList(hashes.size());
for (Hash h : hashes) {
PeerID pID = new PeerID(h.getData());
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), meta));
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
}
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
@ -370,7 +371,7 @@ public class TrackerClient extends I2PAppThread
Peer cur = it.next();
if (coordinator.addPeer(cur)) {
int delay = DELAY_MUL;
delay *= ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
delay *= r.nextInt(10);
delay += DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
@ -418,6 +419,8 @@ public class TrackerClient extends I2PAppThread
long downloaded, long left, String event)
throws IOException
{
// What do we send for left in magnet mode? Can we omit it?
long tleft = left >= 0 ? left : 1;
String s = tr.announce
+ "?info_hash=" + infoHash
+ "&peer_id=" + peerID
@ -425,10 +428,10 @@ public class TrackerClient extends I2PAppThread
+ "&ip=" + _util.getOurIPString() + ".i2p"
+ "&uploaded=" + uploaded
+ "&downloaded=" + downloaded
+ "&left=" + left
+ "&left=" + tleft
+ "&compact=1" // NOTE: opentracker will return 400 for &compact alone
+ ((! event.equals(NO_EVENT)) ? ("&event=" + event) : "");
if (left <= 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
s += "&numwant=0";
else
s += "&numwant=" + _util.getMaxConnections();
@ -445,7 +448,7 @@ public class TrackerClient extends I2PAppThread
in = new FileInputStream(fetched);
TrackerInfo info = new TrackerInfo(in, snark.getID(),
snark.getMetaInfo());
snark.getInfoHash(), snark.getMetaInfo());
_util.debug("TrackerClient response: " + info, Snark.INFO);
String failure = info.getFailureReason();

View File

@ -46,19 +46,20 @@ public class TrackerInfo
private int complete;
private int incomplete;
public TrackerInfo(InputStream in, byte[] my_id, MetaInfo metainfo)
/** @param metainfo may be null */
public TrackerInfo(InputStream in, byte[] my_id, byte[] infohash, MetaInfo metainfo)
throws IOException
{
this(new BDecoder(in), my_id, metainfo);
this(new BDecoder(in), my_id, infohash, metainfo);
}
public TrackerInfo(BDecoder be, byte[] my_id, MetaInfo metainfo)
private TrackerInfo(BDecoder be, byte[] my_id, byte[] infohash, MetaInfo metainfo)
throws IOException
{
this(be.bdecodeMap().getMap(), my_id, metainfo);
this(be.bdecodeMap().getMap(), my_id, infohash, metainfo);
}
public TrackerInfo(Map m, byte[] my_id, MetaInfo metainfo)
private TrackerInfo(Map m, byte[] my_id, byte[] infohash, MetaInfo metainfo)
throws IOException
{
BEValue reason = (BEValue)m.get("failure reason");
@ -84,10 +85,10 @@ public class TrackerInfo
Set<Peer> p;
try {
// One big string (the official compact format)
p = getPeers(bePeers.getBytes(), my_id, metainfo);
p = getPeers(bePeers.getBytes(), my_id, infohash, metainfo);
} catch (InvalidBEncodingException ibe) {
// List of Dictionaries or List of Strings
p = getPeers(bePeers.getList(), my_id, metainfo);
p = getPeers(bePeers.getList(), my_id, infohash, metainfo);
}
peers = p;
}
@ -123,7 +124,7 @@ public class TrackerInfo
******/
/** List of Dictionaries or List of Strings */
private static Set<Peer> getPeers(List<BEValue> l, byte[] my_id, MetaInfo metainfo)
private static Set<Peer> getPeers(List<BEValue> l, byte[] my_id, byte[] infohash, MetaInfo metainfo)
throws IOException
{
Set<Peer> peers = new HashSet(l.size());
@ -144,7 +145,7 @@ public class TrackerInfo
continue;
}
}
peers.add(new Peer(peerID, my_id, metainfo.getInfoHash(), metainfo));
peers.add(new Peer(peerID, my_id, infohash, metainfo));
}
return peers;
@ -156,7 +157,7 @@ public class TrackerInfo
* One big string of concatenated 32-byte hashes
* @since 0.8.1
*/
private static Set<Peer> getPeers(byte[] l, byte[] my_id, MetaInfo metainfo)
private static Set<Peer> getPeers(byte[] l, byte[] my_id, byte[] infohash, MetaInfo metainfo)
throws IOException
{
int count = l.length / HASH_LENGTH;
@ -172,7 +173,7 @@ public class TrackerInfo
// won't happen
continue;
}
peers.add(new Peer(peerID, my_id, metainfo.getInfoHash(), metainfo));
peers.add(new Peer(peerID, my_id, infohash, metainfo));
}
return peers;

View File

@ -24,6 +24,8 @@ import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import net.i2p.data.Base64;
/**
* Holds different types that a bencoded byte array can represent.
* You need to call the correct get method to get the correct java
@ -180,10 +182,14 @@ public class BEValue
{
byte[] bs = (byte[])value;
// XXX - Stupid heuristic... and not UTF-8
if (bs.length <= 12)
valueString = new String(bs);
//if (bs.length <= 12)
// valueString = new String(bs);
//else
// valueString = "bytes:" + bs.length;
if (bs.length <= 32)
valueString = bs.length + " bytes: " + Base64.encode(bs);
else
valueString = "bytes:" + bs.length;
valueString = bs.length + " bytes";
}
else
valueString = value.toString();

View File

@ -1314,15 +1314,17 @@ public class I2PSnarkServlet extends Default {
out.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
out.write(renderOptions(0, 4, options.remove("outbound.length"), "outbound.length", HOP));
out.write("<tr><td>");
out.write(_("I2CP host"));
out.write(": <td><input type=\"text\" name=\"i2cpHost\" value=\""
+ _manager.util().getI2CPHost() + "\" size=\"15\" > ");
if (!_context.isRouterContext()) {
out.write("<tr><td>");
out.write(_("I2CP host"));
out.write(": <td><input type=\"text\" name=\"i2cpHost\" value=\""
+ _manager.util().getI2CPHost() + "\" size=\"15\" > ");
out.write("<tr><td>");
out.write(_("I2CP port"));
out.write(": <td><input type=\"text\" name=\"i2cpPort\" class=\"r\" value=\"" +
+ _manager.util().getI2CPPort() + "\" size=\"5\" maxlength=\"5\" > <br>\n");
out.write("<tr><td>");
out.write(_("I2CP port"));
out.write(": <td><input type=\"text\" name=\"i2cpPort\" class=\"r\" value=\"" +
+ _manager.util().getI2CPPort() + "\" size=\"5\" maxlength=\"5\" > <br>\n");
}
StringBuilder opts = new StringBuilder(64);
for (Iterator iter = options.entrySet().iterator(); iter.hasNext(); ) {