public class KRPC extends Object implements I2PSessionMuxedListener, DHT
This class implements the DHT node communication protocol used for decentralized peer discovery in BitTorrent networks. It handles:
- The UDP port need not be pinged after receiving a PORT message. - The UDP (datagram) port listed in the compact node info is used to receive repliable (signed) datagrams. This is used for queries, except for announces. We call this the "query port". In addition to that UDP port, we use a second datagram port equal to the signed port + 1. This is used to receive unsigned (raw) datagrams for replies, errors, and announce queries. We call this the "response port". - Compact peer info is 32 bytes (32 byte SHA256 Hash) instead of 4 byte IP + 2 byte port. There is no peer port. - Compact node info is 54 bytes (20 byte SHA1 Hash + 32 byte SHA256 Hash + 2 byte port) instead of 20 byte SHA1 Hash + 4 byte IP + 2 byte port. Port is the query port, the response port is always the query port + 1. - The trackerless torrent dictionary "nodes" key is a list of 32 byte binary strings (SHA256 Hashes) instead of a list of lists containing a host string and a port integer.
This implementation uses I2P's datagram infrastructure for secure, anonymous DHT operations within the I2P network.
| Modifier and Type | Class and Description |
|---|---|
protected class | KRPC.ReplyWaiterCallback for replies |
| Modifier and Type | Field and Description |
|---|---|
protected boolean | _isRunning |
protected int | _qPortSigned datagrams. |
protected int | _rPortUnsigned datagrams. |
protected I2PSession | _sessionHook to inject and receive datagrams. |
static String | DHT_FILE_SUFFIXFile suffix for DHT persistent storage. |
static NID | FAKE_NIDAll-zero NID used for pings. |
static boolean | SECURE_NIDWhen true, generated NIDs must satisfy a cryptographic puzzle. |
| Modifier | Constructor and Description |
|---|---|
| KRPC(I2PAppContext ctx,
String baseName,
I2PSession session)Create the DHT instance. |
protected | KRPC(I2PAppContext ctx,
String baseName,
I2PSession session,
KRPC shared)Create the DHT instance sharing state. |
| Modifier and Type | Method and Description |
|---|---|
void | addServedTorrent(InfoHash ih)Serve tracker queries for the given infohash in addition to any already
served. |
void | announce(byte[] ih,
boolean isSeed)Announce to ourselves. |
void | announce(byte[] ih,
byte[] peerHash,
boolean isSeed)Announce somebody else we know about to ourselves. |
int | announce(byte[] ih,
int max,
long maxWait,
boolean isSeed)Not recommended - use getPeersAndAnnounce(). |
void | clear()Clears the tracker and DHT data. |
void | disconnected(I2PSession session)Handle a session disconnect. |
void | errorOccurred(I2PSession session,
String message,
Throwable error)Handle a session error. |
List<NodeInfo> | findClosest(byte[] ih,
int max)Local lookup only |
Collection<Hash> | getPeersAndAnnounce(byte[] ih,
int max,
long maxWait,
int annMax,
long annMaxWait,
boolean isSeed,
boolean noSeeds)Find peers for a torrent, announcing to the closest annMax nodes found. |
int | getPort()The UDP query port. |
int | getRPort()The UDP response port. |
(package private) NodeInfo | heardAbout(NodeInfo nInfo)Called for bootstrap or for all nodes in a receiveNodes reply. |
void | messageAvailable(I2PSession session,
int msgId,
long size)For non-muxed. |
void | messageAvailable(I2PSession session,
int msgId,
long size,
int proto,
int fromPort,
int toPort)Instruct the client that the given session has received a message |
void | ping(Destination dest,
int port)Ping. |
(package private) static List<NodeInfo> | removeSelf(List<NodeInfo> nodes,
NodeInfo self)Remove any entries equal to ourselves from a list of candidate nodes. |
void | removeServedTorrent(InfoHash ih)Stop serving tracker queries for the given infohash. |
String | renderStatusHTML()Debug info, HTML formatted. |
void | reportAbuse(I2PSession session,
int severity)Handle a reportAbuse message from the session. |
void | setServeAll(boolean serveAll)Whether tracker queries are served for every infohash. |
int | size()Known nodes, not estimated total network size. |
void | start()Start the DHT. |
void | stop()Stop everything. |
void | unannounce(byte[] ih)Remove reference to ourselves in the local tracker. |
protected volatile boolean _isRunning
protected int _qPort
protected int _rPort
protected I2PSession _session
public static final String DHT_FILE_SUFFIX
public static final NID FAKE_NID
public static final boolean SECURE_NID
public KRPC(I2PAppContext ctx, String baseName, I2PSession session)
baseName - generally "i2psnark"protected KRPC(I2PAppContext ctx, String baseName, I2PSession session, KRPC shared)
baseName - generally "i2psnark"shared - the KRPC instance whose routing table, tracker, and blacklist are shared with
this instance, or null for a standalone instance; a TorrentKRPC passes the main
instance and overrides start() and stop() to run only the message listenerpublic void addServedTorrent(InfoHash ih)
ih - the infohash to servepublic void announce(byte[] ih,
boolean isSeed)public void announce(byte[] ih,
byte[] peerHash,
boolean isSeed)public int announce(byte[] ih,
int max,
long maxWait,
boolean isSeed)Announce to the closest peers in the local DHT. This is NOT iterative - call getPeers() first to get the closest peers into the local DHT. Blocking unless maxWait <= 0 Caller should run in a thread. This also automatically announces ourself to our local tracker. For best results do a getPeersAndAnnounce() instead, as this announces to the closest in the kbuckets, it does NOT sort through the known nodes hashmap.
announce in interface DHTih - the Info Hash (torrent)max - maximum number of peers to announce tomaxWait - the maximum total time to wait (ms) or 0 to do all in parallel and returnisSeed - true if seed, false if leechpublic void clear()
public void disconnected(I2PSession session)
disconnected in interface I2PSessionListenerdisconnected in interface I2PSessionMuxedListenersession - the sessionpublic void errorOccurred(I2PSession session, String message, Throwable error)
errorOccurred in interface I2PSessionListenererrorOccurred in interface I2PSessionMuxedListenersession - the sessionmessage - the error messageerror - the errorpublic List<NodeInfo> findClosest(byte[] ih, int max)
ih - a 20-byte info hashmax - max to returnpublic Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait, int annMax, long annMaxWait, boolean isSeed, boolean noSeeds)
getPeersAndAnnounce in interface DHTih - the Info Hash (torrent)max - maximum number of peers to returnmaxWait - the maximum time to wait (ms) must be > 0annMax - the number of peers to announce toannMaxWait - the maximum total time to wait for announces, may be 0 to return
immediately without waiting for acksisSeed - true if seed, false if leechnoSeeds - true if we do not want seeds in the resultpublic int getPort()
public int getRPort()
NodeInfo heardAbout(NodeInfo nInfo)
public void messageAvailable(I2PSession session, int msgId, long size)
messageAvailable in interface I2PSessionListenermessageAvailable in interface I2PSessionMuxedListenersession - session to notifymsgId - message number availablesize - size of the message - why it's a long and not an int is a mysterypublic void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromPort, int toPort)
Will be called only if you register via addMuxedSessionListener(). Will be called only for the proto(s) and toPort(s) you register for.
messageAvailable in interface I2PSessionMuxedListenersession - session to notifymsgId - message number availablesize - size of the message - why it's a long and not an int is a mysteryproto - 1-254 or 0 for unspecifiedfromPort - 1-65535 or 0 for unspecifiedtoPort - 1-65535 or 0 for unspecifiedpublic void ping(Destination dest, int port)
static List<NodeInfo> removeSelf(List<NodeInfo> nodes, NodeInfo self)
nodes - candidate nodes, not modifiedself - our own node infopublic void removeServedTorrent(InfoHash ih)
ih - the infohash to stop servingpublic String renderStatusHTML()
renderStatusHTML in interface DHTpublic void reportAbuse(I2PSession session, int severity)
reportAbuse in interface I2PSessionListenerreportAbuse in interface I2PSessionMuxedListenersession - the sessionseverity - the abuse severitypublic void setServeAll(boolean serveAll)
serveAll - true to serve every infohash, false to serve nonepublic int size()
public void start()
public void unannounce(byte[] ih)
unannounce in interface DHTih - the Info Hash (torrent)