Changeset 11204b8


Ignore:
Timestamp:
Aug 17, 2005 8:05:01 PM (15 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
adf56a1
Parents:
cade27dc
git-author:
jrandom <jrandom> (08/17/05 20:05:01)
git-committer:
zzz <zzz@…> (08/17/05 20:05:01)
Message:

2005-08-17 jrandom

  • Revise the SSU peer testing protocol so that Bob verifies Charlie's viability before agreeing to Alice's request. This doesn't work with older SSU peer test builds, but is backwards compatible (older nodes won't ask newer nodes to participate in tests, and newer nodes won't ask older nodes to either).
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/data/Base64.java

    rcade27dc r11204b8  
    4545    /** added by aum */
    4646    public static String encode(String source) {
    47         return encode(source.getBytes());
     47        return (source != null ? encode(source.getBytes()) : "");
    4848    }
    4949    public static String encode(byte[] source) {
    50         return encode(source, 0, (source != null ? source.length : 0));
     50        return (source != null ? encode(source, 0, (source != null ? source.length : 0)) : "");
    5151    }
    5252    public static String encode(byte[] source, int off, int len) {
    53         return encode(source, off, len, false);
     53        return (source != null ? encode(source, off, len, false) : "");
    5454    }
    5555    public static String encode(byte[] source, boolean useStandardAlphabet) {
    56         return encode(source, 0, (source != null ? source.length : 0), useStandardAlphabet);
     56        return (source != null ? encode(source, 0, (source != null ? source.length : 0), useStandardAlphabet) : "");
    5757    }
    5858    public static String encode(byte[] source, int off, int len, boolean useStandardAlphabet) {
    59         return safeEncode(source, off, len, useStandardAlphabet);
     59        return (source != null ? safeEncode(source, off, len, useStandardAlphabet) : "");
    6060    }
    6161
  • core/java/src/net/i2p/util/LogManager.java

    rcade27dc r11204b8  
    643643    public void shutdown() {
    644644        _log.log(Log.WARN, "Shutting down logger");
    645         _writer.flushRecords();
     645        _writer.flushRecords(false);
    646646    }
    647647
  • core/java/src/net/i2p/util/LogWriter.java

    rcade27dc r11204b8  
    6060    }
    6161
    62     public void flushRecords() {
     62    public void flushRecords() { flushRecords(true); }
     63    public void flushRecords(boolean shouldWait) {
    6364        try {
    6465            List records = _manager._removeAll();
     
    7879            t.printStackTrace();
    7980        } finally {
    80             try {
    81                 synchronized (this) {
    82                     this.wait(10*1000);
    83                 }
    84             } catch (InterruptedException ie) { // nop
     81            if (shouldWait) {
     82                try {
     83                    synchronized (this) {
     84                        this.wait(10*1000);
     85                    }
     86                } catch (InterruptedException ie) { // nop
     87                }
    8588            }
    8689        }
  • history.txt

    rcade27dc r11204b8  
    1 $Id: history.txt,v 1.225 2005/08/10 18:55:41 jrandom Exp $
     1$Id: history.txt,v 1.226 2005/08/12 18:54:47 jrandom Exp $
     2
     32005-08-17  jrandom
     4    * Revise the SSU peer testing protocol so that Bob verifies Charlie's
     5      viability before agreeing to Alice's request.  This doesn't work with
     6      older SSU peer test builds, but is backwards compatible (older nodes
     7      won't ask newer nodes to participate in tests, and newer nodes won't
     8      ask older nodes to either).
    29
    3102005-08-12  jrandom
  • router/doc/udp.html

    rcade27dc r11204b8  
    1 <code>$Id: udp.html,v 1.14 2005/07/27 14:04:07 jrandom Exp $</code>
     1<code>$Id: udp.html,v 1.15 2005/08/03 13:58:13 jrandom Exp $</code>
    22
    33<h1>Secure Semireliable UDP (SSU)</h1>
     
    574574<pre>
    575575        Alice                  Bob                  Charlie
    576     PeerTest ------------------&gt;
    577          &lt;-------------PeerTest  PeerTest-------------&gt;
     576    PeerTest -------------------&gt;
     577                             PeerTest--------------------&gt;
     578                                &lt;-------------------PeerTest
     579         &lt;-------------------PeerTest
    578580         &lt;------------------------------------------PeerTest
    579581    PeerTest------------------------------------------&gt;
     
    593595she will know that her firewall or NAT is somehow misconfigured,
    594596rejecting all inbound UDP packets even in direct response to an
    595 outbound packet.  Alternately, Bob may be down.</li>
     597outbound packet.  Alternately, Bob may be down or unable to get
     598Charlie to reply.</li>
    596599
    597600<li>If Alice doesn't receive a PeerTest message with the
  • router/java/src/net/i2p/router/RouterVersion.java

    rcade27dc r11204b8  
    1616 */
    1717public class RouterVersion {
    18     public final static String ID = "$Revision: 1.214 $ $Date: 2005/08/10 18:55:41 $";
     18    public final static String ID = "$Revision: 1.215 $ $Date: 2005/08/12 18:54:47 $";
    1919    public final static String VERSION = "0.6.0.2";
    20     public final static long BUILD = 2;
     20    public final static long BUILD = 3;
    2121    public static void main(String args[]) {
    2222        System.out.println("I2P Router version: " + VERSION);
  • router/java/src/net/i2p/router/StatisticsManager.java

    rcade27dc r11204b8  
    103103
    104104            includeThroughput(stats);
    105             //includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
     105            includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
    106106            includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
    107107            //includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
  • router/java/src/net/i2p/router/transport/udp/PeerTestManager.java

    rcade27dc r11204b8  
    55import java.util.Arrays;
    66
     7import java.util.ArrayList;
     8import java.util.Collections;
     9import java.util.HashMap;
     10import java.util.List;
     11import java.util.Map;
    712import net.i2p.router.CommSystemFacade;
    813import net.i2p.router.RouterContext;
     14import net.i2p.data.Base64;
    915import net.i2p.data.DataHelper;
    1016import net.i2p.data.RouterInfo;
     
    2127    private UDPTransport _transport;
    2228    private PacketBuilder _packetBuilder;
    23     /**
    24      * circular list of nonces which we have received as if we were 'Charlie'
    25      * (meaning if we see it again, we aren't Bob and shouldn't find our own Charlie).
    26      * Synchronize against this when updating it
    27      */
    28     private long _receiveAsCharlie[];
    29     /** index into _receiveAsCharlie which we should next write to */
    30     private int _receiveAsCharlieIndex;
    31     /** nonce we are currently running our own test as, or -1 */
    32     private long _currentTestNonce;
    33     private InetAddress _bobIP;
    34     private int _bobPort;
    35     private SessionKey _bobIntroKey;
    36     private SessionKey _bobCipherKey;
    37     private SessionKey _bobMACKey;
    38     private long _testBeginTime;
    39     private long _lastSendTime;
    40     private long _receiveBobReplyTime;
    41     private long _receiveCharlieReplyTime;
    42     private InetAddress _charlieIP;
    43     private int _charliePort;
    44     private SessionKey _charlieIntroKey;
    45     private int _receiveBobReplyPort;
    46     private int _receiveCharlieReplyPort;
     29    /** map of Long(nonce) to PeerTestState for tests currently in progress */
     30    private Map _activeTests;
     31    /** current test we are running, or null */
     32    private PeerTestState _currentTest;
     33    private List _recentTests;
    4734   
    4835    /** longest we will keep track of a Charlie nonce for */
     
    5340        _transport = transport;
    5441        _log = context.logManager().getLog(PeerTestManager.class);
    55         _receiveAsCharlie = new long[64];
     42        _activeTests = new HashMap(64);
     43        _recentTests = Collections.synchronizedList(new ArrayList(16));
    5644        _packetBuilder = new PacketBuilder(context);
    57         _currentTestNonce = -1;
     45        _currentTest = null;
    5846    }
    5947   
     
    6351    //public void runTest(InetAddress bobIP, int bobPort, SessionKey bobIntroKey) {
    6452    public void runTest(InetAddress bobIP, int bobPort, SessionKey bobCipherKey, SessionKey bobMACKey) {
    65         _currentTestNonce = _context.random().nextLong(MAX_NONCE);
    66         _bobIP = bobIP;
    67         _bobPort = bobPort;
    68         //_bobIntroKey = bobIntroKey;
    69         _bobCipherKey = bobCipherKey;
    70         _bobMACKey = bobMACKey;
    71         _charlieIP = null;
    72         _charliePort = -1;
    73         _charlieIntroKey = null;
    74         _testBeginTime = _context.clock().now();
    75         _lastSendTime = _testBeginTime;
    76         _receiveBobReplyTime = -1;
    77         _receiveCharlieReplyTime = -1;
    78         _receiveBobReplyPort = -1;
    79         _receiveCharlieReplyPort = -1;
     53        PeerTestState test = new PeerTestState();
     54        test.setNonce(_context.random().nextLong(MAX_NONCE));
     55        test.setBobIP(bobIP);
     56        test.setBobPort(bobPort);
     57        test.setBobCipherKey(bobCipherKey);
     58        test.setBobMACKey(bobMACKey);
     59        test.setBeginTime(_context.clock().now());
     60        test.setLastSendTime(test.getBeginTime());
     61        test.setOurRole(PeerTestState.ALICE);
     62        _currentTest = test;
    8063       
    8164        if (_log.shouldLog(Log.DEBUG))
    82             _log.debug("Running test with bob = " + bobIP + ":" + bobPort);
     65            _log.debug("Running test with bob = " + bobIP + ":" + bobPort + " " + test.getNonce());
     66        while (_recentTests.size() > 16)
     67            _recentTests.remove(0);
     68        _recentTests.add(new Long(test.getNonce()));
    8369       
    8470        sendTestToBob();
     
    8975    private class ContinueTest implements SimpleTimer.TimedEvent {
    9076        public void timeReached() {
    91             if (_currentTestNonce < 0) {
     77            PeerTestState state = _currentTest;
     78            if (state == null) {
    9279                // already completed
    9380                return;
    9481            } else if (expired()) {
    9582                testComplete();
    96             } else {
    97                 if (_receiveBobReplyTime < 0) {
     83            } else if (_context.clock().now() - state.getLastSendTime() >= RESEND_TIMEOUT) {
     84                if (state.getReceiveBobTime() <= 0) {
    9885                    // no message from Bob yet, send it again
    9986                    sendTestToBob();
    100                 } else if (_receiveCharlieReplyTime < 0) {
     87                } else if (state.getReceiveCharlieTime() <= 0) {
    10188                    // received from Bob, but no reply from Charlie.  send it to
    10289                    // Bob again so he pokes Charlie
     
    11097            }
    11198        }
    112         private boolean expired() { return _testBeginTime + MAX_TEST_TIME < _context.clock().now(); }
     99        private boolean expired() {
     100            PeerTestState state = _currentTest;
     101            if (state != null)
     102                return _currentTest.getBeginTime() + MAX_TEST_TIME < _context.clock().now();
     103            else
     104                return true;
     105        }
    113106    }
    114107
    115108    private void sendTestToBob() {
    116         if (_log.shouldLog(Log.DEBUG))
    117             _log.debug("Sending test to bob: " + _bobIP + ":" + _bobPort);
    118         _transport.send(_packetBuilder.buildPeerTestFromAlice(_bobIP, _bobPort, _bobCipherKey, _bobMACKey, //_bobIntroKey,
    119                         _currentTestNonce, _transport.getIntroKey()));
     109        PeerTestState test = _currentTest;
     110        if (test != null) {
     111            if (_log.shouldLog(Log.DEBUG))
     112                _log.debug("Sending test to bob: " + test.getBobIP() + ":" + test.getBobPort());
     113            _transport.send(_packetBuilder.buildPeerTestFromAlice(test.getBobIP(), test.getBobPort(), test.getBobCipherKey(), test.getBobMACKey(), //_bobIntroKey,
     114                            test.getNonce(), _transport.getIntroKey()));
     115        }
    120116    }
    121117    private void sendTestToCharlie() {
    122         if (_log.shouldLog(Log.DEBUG))
    123             _log.debug("Sending test to charlie: " + _charlieIP + ":" + _charliePort);
    124         _transport.send(_packetBuilder.buildPeerTestFromAlice(_charlieIP, _charliePort, _charlieIntroKey,
    125                         _currentTestNonce, _transport.getIntroKey()));
     118        PeerTestState test = _currentTest;
     119        if (test != null) {
     120            if (_log.shouldLog(Log.DEBUG))
     121                _log.debug("Sending test to charlie: " + test.getCharlieIP() + ":" + test.getCharliePort());
     122            _transport.send(_packetBuilder.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(), test.getCharlieIntroKey(),
     123                            test.getNonce(), _transport.getIntroKey()));
     124        }
    126125    }
    127126   
     
    132131     */
    133132    private void receiveTestReply(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo) {
    134         if ( (DataHelper.eq(from.getIP(), _bobIP.getAddress())) && (from.getPort() == _bobPort) ) {
    135             _receiveBobReplyTime = _context.clock().now();
    136             _receiveBobReplyPort = testInfo.readPort();
    137             if (_log.shouldLog(Log.DEBUG))
    138                 _log.debug("Receive test reply from bob @ " + _bobIP + " on " + _receiveBobReplyPort);
     133        PeerTestState test = _currentTest;
     134        if ( (DataHelper.eq(from.getIP(), test.getBobIP().getAddress())) && (from.getPort() == test.getBobPort()) ) {
     135            byte ip[] = new byte[testInfo.readIPSize()];
     136            testInfo.readIP(ip, 0);
     137            try {
     138                InetAddress addr = InetAddress.getByAddress(ip);
     139                test.setAliceIP(addr);
     140                test.setReceiveBobTime(_context.clock().now());
     141                test.setAlicePort(testInfo.readPort());
     142
     143                if (_log.shouldLog(Log.DEBUG))
     144                    _log.debug("Receive test reply from bob @ " + from.getIP() + " via our " + test.getAlicePort() + "/" + test.getAlicePortFromCharlie());
     145                if (test.getAlicePortFromCharlie() > 0)
     146                    testComplete();
     147            } catch (UnknownHostException uhe) {
     148                if (_log.shouldLog(Log.ERROR))
     149                    _log.error("Unable to get our IP from bob's reply: " + from + ", " + testInfo, uhe);
     150            }
    139151        } else {
    140             if (_receiveCharlieReplyTime > 0) {
     152            if (test.getReceiveCharlieTime() > 0) {
    141153                // this is our second charlie, yay!
    142                 _receiveCharlieReplyPort = testInfo.readPort();
    143                 if (_log.shouldLog(Log.DEBUG))
    144                     _log.debug("Receive test reply from charlie @ " + _charlieIP + " on " + _receiveCharlieReplyPort);
    145                 testComplete();
     154                test.setAlicePortFromCharlie(testInfo.readPort());
     155                byte ip[] = new byte[testInfo.readIPSize()];
     156                testInfo.readIP(ip, 0);
     157                try {
     158                    InetAddress addr = InetAddress.getByAddress(ip);
     159                    test.setAliceIPFromCharlie(addr);
     160                    if (_log.shouldLog(Log.DEBUG))
     161                        _log.debug("Receive test reply from charlie @ " + test.getCharlieIP() + " via our "
     162                                   + test.getAlicePort() + "/" + test.getAlicePortFromCharlie());
     163                    if (test.getReceiveBobTime() > 0)
     164                        testComplete();
     165                } catch (UnknownHostException uhe) {
     166                    if (_log.shouldLog(Log.ERROR))
     167                        _log.error("Charlie @ " + from + " said we were an invalid IP address: " + uhe.getMessage(), uhe);
     168                }
    146169            } else {
    147170                // ok, first charlie.  send 'em a packet
    148                 _receiveCharlieReplyTime = _context.clock().now();
    149                 _charlieIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
    150                 testInfo.readIntroKey(_charlieIntroKey.getData(), 0);
    151                 _charliePort = from.getPort();
     171                test.setReceiveCharlieTime(_context.clock().now());
     172                SessionKey charlieIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
     173                testInfo.readIntroKey(charlieIntroKey.getData(), 0);
     174                test.setCharlieIntroKey(charlieIntroKey);
    152175                try {
    153                     _charlieIP = InetAddress.getByAddress(from.getIP());
     176                    test.setCharlieIP(InetAddress.getByAddress(from.getIP()));
     177                    test.setCharliePort(from.getPort());
    154178                    if (_log.shouldLog(Log.DEBUG))
    155                         _log.debug("Receive test from charlie @ " + _charlieIP + " on " + _charliePort);
     179                        _log.debug("Receive test from charlie @ " + from);
    156180                    sendTestToCharlie();
    157181                } catch (UnknownHostException uhe) {
     
    170194    private void testComplete() {
    171195        short status = -1;
    172         if (_receiveCharlieReplyPort > 0) {
     196        PeerTestState test = _currentTest;
     197        if (test == null) return;
     198        if (test.getAlicePortFromCharlie() > 0) {
    173199            // we received a second message from charlie
    174             if (_receiveBobReplyPort == _receiveCharlieReplyPort) {
     200            if ( (test.getAlicePort() == test.getAlicePortFromCharlie()) &&
     201                 (test.getAliceIP() != null) && (test.getAliceIPFromCharlie() != null) &&
     202                 (test.getAliceIP().equals(test.getAliceIPFromCharlie())) ) {
    175203                status = CommSystemFacade.STATUS_OK;
    176204            } else {
    177205                status = CommSystemFacade.STATUS_DIFFERENT;
    178206            }
    179         } else if (_receiveCharlieReplyTime > 0) {
     207        } else if (test.getReceiveCharlieTime() > 0) {
    180208            // we received only one message from charlie
    181209            status = CommSystemFacade.STATUS_UNKNOWN;
    182         } else if (_receiveBobReplyTime > 0) {
     210        } else if (test.getReceiveBobTime() > 0) {
    183211            // we received a message from bob but no messages from charlie
    184212            status = CommSystemFacade.STATUS_REJECT_UNSOLICITED;
    185213        } else {
    186             // we never received anything from bob - he is either down or ignoring us
     214            // we never received anything from bob - he is either down,
     215            // ignoring us, or unable to get a Charlie to respond
    187216            status = CommSystemFacade.STATUS_UNKNOWN;
    188217        }
    189218       
     219        if (_log.shouldLog(Log.INFO))
     220            _log.info("Test complete: " + test);
     221       
    190222        honorStatus(status);
    191        
    192         // now zero everything out
    193         _currentTestNonce = -1;
    194         _bobIP = null;
    195         _bobPort = -1;
    196         _bobIntroKey = null;
    197         _bobCipherKey = null;
    198         _bobMACKey = null;
    199         _charlieIP = null;
    200         _charliePort = -1;
    201         _charlieIntroKey = null;
    202         _testBeginTime = -1;
    203         _lastSendTime = -1;
    204         _receiveBobReplyTime = -1;
    205         _receiveCharlieReplyTime = -1;
    206         _receiveBobReplyPort = -1;
    207         _receiveCharlieReplyPort = -1;
     223        _currentTest = null;
    208224    }
    209225   
     
    227243    public void receiveTest(RemoteHostId from, UDPPacketReader reader) {
    228244        UDPPacketReader.PeerTestReader testInfo = reader.getPeerTestReader();
    229         byte fromIP[] = null;
    230         int fromPort = testInfo.readPort();
     245        byte testIP[] = null;
     246        int testPort = testInfo.readPort();
    231247        long nonce = testInfo.readNonce();
    232         if (nonce == _currentTestNonce) {
     248        PeerTestState test = _currentTest;
     249        if ( (test != null) && (test.getNonce() == nonce) ) {
    233250            receiveTestReply(from, testInfo);
    234251            return;
    235252        }
    236253       
    237         if ( (testInfo.readIPSize() > 0) && (fromPort > 0) ) {
    238             fromIP = new byte[testInfo.readIPSize()];
    239             testInfo.readIP(fromIP, 0);
     254        if ( (testInfo.readIPSize() > 0) && (testPort > 0) ) {
     255            testIP = new byte[testInfo.readIPSize()];
     256            testInfo.readIP(testIP, 0);
    240257        }
    241258       
    242         if ( ( (fromIP == null) && (fromPort <= 0) ) || // info is unknown or...
    243              (DataHelper.eq(fromIP, from.getIP()) && (fromPort == from.getPort())) ) { // info matches sender
    244             int knownIndex = -1;
    245             boolean weAreCharlie = false;
    246             synchronized (_receiveAsCharlie) {
    247                 for (int i = 0; (i < _receiveAsCharlie.length) && (knownIndex == -1); i++)
    248                     if (_receiveAsCharlie[i] == nonce)
    249                         knownIndex = i;
    250             }
    251             weAreCharlie = (knownIndex != -1);
    252             if (_log.shouldLog(Log.DEBUG))
    253                 _log.debug("Receive test with nonce " + nonce + ", known as charlie @ " + knownIndex);
    254            
    255             if (weAreCharlie) {
    256                 receiveFromAliceAsCharlie(from, testInfo, nonce);
     259        PeerTestState state = null;
     260        synchronized (_activeTests) {
     261            state = (PeerTestState)_activeTests.get(new Long(nonce));
     262        }
     263       
     264        if (state == null) {
     265            if ( (testIP == null) || (testPort <= 0) ) {
     266                // we are bob, since we haven't seen this nonce before AND its coming from alice
     267                if (_log.shouldLog(Log.DEBUG))
     268                    _log.debug("test IP/port are blank coming from " + from + ", assuming we are Bob and they are alice");
     269                receiveFromAliceAsBob(from, testInfo, nonce, null);
    257270            } else {
    258                 receiveFromAliceAsBob(from, testInfo, nonce);
     271                if (_recentTests.contains(new Long(nonce))) {
     272                    // ignore the packet, as its a holdover from a recently completed locally
     273                    // initiated test
     274                } else {
     275                    if (_log.shouldLog(Log.DEBUG))
     276                        _log.debug("We are charlie, as te testIP/port is " + testIP + ":" + testPort + " and the state is unknown for " + nonce);
     277                    // we are charlie, since alice never sends us her IP and port, only bob does (and,
     278                    // erm, we're not alice, since it isn't our nonce)
     279                    receiveFromBobAsCharlie(from, testInfo, nonce, null);
     280                }
    259281            }
    260282        } else {
    261             receiveFromBobAsCharlie(from, fromIP, fromPort, nonce, testInfo);
     283            if (state.getOurRole() == PeerTestState.BOB) {
     284                if (DataHelper.eq(from.getIP(), state.getAliceIP().getAddress()) &&
     285                    (from.getPort() == state.getAlicePort()) ) {
     286                    receiveFromAliceAsBob(from, testInfo, nonce, state);
     287                } else if (DataHelper.eq(from.getIP(), state.getCharlieIP().getAddress()) &&
     288                           (from.getPort() == state.getCharliePort()) ) {
     289                    receiveFromCharlieAsBob(from, state);
     290                } else {
     291                    if (_log.shouldLog(Log.ERROR))
     292                        _log.error("Received from a fourth party as bob!  alice: " + state.getAliceIP() + ", charlie: " + state.getCharlieIP() + ", dave: " + from);
     293                }
     294            } else if (state.getOurRole() == PeerTestState.CHARLIE) {
     295                if ( (testIP == null) || (testPort <= 0) ) {
     296                    receiveFromAliceAsCharlie(from, testInfo, nonce);
     297                } else {
     298                    receiveFromBobAsCharlie(from, testInfo, nonce, state);
     299                }
     300            }
    262301        }
    263302    }
     
    268307     * 
    269308     */
    270     private void receiveFromBobAsCharlie(RemoteHostId from, byte fromIP[], int fromPort, long nonce, UDPPacketReader.PeerTestReader testInfo) {
    271         if (fromIP == null) {
    272             if (_log.shouldLog(Log.WARN))
    273                 _log.warn("From address received from Bob (we are Charlie) is invalid: " + from + ": " + testInfo);
    274             return;
    275         }
    276         if (fromPort <= 0) {
    277             if (_log.shouldLog(Log.WARN))
    278                 _log.warn("From port received from Bob (we are Charlie) is invalid: " + fromPort + ": " + testInfo);
    279             return;
    280         }
    281 
    282         boolean isNew = true;
    283         int index = -1;
    284         synchronized (_receiveAsCharlie) {
    285             for (int i = 0; i < _receiveAsCharlie.length; i++) {
    286                 if (_receiveAsCharlie[i] == nonce) {
    287                     index = i;
    288                     isNew = false;
    289                     break;
    290                 }
    291             }
    292             if (index == -1) {
    293                 // ok, new nonce, store 'er
    294                 index = (_receiveAsCharlieIndex + 1) % _receiveAsCharlie.length;
    295                 _receiveAsCharlie[index] = nonce;
    296                 _receiveAsCharlieIndex = index;
    297             }
     309    private void receiveFromBobAsCharlie(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) {
     310        boolean isNew = false;
     311        if (state == null) {
     312            isNew = true;
     313            state = new PeerTestState();
     314            state.setOurRole(PeerTestState.CHARLIE);
    298315        }
    299316       
    300317        if (_log.shouldLog(Log.DEBUG))
    301             _log.debug("Receive test as charlie nonce " + nonce + ", stored at index " + index);
    302            
    303         if (isNew)
    304             SimpleTimer.getInstance().addEvent(new RemoveCharlie(nonce, index), MAX_CHARLIE_LIFETIME);
     318            _log.debug("Receive test as charlie nonce " + nonce);
     319           
     320        int sz = testInfo.readIPSize();
     321        byte aliceIPData[] = new byte[sz];
    305322        try {
    306             InetAddress aliceIP = InetAddress.getByAddress(fromIP);
     323            testInfo.readIP(aliceIPData, 0);
     324            int alicePort = testInfo.readPort();
     325            InetAddress aliceIP = InetAddress.getByAddress(aliceIPData);
     326            InetAddress bobIP = InetAddress.getByAddress(from.getIP());
    307327            SessionKey aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
    308328            testInfo.readIntroKey(aliceIntroKey.getData(), 0);
    309             UDPPacket packet = _packetBuilder.buildPeerTestToAlice(aliceIP, fromPort, aliceIntroKey, _transport.getIntroKey(), nonce);
    310            
     329         
     330            state.setAliceIP(aliceIP);
     331            state.setAlicePort(alicePort);
     332            state.setAliceIntroKey(aliceIntroKey);
     333            state.setNonce(nonce);
     334            state.setBobIP(bobIP);
     335            state.setBobPort(from.getPort());
     336            state.setLastSendTime(_context.clock().now());
     337            state.setOurRole(PeerTestState.CHARLIE);
     338            state.setReceiveBobTime(_context.clock().now());
     339           
     340            PeerState bob = _transport.getPeerState(from);
     341            if (bob == null) {
     342                if (_log.shouldLog(Log.ERROR))
     343                    _log.error("Received from bob (" + from + ") who hasn't established a session with us, refusing to help him test " + aliceIP +":" + alicePort);
     344                return;
     345            } else {
     346                state.setBobCipherKey(bob.getCurrentCipherKey());
     347                state.setBobMACKey(bob.getCurrentMACKey());
     348            }
     349
    311350            if (_log.shouldLog(Log.DEBUG))
    312                 _log.debug("Receive from bob as charlie and send to alice @ " + aliceIP + " on " + fromPort);
    313            
     351                _log.debug("Receive from bob (" + from + ") as charlie, sending back to bob and sending to alice @ " + aliceIP + ":" + alicePort);
     352           
     353            if (isNew) {
     354                synchronized (_activeTests) {
     355                    _activeTests.put(new Long(nonce), state);
     356                }
     357                SimpleTimer.getInstance().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME);
     358            }
     359
     360            UDPPacket packet = _packetBuilder.buildPeerTestToBob(bobIP, from.getPort(), aliceIP, alicePort, aliceIntroKey, nonce, state.getBobCipherKey(), state.getBobMACKey());
     361            _transport.send(packet);
     362           
     363            packet = _packetBuilder.buildPeerTestToAlice(aliceIP, alicePort, aliceIntroKey, _transport.getIntroKey(), nonce);
    314364            _transport.send(packet);
    315365        } catch (UnknownHostException uhe) {
    316366            if (_log.shouldLog(Log.WARN))
    317                 _log.warn("Unable to build the aliceIP from " + from, uhe);
     367                _log.warn("Unable to build the aliceIP from " + from + ", ip size: " + sz + " ip val: " + Base64.encode(aliceIPData), uhe);
    318368        }
    319369    }
     
    324374     *
    325375     */
    326     private void receiveFromAliceAsBob(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce) {
    327         // we are Bob, so send Alice her PeerTest, pick a Charlie, and
    328         // send Charlie Alice's info
     376    private void receiveFromAliceAsBob(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) {
     377        // we are Bob, so pick a (potentially) Charlie and send Charlie Alice's info
    329378        PeerState charlie = null;
    330         for (int i = 0; i < 5; i++) {
    331             charlie = _transport.getPeerState(UDPAddress.CAPACITY_TESTING);
    332             if (_log.shouldLog(Log.DEBUG))
    333                 _log.debug("Picking charlie as " + charlie + " for alice of " + from);
    334             if ( (charlie != null) && (!charlie.getRemoteHostId().equals(from)) ) {
    335                 break;
    336             }
    337             charlie = null;
    338         }
     379        RouterInfo charlieInfo = null;
     380        if (state == null) { // pick a new charlie
     381            for (int i = 0; i < 5; i++) {
     382                charlie = _transport.getPeerState(UDPAddress.CAPACITY_TESTING);
     383                if (_log.shouldLog(Log.DEBUG))
     384                    _log.debug("Picking charlie as " + charlie + " for alice of " + from);
     385                if ( (charlie != null) && (!DataHelper.eq(charlie.getRemoteHostId(), from)) ) {
     386                    charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer());
     387                    if (charlieInfo != null)
     388                        break;
     389                }
     390                charlie = null;
     391            }
     392        } else {
     393            charlie = _transport.getPeerState(new RemoteHostId(state.getCharlieIP().getAddress(), state.getCharliePort()));
     394            if (charlie != null)
     395                charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer());
     396        }
     397       
    339398        if (charlie == null) {
    340399            if (_log.shouldLog(Log.WARN))
     
    342401            return;
    343402        }
     403       
    344404        InetAddress aliceIP = null;
    345405        SessionKey aliceIntroKey = null;
     
    349409            testInfo.readIntroKey(aliceIntroKey.getData(), 0);
    350410           
    351             RouterInfo info = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer());
    352             if (info == null) {
    353                 if (_log.shouldLog(Log.WARN))
    354                     _log.warn("No info for charlie: " + charlie);
    355                 return;
    356             }
    357            
    358             UDPAddress addr = new UDPAddress(info.getTargetAddress(UDPTransport.STYLE));
     411            UDPAddress addr = new UDPAddress(charlieInfo.getTargetAddress(UDPTransport.STYLE));
    359412            SessionKey charlieIntroKey = new SessionKey(addr.getIntroKey());
    360413           
    361             UDPPacket packet = _packetBuilder.buildPeerTestToAlice(aliceIP, from.getPort(), aliceIntroKey, charlieIntroKey, nonce);
    362             _transport.send(packet);
    363 
    364             packet = _packetBuilder.buildPeerTestToCharlie(aliceIP, from.getPort(), aliceIntroKey, nonce,
    365                                                            charlie.getRemoteIPAddress(),
    366                                                            charlie.getRemotePort(),
    367                                                            charlie.getCurrentCipherKey(),
    368                                                            charlie.getCurrentMACKey());
     414            //UDPPacket packet = _packetBuilder.buildPeerTestToAlice(aliceIP, from.getPort(), aliceIntroKey, charlieIntroKey, nonce);
     415            //_transport.send(packet);
     416
     417            boolean isNew = false;
     418            if (state == null) {
     419                isNew = true;
     420                state = new PeerTestState();
     421                state.setBeginTime(_context.clock().now());
     422            }
     423            state.setAliceIP(aliceIP);
     424            state.setAlicePort(from.getPort());
     425            state.setAliceIntroKey(aliceIntroKey);
     426            state.setNonce(nonce);
     427            state.setCharlieIP(charlie.getRemoteIPAddress());
     428            state.setCharliePort(charlie.getRemotePort());
     429            state.setCharlieIntroKey(charlieIntroKey);
     430            state.setLastSendTime(_context.clock().now());
     431            state.setOurRole(PeerTestState.BOB);
     432            state.setReceiveAliceTime(_context.clock().now());
     433           
     434            if (isNew) {
     435                synchronized (_activeTests) {
     436                    _activeTests.put(new Long(nonce), state);
     437                }
     438                SimpleTimer.getInstance().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME);
     439            }
     440           
     441            UDPPacket packet = _packetBuilder.buildPeerTestToCharlie(aliceIP, from.getPort(), aliceIntroKey, nonce,
     442                                                                     charlie.getRemoteIPAddress(),
     443                                                                     charlie.getRemotePort(),
     444                                                                     charlie.getCurrentCipherKey(),
     445                                                                     charlie.getCurrentMACKey());
    369446           
    370447            if (_log.shouldLog(Log.DEBUG))
    371                 _log.debug("Receive from alice as bob, picking charlie @ " + charlie.getRemoteIPAddress() + ":"
     448                _log.debug("Receive from alice as bob for " + nonce + ", picking charlie @ " + charlie.getRemoteIPAddress() + ":"
    372449                           + charlie.getRemotePort() + " for alice @ " + aliceIP + ":" + from.getPort());
    373450           
     
    377454                _log.warn("Unable to build the aliceIP from " + from, uhe);
    378455        }
     456    }
     457   
     458    /**
     459     * The PeerTest message came from one of the Charlies picked for an existing test, so send Alice the
     460     * packet verifying participation.
     461     *
     462     */
     463    private void receiveFromCharlieAsBob(RemoteHostId from, PeerTestState state) {
     464        state.setReceiveCharlieTime(_context.clock().now());
     465        UDPPacket packet = _packetBuilder.buildPeerTestToAlice(state.getAliceIP(), state.getAlicePort(),
     466                                                               state.getAliceIntroKey(), state.getCharlieIntroKey(),
     467                                                               state.getNonce());
     468
     469        if (_log.shouldLog(Log.DEBUG))
     470            _log.debug("Receive from charlie @ " + from + " as bob, sending alice back the ok @ " + state.getAliceIP() + ":" + state.getAlicePort());
     471
     472        _transport.send(packet);
    379473    }
    380474   
     
    403497     * forget about charlie's nonce after 60s. 
    404498     */
    405     private class RemoveCharlie implements SimpleTimer.TimedEvent {
     499    private class RemoveTest implements SimpleTimer.TimedEvent {
    406500        private long _nonce;
    407         private int _index;
    408         public RemoveCharlie(long nonce, int index) {
     501        public RemoveTest(long nonce) {
    409502            _nonce = nonce;
    410             _index = index;
    411503        }
    412504        public void timeReached() {
    413             /** only forget about an entry if we haven't already moved on */
    414             synchronized (_receiveAsCharlie) {
    415                 if (_receiveAsCharlie[_index] == _nonce)
    416                     _receiveAsCharlie[_index] = -1;
    417             }
    418         }
    419        
     505            synchronized (_activeTests) {
     506                _activeTests.remove(new Long(_nonce));
     507            }
     508        }
    420509    }
    421510}
  • router/java/src/net/i2p/router/transport/udp/UDPAddress.java

    rcade27dc r11204b8  
    2222   
    2323    public static final String PROP_CAPACITY = "caps";
    24     public static final char CAPACITY_TESTING = 'A';
    25     public static final char CAPACITY_INTRODUCER = 'B';
     24    public static final char CAPACITY_TESTING = 'B';
     25    public static final char CAPACITY_INTRODUCER = 'C';
    2626
    2727    public UDPAddress(RouterAddress addr) {
  • router/java/src/net/i2p/router/transport/udp/UDPTransport.java

    rcade27dc r11204b8  
    378378    }
    379379   
     380    /**
     381     * if we haven't received anything in the last 5 minutes from a peer, don't
     382     * trust its known capacities
     383     */
     384    private static final int MAX_INACTIVITY_FOR_CAPACITY = 5*60*1000;
    380385    /** pick a random peer with the given capacity */
    381386    public PeerState getPeerState(char capacity) {
     387        long now = _context.clock().now();
    382388        int index = _context.random().nextInt(1024);
    383389        List peers = _peersByCapacity[capacity-'A'];
    384390        int size = 0;
     391        int off = 0;
    385392        PeerState rv = null;
    386         for (int i = 0; i < 5; i++) {
     393        while (rv == null) {
    387394            synchronized (peers) {
    388395                size = peers.size();
    389396                if (size > 0) {
    390                     index = (index + i) % size;
     397                    index = (index + off) % size;
    391398                    rv = (PeerState)peers.get(index);
    392399                }
     
    396403            if (_context.shitlist().isShitlisted(rv.getRemotePeer()))
    397404                rv = null;
     405            else if (now - rv.getLastReceiveTime() > MAX_INACTIVITY_FOR_CAPACITY)
     406                rv = null;
    398407            else
    399408                break;
     409            off++;
     410            if (off >= size)
     411                break;
    400412        }
    401413        _context.statManager().addRateData("udp.peersByCapacity", size, capacity);
     
    403415    }
    404416
    405     private static final int MAX_PEERS_PER_CAPACITY = 16;
     417    private static final int MAX_PEERS_PER_CAPACITY = 64;
    406418   
    407419    /**
Note: See TracChangeset for help on using the changeset viewer.