Changeset 1c25c0f


Ignore:
Timestamp:
Nov 14, 2009 3:00:28 PM (11 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
c393e70
Parents:
b7ebce4
Message:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • router/java/src/net/i2p/router/transport/udp/PeerTestManager.java

    rb7ebce4 r1c25c0f  
    2020
    2121/**
    22  *
     22 *  From udp.html on the website:
     23
     24<p>The automation of collaborative reachability testing for peers is
     25enabled by a sequence of PeerTest messages.  With its proper
     26execution, a peer will be able to determine their own reachability
     27and may update its behavior accordingly.  The testing process is
     28quite simple:</p>
     29
     30<pre>
     31        Alice                  Bob                  Charlie
     32    PeerTest -------------------&gt;
     33                             PeerTest--------------------&gt;
     34                                &lt;-------------------PeerTest
     35         &lt;-------------------PeerTest
     36         &lt;------------------------------------------PeerTest
     37    PeerTest------------------------------------------&gt;
     38         &lt;------------------------------------------PeerTest
     39</pre>
     40
     41<p>Each of the PeerTest messages carry a nonce identifying the
     42test series itself, as initialized by Alice.  If Alice doesn't
     43get a particular message that she expects, she will retransmit
     44accordingly, and based upon the data received or the messages
     45missing, she will know her reachability.  The various end states
     46that may be reached are as follows:</p>
     47
     48<ul>
     49<li>If she doesn't receive a response from Bob, she will retransmit
     50up to a certain number of times, but if no response ever arrives,
     51she will know that her firewall or NAT is somehow misconfigured,
     52rejecting all inbound UDP packets even in direct response to an
     53outbound packet.  Alternately, Bob may be down or unable to get
     54Charlie to reply.</li>
     55
     56<li>If Alice doesn't receive a PeerTest message with the
     57expected nonce from a third party (Charlie), she will retransmit
     58her initial request to Bob up to a certain number of times, even
     59if she has received Bob's reply already.  If Charlie's first message
     60still doesn't get through but Bob's does, she knows that she is
     61behind a NAT or firewall that is rejecting unsolicited connection
     62attempts and that port forwarding is not operating properly (the
     63IP and port that Bob offered up should be forwarded).</li>
     64
     65<li>If Alice receives Bob's PeerTest message and both of Charlie's
     66PeerTest messages but the enclosed IP and port numbers in Bob's
     67and Charlie's second messages don't match, she knows that she is
     68behind a symmetric NAT, rewriting all of her outbound packets with
     69different 'from' ports for each peer contacted.  She will need to
     70explicitly forward a port and always have that port exposed for
     71remote connectivity, ignoring further port discovery.</li>
     72
     73<li>If Alice receives Charlie's first message but not his second,
     74she will retransmit her PeerTest message to Charlie up to a
     75certain number of times, but if no response is received she knows
     76that Charlie is either confused or no longer online.</li>
     77</ul>
     78
     79<p>Alice should choose Bob arbitrarily from known peers who seem
     80to be capable of participating in peer tests.  Bob in turn should
     81choose Charlie arbitrarily from peers that he knows who seem to be
     82capable of participating in peer tests and who are on a different
     83IP from both Bob and Alice.  If the first error condition occurs
     84(Alice doesn't get PeerTest messages from Bob), Alice may decide
     85to designate a new peer as Bob and try again with a different nonce.</p>
     86
     87<p>Alice's introduction key is included in all of the PeerTest
     88messages so that she doesn't need to already have an established
     89session with Bob and so that Charlie can contact her without knowing
     90any additional information.  Alice may go on to establish a session
     91with either Bob or Charlie, but it is not required.</p>
     92
    2393 */
    2494class PeerTestManager {
     
    2797    private UDPTransport _transport;
    2898    private PacketBuilder _packetBuilder;
    29     /** map of Long(nonce) to PeerTestState for tests currently in progress */
    30     private final Map _activeTests;
    31     /** current test we are running, or null */
     99    /** map of Long(nonce) to PeerTestState for tests currently in progress (as Bob/Charlie) */
     100    private final Map<Long, PeerTestState> _activeTests;
     101    /** current test we are running (as Alice), or null */
    32102    private PeerTestState _currentTest;
    33103    private boolean _currentTestComplete;
    34     private List _recentTests;
     104    /** as Alice */
     105    private List<Long> _recentTests;
    35106   
    36107    /** longest we will keep track of a Charlie nonce for */
    37108    private static final int MAX_CHARLIE_LIFETIME = 10*1000;
    38109
     110    /**
     111     *  Have seen peer tests (as Alice) get stuck (_currentTest != null)
     112     *  so I've thrown some synchronizization on the methods;
     113     *  don't know the root cause or whether this fixes it
     114     */
    39115    public PeerTestManager(RouterContext context, UDPTransport transport) {
    40116        _context = context;
     
    55131    private static final long MAX_NONCE = (1l << 32) - 1l;
    56132    //public void runTest(InetAddress bobIP, int bobPort, SessionKey bobIntroKey) {
    57     public void runTest(InetAddress bobIP, int bobPort, SessionKey bobCipherKey, SessionKey bobMACKey) {
     133
     134    /**
     135     *  The next few methods are for when we are Alice
     136     */
     137    public synchronized void runTest(InetAddress bobIP, int bobPort, SessionKey bobCipherKey, SessionKey bobMACKey) {
    58138        if (_currentTest != null) {
    59139            if (_log.shouldLog(Log.WARN))
     
    86166    private class ContinueTest implements SimpleTimer.TimedEvent {
    87167        public void timeReached() {
    88             PeerTestState state = _currentTest;
    89             if (state == null) {
    90                 // already completed
    91                 return;
    92             } else if (expired()) {
    93                 testComplete(true);
    94             } else if (_context.clock().now() - state.getLastSendTime() >= RESEND_TIMEOUT) {
    95                 if (state.getReceiveBobTime() <= 0) {
    96                     // no message from Bob yet, send it again
    97                     sendTestToBob();
    98                 } else if (state.getReceiveCharlieTime() <= 0) {
    99                     // received from Bob, but no reply from Charlie.  send it to
    100                     // Bob again so he pokes Charlie
    101                     sendTestToBob();
    102                 } else {
    103                     // received from both Bob and Charlie, but we haven't received a
    104                     // second message from Charlie yet
    105                     sendTestToCharlie();
    106                 }
    107                 SimpleScheduler.getInstance().addEvent(ContinueTest.this, RESEND_TIMEOUT);
    108             }
    109         }
    110     }
    111 
     168            synchronized (PeerTestManager.this) {
     169                PeerTestState state = _currentTest;
     170                if (state == null) {
     171                    // already completed
     172                    return;
     173                } else if (expired()) {
     174                    testComplete(true);
     175                } else if (_context.clock().now() - state.getLastSendTime() >= RESEND_TIMEOUT) {
     176                    if (state.getReceiveBobTime() <= 0) {
     177                        // no message from Bob yet, send it again
     178                        sendTestToBob();
     179                    } else if (state.getReceiveCharlieTime() <= 0) {
     180                        // received from Bob, but no reply from Charlie.  send it to
     181                        // Bob again so he pokes Charlie
     182                        sendTestToBob();
     183                    } else {
     184                        // received from both Bob and Charlie, but we haven't received a
     185                        // second message from Charlie yet
     186                        sendTestToCharlie();
     187                    }
     188                    SimpleScheduler.getInstance().addEvent(ContinueTest.this, RESEND_TIMEOUT);
     189                }
     190            }
     191        }
     192    }
     193
     194    /** call from a synchronized method */
    112195    private boolean expired() {
    113196        PeerTestState state = _currentTest;
     
    118201    }
    119202   
     203    /** call from a synchronized method */
    120204    private void sendTestToBob() {
    121205        PeerTestState test = _currentTest;
     
    129213        }
    130214    }
     215    /** call from a synchronized method */
    131216    private void sendTestToCharlie() {
    132217        PeerTestState test = _currentTest;
     
    154239    /**
    155240     * Receive a PeerTest message which contains the correct nonce for our current
    156      * test
    157      */
    158     private void receiveTestReply(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo) {
     241     * test. We are Alice.
     242     */
     243    private synchronized void receiveTestReply(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo) {
    159244        _context.statManager().addRateData("udp.receiveTestReply", 1, 0);
    160245        PeerTestState test = _currentTest;
     
    209294                    _log.warn("Bob chose a charlie we already have a session to, cancelling the test and rerunning (bob: "
    210295                              + _currentTest + ", charlie: " + from + ")");
     296                // why are we doing this instead of calling testComplete() ?
    211297                _currentTestComplete = true;
    212298                _context.statManager().addRateData("udp.statusKnownCharlie", 1, 0);
     
    268354     * we have successfully received the second PeerTest from a Charlie.
    269355     *
     356     * @param forgetTest must be true to clear out this test and allow another
     357     *
     358     * call from a synchronized method
    270359     */
    271360    private void testComplete(boolean forgetTest) {
     
    325414     * that should be sent in response, or if its a reply to our own current testing,
    326415     * adjusting our test state.
    327      *
     416     * We could be Alice, Bob, or Charlie.
    328417     */
    329418    public void receiveTest(RemoteHostId from, UDPPacketReader reader) {
     
    335424        PeerTestState test = _currentTest;
    336425        if ( (test != null) && (test.getNonce() == nonce) ) {
     426            // we are Alice
    337427            receiveTestReply(from, testInfo);
    338428            return;
    339429        }
    340        
     430
     431        // we are Bob or Charlie
     432
    341433        if ( (testInfo.readIPSize() > 0) && (testPort > 0) ) {
    342434            testIP = new byte[testInfo.readIPSize()];
     
    361453                } else {
    362454                    if (_log.shouldLog(Log.DEBUG))
    363                         _log.debug("We are charlie, as te testIP/port is " + RemoteHostId.toString(testIP) + ":" + testPort + " and the state is unknown for " + nonce);
     455                        _log.debug("We are charlie, as the testIP/port is " + RemoteHostId.toString(testIP) + ":" + testPort + " and the state is unknown for " + nonce);
    364456                    // we are charlie, since alice never sends us her IP and port, only bob does (and,
    365457                    // erm, we're not alice, since it isn't our nonce)
     
    389481    }
    390482   
     483    // Below here are methods for when we are Bob or Charlie
     484
    391485    private static final int MAX_RELAYED_PER_TEST = 5;
    392486   
Note: See TracChangeset for help on using the changeset viewer.