net.i2p.router.transport.udp

## Class PeerTestManager

- java.lang.Object
- - net.i2p.router.transport.udp.PeerTestManager

-     class PeerTestManager
      extends Object

  Entry points are runTest() to start a new test as Alice, and receiveTest() for all received test packets. IPv6 info: All Alice-Bob and Alice-Charlie communication is via IPv4. The Bob-Charlie communication may be via IPv6, however Charlie must be IPv4-capable. The IP address (of Alice) in the message must be IPv4 if present, as we only support testing of IPv4. Testing of IPv6 could be added in the future. From udp.html on the website:

  The automation of collaborative reachability testing for peers is enabled by a sequence of PeerTest messages. With its proper execution, a peer will be able to determine their own reachability and may update its behavior accordingly. The testing process is quite simple:

              Alice                  Bob                  Charlie

          runTest()
          sendTestToBob()     receiveFromAliceAsBob()
          PeerTest ------------------->

                              sendTestToCharlie()       receiveFromBobAsCharlie()
                                   PeerTest-------------------->

                              receiveFromCharlieAsBob()
                                      <-------------------PeerTest

          receiveTestReply()
               <-------------------PeerTest

          receiveTestReply()
               <------------------------------------------PeerTest

                                                        receiveFromAliceAsCharlie()
          PeerTest------------------------------------------>

          receiveTestReply()
               <------------------------------------------PeerTest

  Each of the PeerTest messages carry a nonce identifying the test series itself, as initialized by Alice. If Alice doesn't get a particular message that she expects, she will retransmit accordingly, and based upon the data received or the messages missing, she will know her reachability. The various end states that may be reached are as follows:

  - If she doesn't receive a response from Bob, she will retransmit up to a certain number of times, but if no response ever arrives, she will know that her firewall or NAT is somehow misconfigured, rejecting all inbound UDP packets even in direct response to an outbound packet. Alternately, Bob may be down or unable to get Charlie to reply.
  - If Alice doesn't receive a PeerTest message with the expected nonce from a third party (Charlie), she will retransmit her initial request to Bob up to a certain number of times, even if she has received Bob's reply already. If Charlie's first message still doesn't get through but Bob's does, she knows that she is behind a NAT or firewall that is rejecting unsolicited connection attempts and that port forwarding is not operating properly (the IP and port that Bob offered up should be forwarded).
  - If Alice receives Bob's PeerTest message and both of Charlie's PeerTest messages but the enclosed IP and port numbers in Bob's and Charlie's second messages don't match, she knows that she is behind a symmetric NAT, rewriting all of her outbound packets with different 'from' ports for each peer contacted. She will need to explicitly forward a port and always have that port exposed for remote connectivity, ignoring further port discovery.
  - If Alice receives Charlie's first message but not his second, she will retransmit her PeerTest message to Charlie up to a certain number of times, but if no response is received she knows that Charlie is either confused or no longer online.

  Alice should choose Bob arbitrarily from known peers who seem to be capable of participating in peer tests. Bob in turn should choose Charlie arbitrarily from peers that he knows who seem to be capable of participating in peer tests and who are on a different IP from both Bob and Alice. If the first error condition occurs (Alice doesn't get PeerTest messages from Bob), Alice may decide to designate a new peer as Bob and try again with a different nonce.

  Alice's introduction key is included in all of the PeerTest messages so that she doesn't need to already have an established session with Bob and so that Charlie can contact her without knowing any additional information. Alice may go on to establish a session with either Bob or Charlie, but it is not required.

- - ### Constructor Summary

    Constructors
    Constructor and Description
    `PeerTestManager(RouterContext context, UDPTransport transport)` Have seen peer tests (as Alice) get stuck (_currentTest != null) so I've thrown some synchronizization on the methods; don't know the root cause or whether this fixes it

  - ### Method Summary

    All Methods Static Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `(package private) static RouterAddress` | `getAddress(List<RouterAddress> addrs, boolean isIPv6)` Get an address out of a list of addresses.
    `(package private) static SessionKey` | `getIntroKey(RouterAddress ra)` Get an intro key out of an address.
    `void` | `receiveTest(RemoteHostId from, PeerState2 fromPeer, int msg, int status, Hash h, byte[] data)` Entry point for all in-session incoming packets.
    `void` | `receiveTest(RemoteHostId from, UDPPacket packet)` Entry point for all out-of-session packets, messages 5-7 only.
    `boolean` | `runTest(PeerState bob)` The next few methods are for when we are Alice

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### PeerTestManager

          public PeerTestManager(RouterContext context,
                                 UDPTransport transport)

      Have seen peer tests (as Alice) get stuck (_currentTest != null) so I've thrown some synchronizization on the methods; don't know the root cause or whether this fixes it

  - ### Method Detail

    - #### getAddress

          static RouterAddress getAddress(List<RouterAddress> addrs,
                                          boolean isIPv6)

      Get an address out of a list of addresses. SSU2 only.
      Returns:
        address or null

    - #### getIntroKey

          static SessionKey getIntroKey(RouterAddress ra)

      Get an intro key out of an address. SSU2 only.

    - #### receiveTest

          public void receiveTest(RemoteHostId from,
                                  PeerState2 fromPeer,
                                  int msg,
                                  int status,
                                  Hash h,
                                  byte[] data)

      Entry point for all in-session incoming packets. SSU 2 only. Receive a test message of some sort from the given peer, queueing up any packet that should be sent in response, or if its a reply to our own current testing, adjusting our test state. We could be Alice, Bob, or Charlie.
      Parameters:
        `from` - non-null
        `fromPeer` - non-null if an associated session was found, otherwise null
        `msg` - 1-7
        `status` - 0 = accept, 1-255 = reject
        `h` - Alice or Charlie hash for msg 2 and 4, null for msg 1, 3, 5-7
        `data` - excludes flag, includes signature

    - #### receiveTest

          public void receiveTest(RemoteHostId from,
                                  UDPPacket packet)

      Entry point for all out-of-session packets, messages 5-7 only. SSU 2 only. Receive a test message of some sort from the given peer, queueing up any packet that should be sent in response, or if its a reply to our own current testing, adjusting our test state. We could be Alice or Charlie.
      Parameters:
        `from` - non-null
        `packet` - header already decrypted

    - #### runTest

          public boolean runTest(PeerState bob)

      The next few methods are for when we are Alice
      Parameters:
        `bob` - IPv4 only
      Returns:
        true if we successfully started a test