forked from I2P_Developers/i2p.i2p
* i2psnark:
- Store seed/leech status in DHT tracker (ticket #1280) - Increase max received DHT nodes (Vuze sends more than K) - Recognize not-registered message from diftracker - Fix bug in DHT unannounce()
This commit is contained in:
@ -221,7 +221,8 @@ class PeerCheckerTask implements Runnable
|
|||||||
peer.keepAlive();
|
peer.keepAlive();
|
||||||
// announce them to local tracker (TrackerClient does this too)
|
// announce them to local tracker (TrackerClient does this too)
|
||||||
if (dht != null && (_runCount % 5) == 0) {
|
if (dht != null && (_runCount % 5) == 0) {
|
||||||
dht.announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
|
dht.announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash(),
|
||||||
|
peer.isCompleted());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +271,7 @@ class PeerCheckerTask implements Runnable
|
|||||||
|
|
||||||
// announce ourselves to local tracker (TrackerClient does this too)
|
// announce ourselves to local tracker (TrackerClient does this too)
|
||||||
if (dht != null && (_runCount % 16) == 0) {
|
if (dht != null && (_runCount % 16) == 0) {
|
||||||
dht.announce(coordinator.getInfoHash());
|
dht.announce(coordinator.getInfoHash(), coordinator.completed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,7 @@ public class TrackerClient implements Runnable {
|
|||||||
private static final String COMPLETED_EVENT = "completed";
|
private static final String COMPLETED_EVENT = "completed";
|
||||||
private static final String STOPPED_EVENT = "stopped";
|
private static final String STOPPED_EVENT = "stopped";
|
||||||
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
|
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
|
||||||
|
private static final String NOT_REGISTERED_2 = "torrent not found"; // diftracker
|
||||||
/** this is our equivalent to router.utorrent.com for bootstrap */
|
/** this is our equivalent to router.utorrent.com for bootstrap */
|
||||||
private static final String DEFAULT_BACKUP_TRACKER = "http://tracker.welterde.i2p/a";
|
private static final String DEFAULT_BACKUP_TRACKER = "http://tracker.welterde.i2p/a";
|
||||||
|
|
||||||
@ -109,6 +110,8 @@ public class TrackerClient implements Runnable {
|
|||||||
// these 2 used in loop()
|
// these 2 used in loop()
|
||||||
private volatile boolean runStarted;
|
private volatile boolean runStarted;
|
||||||
private volatile int consecutiveFails;
|
private volatile int consecutiveFails;
|
||||||
|
// if we don't want anything else.
|
||||||
|
// Not necessarily seeding, as we may have skipped some files.
|
||||||
private boolean completed;
|
private boolean completed;
|
||||||
private volatile boolean _fastUnannounce;
|
private volatile boolean _fastUnannounce;
|
||||||
private long lastDHTAnnounce;
|
private long lastDHTAnnounce;
|
||||||
@ -391,7 +394,7 @@ public class TrackerClient implements Runnable {
|
|||||||
// Local DHT tracker announce
|
// Local DHT tracker announce
|
||||||
DHT dht = _util.getDHT();
|
DHT dht = _util.getDHT();
|
||||||
if (dht != null && (meta == null || !meta.isPrivate()))
|
if (dht != null && (meta == null || !meta.isPrivate()))
|
||||||
dht.announce(snark.getInfoHash());
|
dht.announce(snark.getInfoHash(), coordinator.completed());
|
||||||
|
|
||||||
int oldSeenPeers = snark.getTrackerSeenPeers();
|
int oldSeenPeers = snark.getTrackerSeenPeers();
|
||||||
int maxSeenPeers = 0;
|
int maxSeenPeers = 0;
|
||||||
@ -539,7 +542,8 @@ public class TrackerClient implements Runnable {
|
|||||||
DHT dht = _util.getDHT();
|
DHT dht = _util.getDHT();
|
||||||
if (dht != null) {
|
if (dht != null) {
|
||||||
for (Peer peer : peers) {
|
for (Peer peer : peers) {
|
||||||
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
|
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash(),
|
||||||
|
false); // TODO actual seed/leech status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,13 +576,15 @@ public class TrackerClient implements Runnable {
|
|||||||
// don't show secondary tracker problems to the user
|
// don't show secondary tracker problems to the user
|
||||||
if (tr.isPrimary)
|
if (tr.isPrimary)
|
||||||
snark.setTrackerProblems(tr.trackerProblems);
|
snark.setTrackerProblems(tr.trackerProblems);
|
||||||
if (tr.trackerProblems.toLowerCase(Locale.US).startsWith(NOT_REGISTERED)) {
|
String tplc = tr.trackerProblems.toLowerCase(Locale.US);
|
||||||
|
if (tplc.startsWith(NOT_REGISTERED) || tplc.startsWith(NOT_REGISTERED_2)) {
|
||||||
// Give a guy some time to register it if using opentrackers too
|
// Give a guy some time to register it if using opentrackers too
|
||||||
//if (trckrs.size() == 1) {
|
//if (trckrs.size() == 1) {
|
||||||
// stop = true;
|
// stop = true;
|
||||||
// snark.stopTorrent();
|
// snark.stopTorrent();
|
||||||
//} else { // hopefully each on the opentrackers list is really open
|
//} else { // hopefully each on the opentrackers list is really open
|
||||||
if (tr.registerFails++ > MAX_REGISTER_FAILS)
|
if (tr.registerFails++ > MAX_REGISTER_FAILS ||
|
||||||
|
(!tr.isPrimary && tr.registerFails > MAX_REGISTER_FAILS / 2))
|
||||||
tr.stop = true;
|
tr.stop = true;
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@ -654,7 +660,7 @@ public class TrackerClient implements Runnable {
|
|||||||
numwant = _util.getMaxConnections();
|
numwant = _util.getMaxConnections();
|
||||||
Collection<Hash> hashes = dht.getPeersAndAnnounce(snark.getInfoHash(), numwant,
|
Collection<Hash> hashes = dht.getPeersAndAnnounce(snark.getInfoHash(), numwant,
|
||||||
5*60*1000, DHT_ANNOUNCE_PEERS, 3*60*1000,
|
5*60*1000, DHT_ANNOUNCE_PEERS, 3*60*1000,
|
||||||
coordinator.completed());
|
coordinator.completed(), numwant <= 1);
|
||||||
if (!hashes.isEmpty()) {
|
if (!hashes.isEmpty()) {
|
||||||
runStarted = true;
|
runStarted = true;
|
||||||
lastDHTAnnounce = _util.getContext().clock().now();
|
lastDHTAnnounce = _util.getContext().clock().now();
|
||||||
|
@ -46,11 +46,12 @@ public interface DHT {
|
|||||||
* @param annMax the number of peers to announce to
|
* @param annMax the number of peers to announce to
|
||||||
* @param annMaxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
|
* @param annMaxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
|
||||||
* @param isSeed true if seed, false if leech
|
* @param isSeed true if seed, false if leech
|
||||||
|
* @param noSeeds true if we do not want seeds in the result
|
||||||
* @return possibly empty (never null)
|
* @return possibly empty (never null)
|
||||||
*/
|
*/
|
||||||
public Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait,
|
public Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait,
|
||||||
int annMax, long annMaxWait,
|
int annMax, long annMaxWait,
|
||||||
boolean isSeed);
|
boolean isSeed, boolean noSeeds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Announce to ourselves.
|
* Announce to ourselves.
|
||||||
@ -58,7 +59,7 @@ public interface DHT {
|
|||||||
*
|
*
|
||||||
* @param ih the Info Hash (torrent)
|
* @param ih the Info Hash (torrent)
|
||||||
*/
|
*/
|
||||||
public void announce(byte[] ih);
|
public void announce(byte[] ih, boolean isSeed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Announce somebody else we know about to ourselves.
|
* Announce somebody else we know about to ourselves.
|
||||||
@ -67,7 +68,7 @@ public interface DHT {
|
|||||||
* @param ih the Info Hash (torrent)
|
* @param ih the Info Hash (torrent)
|
||||||
* @param peerHash the peer's Hash
|
* @param peerHash the peer's Hash
|
||||||
*/
|
*/
|
||||||
public void announce(byte[] ih, byte[] peerHash);
|
public void announce(byte[] ih, byte[] peerHash, boolean isSeed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove reference to ourselves in the local tracker.
|
* Remove reference to ourselves in the local tracker.
|
||||||
|
@ -60,7 +60,7 @@ class DHTTracker {
|
|||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void announce(InfoHash ih, Hash hash) {
|
void announce(InfoHash ih, Hash hash, boolean isSeed) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Announce " + hash + " for " + ih);
|
_log.debug("Announce " + hash + " for " + ih);
|
||||||
Peers peers = _torrents.get(ih);
|
Peers peers = _torrents.get(ih);
|
||||||
@ -79,6 +79,9 @@ class DHTTracker {
|
|||||||
if (peer2 != null)
|
if (peer2 != null)
|
||||||
peer = peer2;
|
peer = peer2;
|
||||||
peer.setLastSeen(_context.clock().now());
|
peer.setLastSeen(_context.clock().now());
|
||||||
|
// don't let false trump true, as not all sources know the seed status
|
||||||
|
if (isSeed)
|
||||||
|
peer.setSeed(true);
|
||||||
} else {
|
} else {
|
||||||
// We could update setLastSeen if he is already
|
// We could update setLastSeen if he is already
|
||||||
// in there, but that would tend to keep
|
// in there, but that would tend to keep
|
||||||
@ -94,26 +97,42 @@ class DHTTracker {
|
|||||||
Peers peers = _torrents.get(ih);
|
Peers peers = _torrents.get(ih);
|
||||||
if (peers == null)
|
if (peers == null)
|
||||||
return;
|
return;
|
||||||
Peer peer = new Peer(hash.getData());
|
peers.remove(hash);
|
||||||
peers.remove(peer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller's responsibility to remove himself from the list
|
* Caller's responsibility to remove himself from the list
|
||||||
|
*
|
||||||
|
* @param noSeeds true if we do not want seeds in the result
|
||||||
* @return list or empty list (never null)
|
* @return list or empty list (never null)
|
||||||
*/
|
*/
|
||||||
List<Hash> getPeers(InfoHash ih, int max) {
|
List<Hash> getPeers(InfoHash ih, int max, boolean noSeeds) {
|
||||||
Peers peers = _torrents.get(ih);
|
Peers peers = _torrents.get(ih);
|
||||||
if (peers == null)
|
if (peers == null || max <= 0)
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
||||||
int size = peers.size();
|
List<Peer> rv = new ArrayList<Peer>(peers.values());
|
||||||
List<Hash> rv = new ArrayList<Hash>(peers.values());
|
int size = rv.size();
|
||||||
if (max < size) {
|
if (max < size)
|
||||||
Collections.shuffle(rv, _context.random());
|
Collections.shuffle(rv, _context.random());
|
||||||
|
if (noSeeds) {
|
||||||
|
int i = 0;
|
||||||
|
for (Iterator<Peer> iter = rv.iterator(); iter.hasNext(); ) {
|
||||||
|
if (iter.next().isSeed())
|
||||||
|
iter.remove();
|
||||||
|
else if (++i >= max)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (max < rv.size())
|
||||||
|
rv = rv.subList(0, max);
|
||||||
|
} else {
|
||||||
|
if (max < size)
|
||||||
rv = rv.subList(0, max);
|
rv = rv.subList(0, max);
|
||||||
}
|
}
|
||||||
return rv;
|
// a Peer is a Hash
|
||||||
|
List rv1 = rv;
|
||||||
|
List<Hash> rv2 = rv1;
|
||||||
|
return rv2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -317,14 +317,15 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
* @param annMax the number of peers to announce to
|
* @param annMax the number of peers to announce to
|
||||||
* @param annMaxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
|
* @param annMaxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
|
||||||
* @param isSeed true if seed, false if leech
|
* @param isSeed true if seed, false if leech
|
||||||
|
* @param noSeeds true if we do not want seeds in the result
|
||||||
* @return possibly empty (never null)
|
* @return possibly empty (never null)
|
||||||
*/
|
*/
|
||||||
public Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait,
|
public Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait,
|
||||||
int annMax, long annMaxWait,
|
int annMax, long annMaxWait,
|
||||||
boolean isSeed) {
|
boolean isSeed, boolean noSeeds) {
|
||||||
// check local tracker first
|
// check local tracker first
|
||||||
InfoHash iHash = new InfoHash(ih);
|
InfoHash iHash = new InfoHash(ih);
|
||||||
Collection<Hash> rv = _tracker.getPeers(iHash, max);
|
Collection<Hash> rv = _tracker.getPeers(iHash, max, noSeeds);
|
||||||
rv.remove(_myNodeInfo.getHash());
|
rv.remove(_myNodeInfo.getHash());
|
||||||
if (rv.size() >= max)
|
if (rv.size() >= max)
|
||||||
return rv;
|
return rv;
|
||||||
@ -360,7 +361,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Try " + i + ": " + nInfo);
|
_log.debug("Try " + i + ": " + nInfo);
|
||||||
|
|
||||||
ReplyWaiter waiter = sendGetPeers(nInfo, iHash);
|
ReplyWaiter waiter = sendGetPeers(nInfo, iHash, noSeeds);
|
||||||
if (waiter == null)
|
if (waiter == null)
|
||||||
continue;
|
continue;
|
||||||
synchronized(waiter) {
|
synchronized(waiter) {
|
||||||
@ -419,7 +420,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
}
|
}
|
||||||
// now announce
|
// now announce
|
||||||
if (!heardFrom.isEmpty()) {
|
if (!heardFrom.isEmpty()) {
|
||||||
announce(ih);
|
announce(ih, isSeed);
|
||||||
// announce to the closest we've heard from
|
// announce to the closest we've heard from
|
||||||
int annCnt = 0;
|
int annCnt = 0;
|
||||||
long start = _context.clock().now();
|
long start = _context.clock().now();
|
||||||
@ -458,9 +459,9 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
*
|
*
|
||||||
* @param ih the Info Hash (torrent)
|
* @param ih the Info Hash (torrent)
|
||||||
*/
|
*/
|
||||||
public void announce(byte[] ih) {
|
public void announce(byte[] ih, boolean isSeed) {
|
||||||
InfoHash iHash = new InfoHash(ih);
|
InfoHash iHash = new InfoHash(ih);
|
||||||
_tracker.announce(iHash, _myNodeInfo.getHash());
|
_tracker.announce(iHash, _myNodeInfo.getHash(), isSeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -470,9 +471,9 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
* @param ih the Info Hash (torrent)
|
* @param ih the Info Hash (torrent)
|
||||||
* @param peerHash the peer's Hash
|
* @param peerHash the peer's Hash
|
||||||
*/
|
*/
|
||||||
public void announce(byte[] ih, byte[] peerHash) {
|
public void announce(byte[] ih, byte[] peerHash, boolean isSeed) {
|
||||||
InfoHash iHash = new InfoHash(ih);
|
InfoHash iHash = new InfoHash(ih);
|
||||||
_tracker.announce(iHash, new Hash(peerHash));
|
_tracker.announce(iHash, new Hash(peerHash), isSeed);
|
||||||
// Do NOT do this, corrupts the Hash cache and the Peer ID
|
// Do NOT do this, corrupts the Hash cache and the Peer ID
|
||||||
//_tracker.announce(iHash, Hash.create(peerHash));
|
//_tracker.announce(iHash, Hash.create(peerHash));
|
||||||
}
|
}
|
||||||
@ -508,7 +509,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
* @return the number of successful announces, not counting ourselves.
|
* @return the number of successful announces, not counting ourselves.
|
||||||
*/
|
*/
|
||||||
public int announce(byte[] ih, int max, long maxWait, boolean isSeed) {
|
public int announce(byte[] ih, int max, long maxWait, boolean isSeed) {
|
||||||
announce(ih);
|
announce(ih, isSeed);
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
long start = _context.clock().now();
|
long start = _context.clock().now();
|
||||||
InfoHash iHash = new InfoHash(ih);
|
InfoHash iHash = new InfoHash(ih);
|
||||||
@ -555,7 +556,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
return false;
|
return false;
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("No token for announce to " + nInfo + ", sending get_peers first");
|
_log.info("No token for announce to " + nInfo + ", sending get_peers first");
|
||||||
ReplyWaiter waiter = sendGetPeers(nInfo, iHash);
|
ReplyWaiter waiter = sendGetPeers(nInfo, iHash, false);
|
||||||
if (waiter == null)
|
if (waiter == null)
|
||||||
return false;
|
return false;
|
||||||
long start = _context.clock().now();
|
long start = _context.clock().now();
|
||||||
@ -728,15 +729,18 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
* Blocking if we have to look up the dest for the nodeinfo
|
* Blocking if we have to look up the dest for the nodeinfo
|
||||||
*
|
*
|
||||||
* @param nInfo who to send it to
|
* @param nInfo who to send it to
|
||||||
|
* @param noSeeds true if we do not want seeds in the result
|
||||||
* @return null on error
|
* @return null on error
|
||||||
*/
|
*/
|
||||||
private ReplyWaiter sendGetPeers(NodeInfo nInfo, InfoHash ih) {
|
private ReplyWaiter sendGetPeers(NodeInfo nInfo, InfoHash ih, boolean noSeeds) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Sending get peers of " + ih + " to: " + nInfo);
|
_log.info("Sending get peers of " + ih + " to: " + nInfo + " noseeds? " + noSeeds);
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
map.put("q", "get_peers");
|
map.put("q", "get_peers");
|
||||||
Map<String, Object> args = new HashMap<String, Object>();
|
Map<String, Object> args = new HashMap<String, Object>();
|
||||||
args.put("info_hash", ih.getData());
|
args.put("info_hash", ih.getData());
|
||||||
|
if (noSeeds)
|
||||||
|
args.put("noseed", Integer.valueOf(1));
|
||||||
map.put("a", args);
|
map.put("a", args);
|
||||||
ReplyWaiter rv = sendQuery(nInfo, map, true);
|
ReplyWaiter rv = sendQuery(nInfo, map, true);
|
||||||
// save the InfoHash so we can get it later
|
// save the InfoHash so we can get it later
|
||||||
@ -754,7 +758,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
*/
|
*/
|
||||||
private ReplyWaiter sendAnnouncePeer(NodeInfo nInfo, InfoHash ih, Token token, boolean isSeed) {
|
private ReplyWaiter sendAnnouncePeer(NodeInfo nInfo, InfoHash ih, Token token, boolean isSeed) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Sending announce of " + ih + " to: " + nInfo);
|
_log.info("Sending announce of " + ih + " to: " + nInfo + " seed? " + isSeed);
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
map.put("q", "announce_peer");
|
map.put("q", "announce_peer");
|
||||||
Map<String, Object> args = new HashMap<String, Object>();
|
Map<String, Object> args = new HashMap<String, Object>();
|
||||||
@ -1126,14 +1130,22 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
} else if (method.equals("get_peers")) {
|
} else if (method.equals("get_peers")) {
|
||||||
byte[] hash = args.get("info_hash").getBytes();
|
byte[] hash = args.get("info_hash").getBytes();
|
||||||
InfoHash ih = new InfoHash(hash);
|
InfoHash ih = new InfoHash(hash);
|
||||||
receiveGetPeers(msgID, nInfo, ih);
|
boolean noSeeds = false;
|
||||||
|
BEValue nos = args.get("noseed");
|
||||||
|
if (nos != null)
|
||||||
|
noSeeds = nos.getInt() == 1;
|
||||||
|
receiveGetPeers(msgID, nInfo, ih, noSeeds);
|
||||||
} else if (method.equals("announce_peer")) {
|
} else if (method.equals("announce_peer")) {
|
||||||
byte[] hash = args.get("info_hash").getBytes();
|
byte[] hash = args.get("info_hash").getBytes();
|
||||||
InfoHash ih = new InfoHash(hash);
|
InfoHash ih = new InfoHash(hash);
|
||||||
// this is the "TCP" port, we don't care
|
// this is the "TCP" port, we don't care
|
||||||
//int port = args.get("port").getInt();
|
//int port = args.get("port").getInt();
|
||||||
byte[] token = args.get("token").getBytes();
|
byte[] token = args.get("token").getBytes();
|
||||||
receiveAnnouncePeer(msgID, ih, token);
|
boolean isSeed = false;
|
||||||
|
BEValue iss = args.get("seed");
|
||||||
|
if (iss != null)
|
||||||
|
isSeed = iss.getInt() == 1;
|
||||||
|
receiveAnnouncePeer(msgID, ih, token, isSeed);
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Unknown query method rcvd: " + method);
|
_log.warn("Unknown query method rcvd: " + method);
|
||||||
@ -1246,16 +1258,17 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
/**
|
/**
|
||||||
* Handle and respond to the query
|
* Handle and respond to the query
|
||||||
*/
|
*/
|
||||||
private void receiveGetPeers(MsgID msgID, NodeInfo nInfo, InfoHash ih) throws InvalidBEncodingException {
|
private void receiveGetPeers(MsgID msgID, NodeInfo nInfo,
|
||||||
|
InfoHash ih, boolean noSeeds) throws InvalidBEncodingException {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Rcvd get_peers from: " + nInfo + " for: " + ih);
|
_log.info("Rcvd get_peers from: " + nInfo + " for: " + ih + " noseeds? " + noSeeds);
|
||||||
// generate and save random token
|
// generate and save random token
|
||||||
Token token = new Token(_context);
|
Token token = new Token(_context);
|
||||||
_outgoingTokens.put(token, nInfo);
|
_outgoingTokens.put(token, nInfo);
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Stored new OB token: " + token + " for: " + nInfo);
|
_log.info("Stored new OB token: " + token + " for: " + nInfo);
|
||||||
|
|
||||||
List<Hash> peers = _tracker.getPeers(ih, MAX_WANT);
|
List<Hash> peers = _tracker.getPeers(ih, MAX_WANT, noSeeds);
|
||||||
// Check this before removing him, so we don't needlessly send nodes
|
// Check this before removing him, so we don't needlessly send nodes
|
||||||
// if he's the only one on the torrent.
|
// if he's the only one on the torrent.
|
||||||
boolean noPeers = peers.isEmpty();
|
boolean noPeers = peers.isEmpty();
|
||||||
@ -1290,7 +1303,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
* We have no node info here, it came on response port, we have to get it from the token.
|
* We have no node info here, it came on response port, we have to get it from the token.
|
||||||
* So we can't verify that it came from the same peer, as BEP 5 specifies.
|
* So we can't verify that it came from the same peer, as BEP 5 specifies.
|
||||||
*/
|
*/
|
||||||
private void receiveAnnouncePeer(MsgID msgID, InfoHash ih, byte[] tok) throws InvalidBEncodingException {
|
private void receiveAnnouncePeer(MsgID msgID, InfoHash ih,
|
||||||
|
byte[] tok, boolean isSeed) throws InvalidBEncodingException {
|
||||||
Token token = new Token(tok);
|
Token token = new Token(tok);
|
||||||
NodeInfo nInfo = _outgoingTokens.get(token);
|
NodeInfo nInfo = _outgoingTokens.get(token);
|
||||||
if (nInfo == null) {
|
if (nInfo == null) {
|
||||||
@ -1301,9 +1315,9 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Rcvd announce from: " + nInfo + " for: " + ih);
|
_log.info("Rcvd announce from: " + nInfo + " for: " + ih + " seed? " + isSeed);
|
||||||
|
|
||||||
_tracker.announce(ih, nInfo.getHash());
|
_tracker.announce(ih, nInfo.getHash(), isSeed);
|
||||||
// the reply for an announce is the same as the reply for a ping
|
// the reply for an announce is the same as the reply for a ping
|
||||||
sendPong(nInfo, msgID);
|
sendPong(nInfo, msgID);
|
||||||
}
|
}
|
||||||
@ -1362,7 +1376,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
|||||||
* @throws NPE, IllegalArgumentException, and others too
|
* @throws NPE, IllegalArgumentException, and others too
|
||||||
*/
|
*/
|
||||||
private List<NodeInfo> receiveNodes(NodeInfo nInfo, byte[] ids) throws InvalidBEncodingException {
|
private List<NodeInfo> receiveNodes(NodeInfo nInfo, byte[] ids) throws InvalidBEncodingException {
|
||||||
int max = Math.min(K, ids.length / NodeInfo.LENGTH);
|
// Azureus sends 20
|
||||||
|
int max = Math.min(3 * K, ids.length / NodeInfo.LENGTH);
|
||||||
List<NodeInfo> rv = new ArrayList<NodeInfo>(max);
|
List<NodeInfo> rv = new ArrayList<NodeInfo>(max);
|
||||||
for (int off = 0; off < ids.length && rv.size() < max; off += NodeInfo.LENGTH) {
|
for (int off = 0; off < ids.length && rv.size() < max; off += NodeInfo.LENGTH) {
|
||||||
NodeInfo nInf = new NodeInfo(ids, off);
|
NodeInfo nInf = new NodeInfo(ids, off);
|
||||||
|
@ -14,7 +14,9 @@ import net.i2p.data.Hash;
|
|||||||
*/
|
*/
|
||||||
class Peer extends Hash {
|
class Peer extends Hash {
|
||||||
|
|
||||||
private long lastSeen;
|
private volatile long lastSeen;
|
||||||
|
// todo we could pack this into the upper bit of lastSeen
|
||||||
|
private volatile boolean isSeed;
|
||||||
|
|
||||||
public Peer(byte[] data) {
|
public Peer(byte[] data) {
|
||||||
super(data);
|
super(data);
|
||||||
@ -27,4 +29,14 @@ class Peer extends Hash {
|
|||||||
public void setLastSeen(long now) {
|
public void setLastSeen(long now) {
|
||||||
lastSeen = now;
|
lastSeen = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.9.14 */
|
||||||
|
public boolean isSeed() {
|
||||||
|
return isSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 0.9.14 */
|
||||||
|
public void setSeed(boolean isSeed) {
|
||||||
|
this.isSeed = isSeed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
2014-06-01 zzz
|
||||||
|
* i2psnark:
|
||||||
|
- Store seed/leech status in DHT tracker (ticket #1280)
|
||||||
|
- Increase max received DHT nodes (Vuze sends more)
|
||||||
|
|
||||||
2014-05-31 zzz
|
2014-05-31 zzz
|
||||||
Prop from i2p.i2p.zzz.test2:
|
Prop from i2p.i2p.zzz.test2:
|
||||||
* Console: Fix shutdown error on old wrappers (ticket #1285)
|
* Console: Fix shutdown error on old wrappers (ticket #1285)
|
||||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 2;
|
public final static long BUILD = 3;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
Reference in New Issue
Block a user