org.klomp.snark.dht
Class KRPC

java.lang.Object
  extended by org.klomp.snark.dht.KRPC
All Implemented Interfaces:
I2PSessionListener, I2PSessionMuxedListener, DHT

public class KRPC
extends Object
implements I2PSessionMuxedListener, DHT

Standard BEP 5 Mods for I2P:

 - 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.
 
Questions: - nodes (in the find_node and get_peers response) is one concatenated string, not a list of strings, right? - Node ID enforcement, keyspace rotation?

Since:
0.9.2
Author:
zzz

Field Summary
static String DHT_FILE_SUFFIX
           
static NID FAKE_NID
          all-zero NID used for pings
static boolean SECURE_NID
           
 
Constructor Summary
KRPC(I2PAppContext ctx, String baseName, I2PSession session)
           
 
Method Summary
 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)
          Notify the client that the session has been terminated.
 void errorOccurred(I2PSession session, String message, Throwable error)
          Notify the client that some error occurred.
 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)
          Get peers for a torrent, and announce to the closest annMax nodes we find.
 int getPort()
           
 int getRPort()
           
(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 Will be called only if you register via addMuxedSessionListener().
 void ping(Destination dest, int port)
          Ping.
 String renderStatusHTML()
          Debug info, HTML formatted
 void reportAbuse(I2PSession session, int severity)
          Instruct the client that the session specified seems to be under attack and that the client may wish to move its destination to another router.
 int size()
          Known nodes, not estimated total network size.
 void start()
          Loads the DHT from file.
 void stop()
          Stop everything.
 void unannounce(byte[] ih)
          Remove reference to ourselves in the local tracker.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

FAKE_NID

public static final NID FAKE_NID
all-zero NID used for pings


SECURE_NID

public static final boolean SECURE_NID
See Also:
Constant Field Values

DHT_FILE_SUFFIX

public static final String DHT_FILE_SUFFIX
See Also:
Constant Field Values
Constructor Detail

KRPC

public KRPC(I2PAppContext ctx,
            String baseName,
            I2PSession session)
Parameters:
baseName - generally "i2psnark"
Method Detail

size

public int size()
Known nodes, not estimated total network size.

Specified by:
size in interface DHT

getPort

public int getPort()
Specified by:
getPort in interface DHT
Returns:
The UDP query port

getRPort

public int getRPort()
Specified by:
getRPort in interface DHT
Returns:
The UDP response port

ping

public void ping(Destination dest,
                 int port)
Ping. We don't have a NID yet so the node is presumed to be absent from our DHT. Non-blocking, does not wait for pong. If and when the pong is received the node will be inserted in our DHT.

Specified by:
ping in interface DHT

findClosest

public List<NodeInfo> findClosest(byte[] ih,
                                  int max)
Local lookup only

Parameters:
ih - a 20-byte info hash
max - max to return
Returns:
list or empty list (never null)

getPeersAndAnnounce

public Collection<Hash> getPeersAndAnnounce(byte[] ih,
                                            int max,
                                            long maxWait,
                                            int annMax,
                                            long annMaxWait,
                                            boolean isSeed,
                                            boolean noSeeds)
Get peers for a torrent, and announce to the closest annMax nodes we find. This is an iterative lookup in the DHT. Blocking! Caller should run in a thread.

Specified by:
getPeersAndAnnounce in interface DHT
Parameters:
ih - the Info Hash (torrent)
max - maximum number of peers to return
maxWait - the maximum time to wait (ms) must be > 0
annMax - the number of peers to announce to
annMaxWait - the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
isSeed - true if seed, false if leech
noSeeds - true if we do not want seeds in the result
Returns:
possibly empty (never null)

announce

public void announce(byte[] ih,
                     boolean isSeed)
Announce to ourselves. Non-blocking.

Specified by:
announce in interface DHT
Parameters:
ih - the Info Hash (torrent)

announce

public void announce(byte[] ih,
                     byte[] peerHash,
                     boolean isSeed)
Announce somebody else we know about to ourselves. Non-blocking.

Specified by:
announce in interface DHT
Parameters:
ih - the Info Hash (torrent)
peerHash - the peer's Hash

unannounce

public void unannounce(byte[] ih)
Remove reference to ourselves in the local tracker. Use when shutting down the torrent locally. Non-blocking.

Specified by:
unannounce in interface DHT
Parameters:
ih - the Info Hash (torrent)

announce

public int announce(byte[] ih,
                    int max,
                    long maxWait,
                    boolean isSeed)
Not recommended - use getPeersAndAnnounce(). 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.

Specified by:
announce in interface DHT
Parameters:
ih - the Info Hash (torrent)
max - maximum number of peers to announce to
maxWait - the maximum total time to wait (ms) or 0 to do all in parallel and return immediately.
isSeed - true if seed, false if leech
Returns:
the number of successful announces, not counting ourselves.

start

public void start()
Loads the DHT from file. Can't be restarted after stopping?


stop

public void stop()
Stop everything.

Specified by:
stop in interface DHT

clear

public void clear()
Clears the tracker and DHT data. Call after saving DHT data to disk.


renderStatusHTML

public String renderStatusHTML()
Debug info, HTML formatted

Specified by:
renderStatusHTML in interface DHT

heardAbout

NodeInfo heardAbout(NodeInfo nInfo)
Called for bootstrap or for all nodes in a receiveNodes reply. Package private for PersistDHT.

Returns:
non-null nodeInfo from DB if present, otherwise the nInfo parameter is returned

messageAvailable

public 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 Will be called only if you register via addMuxedSessionListener(). Will be called only for the proto(s) and toPort(s) you register for.

Specified by:
messageAvailable in interface I2PSessionMuxedListener
Parameters:
session - session to notify
msgId - message number available
size - size of the message - why it's a long and not an int is a mystery
proto - 1-254 or 0 for unspecified
fromPort - 1-65535 or 0 for unspecified
toPort - 1-65535 or 0 for unspecified

messageAvailable

public void messageAvailable(I2PSession session,
                             int msgId,
                             long size)
for non-muxed

Specified by:
messageAvailable in interface I2PSessionListener
Specified by:
messageAvailable in interface I2PSessionMuxedListener
Parameters:
session - session to notify
msgId - message number available
size - size of the message - why it's a long and not an int is a mystery

reportAbuse

public void reportAbuse(I2PSession session,
                        int severity)
Description copied from interface: I2PSessionMuxedListener
Instruct the client that the session specified seems to be under attack and that the client may wish to move its destination to another router. All registered listeners will be called. Unused. Not fully implemented.

Specified by:
reportAbuse in interface I2PSessionListener
Specified by:
reportAbuse in interface I2PSessionMuxedListener
Parameters:
session - session to report abuse to
severity - how bad the abuse is

disconnected

public void disconnected(I2PSession session)
Description copied from interface: I2PSessionMuxedListener
Notify the client that the session has been terminated. All registered listeners will be called.

Specified by:
disconnected in interface I2PSessionListener
Specified by:
disconnected in interface I2PSessionMuxedListener

errorOccurred

public void errorOccurred(I2PSession session,
                          String message,
                          Throwable error)
Description copied from interface: I2PSessionMuxedListener
Notify the client that some error occurred. All registered listeners will be called.

Specified by:
errorOccurred in interface I2PSessionListener
Specified by:
errorOccurred in interface I2PSessionMuxedListener
error - can be null? or not?