java.lang.Object
org.klomp.snark.UDPTrackerClient
All Implemented Interfaces:
I2PSessionListener, I2PSessionMuxedListener

class UDPTrackerClientextends Object implements I2PSessionMuxedListener
One of these for all trackers and info hashes. Ref: BEP 15, proposal 160.

The main difference from BEP 15 is that the announce response contains a 32-byte hash instead of a 4-byte IP and a 2-byte port.

We send both repliable and raw datagrams, but we only receive raw datagrams, as follows:

   client      tracker          type
   ----------+----------------+--------------------
   conn req  | -->            | repliable Datagram2
             | <-- conn resp  | raw
   announce  | -->            | repliable Datagram3
             | <-- ann resp   | raw
             | <-- error      | raw
   ----------+-----------------+-------------------
  • Field Details

    • _context

      private final I2PAppContext _context
      The app context.
    • _log

      private final Log _log
      Logger for UDP tracker traffic.
    • _session

      private final I2PSession _session
      Hook to inject and receive datagrams.
    • _util

      private final I2PSnarkUtil _util
      The webapp's configuration helper.
    • _myHash

      private final Hash _myHash
      Hash of this client's destination.
    • _rPort

      private final int _rPort
      Unsigned datagrams.
    • _trackers

      Dest and port to tracker data.
    • _sentQueries

      private final Map<Integer, UDPTrackerClient.ReplyWaiter> _sentQueries
      Our TID to tracker.
    • _isRunning

      private boolean _isRunning
      True while the client thread is running.
    • INIT_CONN_ID

      private static final long INIT_CONN_ID
      Initial connection id sent in the connect request.
      See Also:
    • EVENT_NONE

      public static final int EVENT_NONE
      No event (periodic announce).
      See Also:
    • EVENT_COMPLETED

      public static final int EVENT_COMPLETED
      Torrent download completed.
      See Also:
    • EVENT_STARTED

      public static final int EVENT_STARTED
      Torrent download started.
      See Also:
    • EVENT_STOPPED

      public static final int EVENT_STOPPED
      Torrent stopped.
      See Also:
    • EVENT_PAUSED

      public static final int EVENT_PAUSED
      Partial seed (BEP 21), HTTP only; not defined in the UDP protocol.
      See Also:
    • ACTION_CONNECT

      private static final int ACTION_CONNECT
      Action value for a connection request.
      See Also:
    • ACTION_ANNOUNCE

      private static final int ACTION_ANNOUNCE
      Action value for an announce request.
      See Also:
    • ACTION_SCRAPE

      private static final int ACTION_SCRAPE
      Action value for a scrape request.
      See Also:
    • ACTION_ERROR

      private static final int ACTION_ERROR
      Action value marking an error reply.
      See Also:
    • CONN_EXPIRATION

      private static final long CONN_EXPIRATION
      How long a connection ID stays valid, in milliseconds (BEP 15 connection lifetime).
      See Also:
    • DEFAULT_TIMEOUT

      private static final long DEFAULT_TIMEOUT
      Query timeout before any backoff, in milliseconds.
      See Also:
    • DEFAULT_INTERVAL

      private static final int DEFAULT_INTERVAL
      Announce interval used until a tracker reports one, in seconds.
      See Also:
    • MIN_INTERVAL

      private static final int MIN_INTERVAL
      Shortest announce interval accepted from a tracker, in seconds.
      See Also:
    • MAX_INTERVAL

      private static final int MAX_INTERVAL
      Longest announce interval accepted from a tracker, in seconds.
      See Also:
  • Constructor Details

    • UDPTrackerClient

      public UDPTrackerClient(I2PAppContext ctx, I2PSession session, I2PSnarkUtil util)
      Create a client bound to one torrent's session, listening on the port just below TrackerClient.PORT so it never collides with the HTTP tracker client.
      Parameters:
      ctx - the application context supplying the log and timer services
      session - the torrent's session, used to send datagrams and to derive our own hash
      util - the utility instance supplying the enabled-tracker configuration
  • Method Details

    • start

      public void start()
      Can't be restarted after stopping?
    • stop

      public void stop()
      Stop everything.
    • announce

      public UDPTrackerClient.TrackerResponse announce(byte[] ih, byte[] peerID, int max, long maxWait, String toHost, int toPort, long downloaded, long left, long uploaded, int event, boolean fast)
      Announce and get peers for a torrent. Blocking! Caller should run in a thread.
      Parameters:
      ih - the Info Hash (torrent)
      peerID - the peer ID this client announces itself under
      max - maximum number of peers to return
      maxWait - the maximum time to wait (ms) must be > 0
      toHost - the tracker hostname
      toPort - the tracker port
      downloaded - bytes downloaded so far for this torrent
      left - bytes still to download for this torrent
      uploaded - bytes uploaded so far for this torrent
      event - one of the EVENT_* codes describing why this announce is being made
      fast - if true, don't wait for dest, no retx, ...
      Returns:
      null on fail or if fast is true
    • scrape

      public UDPTrackerClient.TrackerResponse scrape(byte[] ih, long maxWait, String toHost, int toPort)
      Scrape for swarm composition for a torrent. Blocking! Caller should run in a thread.

      BEP 15 scrape request, single info hash.

      Parameters:
      ih - the Info Hash (torrent)
      maxWait - the maximum time to wait (ms) must be > 0
      toHost - the tracker hostname
      toPort - the tracker port
      Returns:
      the response, or null on fail or timeout
    • getConnection

      private Long getConnection(UDPTrackerClient.Tracker tr, long untilTime)
      Establish a connection to the tracker.
      Parameters:
      tr - the tracker to connect to
      untilTime - the deadline time in milliseconds
      Returns:
      the connection ID, or null on fail
    • getTracker

      private UDPTrackerClient.Tracker getTracker(String host, int port)
      Create or find a tracker entry.
      Parameters:
      host - the tracker hostname
      port - the tracker port
      Returns:
      non-null tracker entry
    • sendConnReq

      private UDPTrackerClient.ReplyWaiter sendConnReq(UDPTrackerClient.Tracker tr, long toWait)
      Send one time with a new tid.
      Parameters:
      tr - the tracker to send the connect request to
      toWait - how long to wait for the reply, in ms, greater than zero
      Returns:
      the waiter to poll for the reply, or null if the request could not be sent
      Throws:
      IllegalArgumentException - if toWait is zero or negative
    • sendConnReq

      private byte[] sendConnReq(UDPTrackerClient.Tracker tr, int tid)
      Send one time with given tid.
      Parameters:
      tr - the tracker to send the connect request to
      tid - the transaction ID to send, and to match the reply against
      Returns:
      the payload or null on failure
    • sendAnnounce

      private UDPTrackerClient.ReplyWaiter sendAnnounce(UDPTrackerClient.Tracker tr, long connID, byte[] ih, byte[] id, long downloaded, long left, long uploaded, int event, int numWant, long toWait)
      Send one time with a new tid.
      Parameters:
      tr - the tracker to announce to
      connID - the connection ID from the connect response
      ih - the 20-byte SHA-1 info hash of the torrent
      id - the 20-byte peer ID to advertise
      downloaded - bytes downloaded so far for this torrent
      left - bytes still to download for this torrent
      uploaded - bytes uploaded so far for this torrent
      event - one of the EVENT_* codes describing why this announce is made
      numWant - maximum number of peers to return
      toWait - how long to wait for the reply, in ms, 0 or less to skip registering a waiter
      Returns:
      null on failure or if toWait <= 0
    • sendAnnounce

      private byte[] sendAnnounce(UDPTrackerClient.Tracker tr, int tid, long connID, byte[] ih, byte[] id, long downloaded, long left, long uploaded, int event, int numWant)
      Send one time with given tid.
      Parameters:
      tr - the tracker to announce to
      tid - the transaction ID to send, and to match the reply against
      connID - the connection ID from the connect response
      ih - the 20-byte SHA-1 info hash of the torrent
      id - the 20-byte peer ID to advertise
      downloaded - bytes downloaded so far for this torrent
      left - bytes still to download for this torrent
      uploaded - bytes uploaded so far for this torrent
      event - one of the EVENT_* codes describing why this announce is made
      numWant - maximum number of peers to return
      Returns:
      the payload or null on failure
    • sendScrape

      private UDPTrackerClient.ReplyWaiter sendScrape(UDPTrackerClient.Tracker tr, long connID, byte[] ih, long toWait)
      Send one time with a new tid.
      Parameters:
      tr - the tracker to scrape from
      connID - the connection ID from the connect response
      ih - the 20-byte SHA-1 info hash to scrape
      toWait - if <= 0 does not register
      Returns:
      null on failure or if toWait <= 0
    • sendScrape

      private byte[] sendScrape(UDPTrackerClient.Tracker tr, int tid, long connID, byte[] ih)
      Send one time with given tid.
      Parameters:
      tr - the tracker to scrape from
      tid - the transaction ID to send, and to match the reply against
      connID - the connection ID from the connect response
      ih - the 20-byte SHA-1 info hash to scrape
      Returns:
      the payload or null on failure
    • waitAndRetransmit

      private boolean waitAndRetransmit(UDPTrackerClient.ReplyWaiter w, long untilTime)
      Wait after initial send, resend if necessary.
      Parameters:
      w - the outstanding query to wait for a reply on, locked throughout
      untilTime - deadline in ms since epoch to keep retransmitting until
      Returns:
      true if a valid reply was received, false on timeout or resend failure
    • resend

      private boolean resend(UDPTrackerClient.ReplyWaiter w, long toWait)
      Resend the stored payload.
      Parameters:
      w - the outstanding query whose stored payload is sent again
      toWait - the retransmit timeout in ms, used only for logging
      Returns:
      true if the datagram was handed to the session for sending
    • sendMessage

      private boolean sendMessage(Destination dest, int toPort, byte[] payload, boolean repliable)
      Lowest-level send message call.
      Parameters:
      dest - may be null, returns false
      toPort - the tracker's UDP port to send the datagram to
      payload - the BEP 15 request bytes, wrapped before sending
      repliable - true to wrap in a repliable Datagram2, false for a raw Datagram3 that does not carry our lease set
      Returns:
      true if the session accepted the datagram; false when not running, when the payload cannot be wrapped in a Datagram2 or Datagram3, or when the send is rejected
    • receiveMessage

      private void receiveMessage(Destination from, int fromPort, byte[] payload)
      Receive a message.
      Parameters:
      from - dest or null if it didn't come in on signed port
      fromPort - the local port the datagram arrived on, unused
      payload - the raw tracker response, ignored if shorter than 8 bytes
    • receiveConnection

      private void receiveConnection(UDPTrackerClient.ReplyWaiter waiter, byte[] payload)
      Receive a connection reply.
      Parameters:
      waiter - the outstanding request this reply answers
      payload - the connect response: 8-byte action and tid header, an 8-byte connection ID at offset 8, and an optional 2-byte lifetime in seconds at offset 16
    • receiveAnnounce

      private void receiveAnnounce(UDPTrackerClient.ReplyWaiter waiter, byte[] payload)
      Parses an announce reply and hands it to the waiter.
      Parameters:
      waiter - the request the reply answers
      payload - the reply body
    • receiveScrape

      private void receiveScrape(UDPTrackerClient.ReplyWaiter waiter, byte[] payload)
      Parse a BEP 15 scrape response, single info hash: seeders, completed, leechers.
      Parameters:
      waiter - the waiter for the scrape request
      payload - the raw response
    • receiveError

      private void receiveError(UDPTrackerClient.ReplyWaiter waiter, byte[] payload, int expected)
      Parses an error reply and fails the waiter.
      Parameters:
      waiter - the request the reply answers
      payload - the reply body
      expected - the action the reply should have carried
    • 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 payload in bytes. The I2CP payload size is an int internally and is widened to long here, so the value is never negative
    • reportAbuse

      public void reportAbuse(I2PSession session, int severity)
      Handle a reportAbuse message from the session.
      Specified by:
      reportAbuse in interface I2PSessionListener
      Specified by:
      reportAbuse in interface I2PSessionMuxedListener
      Parameters:
      session - the session that reported the abuse
      severity - the abuse severity
    • disconnected

      public void disconnected(I2PSession session)
      Handle a session disconnect.
      Specified by:
      disconnected in interface I2PSessionListener
      Specified by:
      disconnected in interface I2PSessionMuxedListener
      Parameters:
      session - the session that dropped
    • errorOccurred

      public void errorOccurred(I2PSession session, String message, Throwable error)
      Handle a session error.
      Specified by:
      errorOccurred in interface I2PSessionListener
      Specified by:
      errorOccurred in interface I2PSessionMuxedListener
      Parameters:
      session - the session that reported the error
      message - the error message
      error - the cause of the error, non-null