Changeset 443abce


Ignore:
Timestamp:
Dec 26, 2010 8:36:44 PM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
bebd6b2, cdcbc802
Parents:
49b11bb4
Message:
  • I2CP:
    • Move BWLimits and DestLookup? message support from I2PSimpleSession to I2PSessionImpl
    • Include the Hash in the DestReplyMessage? on a failed lookup so the client may correlate replies
    • Add support for parallel lookups and BWLimits requests
    • Add support for specifying the timeout for DestLookups? (can only be smaller than the router timeout for now)
    • Extend dest lookup router timeout from 10s to 15s
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java

    r49b11bb4 r443abce  
    1515import net.i2p.I2PException;
    1616import net.i2p.client.I2PSession;
     17import net.i2p.client.I2PSessionException;
    1718import net.i2p.client.streaming.I2PServerSocket;
    1819import net.i2p.client.streaming.I2PSocket;
     
    2021import net.i2p.client.streaming.I2PSocketManager;
    2122import net.i2p.client.streaming.I2PSocketManagerFactory;
     23import net.i2p.data.Base32;
    2224import net.i2p.data.DataFormatException;
    2325import net.i2p.data.Destination;
     
    317319    }
    318320
     321    private static final int BASE32_HASH_LENGTH = 52;   // 1 + Hash.HASH_LENGTH * 8 / 5
     322
    319323    /** Base64 Hash or Hash.i2p or name.i2p using naming service */
    320324    Destination getDestination(String ip) {
     
    322326        if (ip.endsWith(".i2p")) {
    323327            if (ip.length() < 520) {   // key + ".i2p"
    324                 Destination dest = _context.namingService().lookup(ip);
    325                 if (dest != null)
    326                     return dest;
    327             }
     328                if (_manager != null && ip.length() == BASE32_HASH_LENGTH + 8 && ip.endsWith(".b32.i2p")) {
     329                    // Use existing I2PSession for b32 lookups if we have it
     330                    // This is much more efficient than using the naming service
     331                    I2PSession sess = _manager.getSession();
     332                    if (sess != null) {
     333                        byte[] b = Base32.decode(ip.substring(0, BASE32_HASH_LENGTH));
     334                        if (b != null) {
     335                            Hash h = new Hash(b);
     336                            if (_log.shouldLog(Log.INFO))
     337                                _log.info("Using existing session for lookup of " + ip);
     338                            try {
     339                                return sess.lookupDest(h);
     340                            } catch (I2PSessionException ise) {
     341                            }
     342                        }
     343                    }
     344                }
     345                if (_log.shouldLog(Log.INFO))
     346                    _log.info("Using naming service for lookup of " + ip);
     347                return _context.namingService().lookup(ip);
     348            }
     349            if (_log.shouldLog(Log.INFO))
     350                _log.info("Creating Destination for " + ip);
    328351            try {
    329352                return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
     
    332355            }
    333356        } else {
     357            if (_log.shouldLog(Log.INFO))
     358                _log.info("Creating Destination for " + ip);
    334359            try {
    335360                return new Destination(ip);
  • core/java/src/net/i2p/client/DestReplyMessageHandler.java

    r49b11bb4 r443abce  
    1010import net.i2p.data.i2cp.DestReplyMessage;
    1111import net.i2p.util.Log;
     12
     13import net.i2p.data.Destination;
     14import net.i2p.data.Hash;
    1215
    1316/**
     
    2326            _log.debug("Handle message " + message);
    2427        DestReplyMessage msg = (DestReplyMessage) message;
    25        ((I2PSimpleSession)session).destReceived(msg.getDestination());
     28        Destination d = msg.getDestination();
     29        if (d != null)
     30            session.destReceived(d);
     31        Hash h = msg.getHash();
     32        if (h != null)
     33            session.destLookupFailed(h);
     34        // else let it time out
    2635    }
    2736}
  • core/java/src/net/i2p/client/I2PClientMessageHandlerMap.java

    r49b11bb4 r443abce  
    1111
    1212import net.i2p.I2PAppContext;
     13import net.i2p.data.i2cp.BandwidthLimitsMessage;
     14import net.i2p.data.i2cp.DestReplyMessage;
    1315import net.i2p.data.i2cp.DisconnectMessage;
    1416import net.i2p.data.i2cp.MessagePayloadMessage;
     
    3739        highest = Math.max(highest, MessageStatusMessage.MESSAGE_TYPE);
    3840        highest = Math.max(highest, SetDateMessage.MESSAGE_TYPE);
     41        highest = Math.max(highest, DestReplyMessage.MESSAGE_TYPE);
     42        highest = Math.max(highest, BandwidthLimitsMessage.MESSAGE_TYPE);
    3943       
    4044        _handlers = new I2CPMessageHandler[highest+1];
     
    4549        _handlers[MessageStatusMessage.MESSAGE_TYPE] = new MessageStatusMessageHandler(context);
    4650        _handlers[SetDateMessage.MESSAGE_TYPE] = new SetDateMessageHandler(context);
     51        _handlers[DestReplyMessage.MESSAGE_TYPE] = new DestReplyMessageHandler(context);
     52        _handlers[BandwidthLimitsMessage.MESSAGE_TYPE] = new BWLimitsMessageHandler(context);
    4753    }
    4854
  • core/java/src/net/i2p/client/I2PSession.java

    r49b11bb4 r443abce  
    139139
    140140    /**
    141      * Lookup up a Hash
    142      *
     141     * Lookup a Destination by Hash.
     142     * Blocking. Waits a max of 10 seconds by default.
    143143     */
    144144    public Destination lookupDest(Hash h) throws I2PSessionException;
    145145
    146146    /**
    147      * Get the current bandwidth limits
     147     *  Blocking.
     148     *  @param maxWait ms
     149     *  @since 0.8.3
     150     *  @return null on failure
     151     */
     152    public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException;
     153
     154    /**
     155     * Get the current bandwidth limits. Blocking.
    148156     */
    149157    public int[] bandwidthLimits() throws I2PSessionException;
  • core/java/src/net/i2p/client/I2PSessionImpl.java

    r49b11bb4 r443abce  
    1616import java.net.Socket;
    1717import java.net.UnknownHostException;
    18 import java.util.concurrent.ConcurrentHashMap;
    1918import java.util.ArrayList;
    2019import java.util.HashSet;
     
    2423import java.util.Properties;
    2524import java.util.Set;
     25import java.util.concurrent.ConcurrentHashMap;
     26import java.util.concurrent.LinkedBlockingQueue;
    2627
    2728import net.i2p.I2PAppContext;
     
    3435import net.i2p.data.SessionTag;
    3536import net.i2p.data.SigningPrivateKey;
     37import net.i2p.data.i2cp.DestLookupMessage;
     38import net.i2p.data.i2cp.GetBandwidthLimitsMessage;
    3639import net.i2p.data.i2cp.GetDateMessage;
    3740import net.i2p.data.i2cp.I2CPMessage;
     
    9699    /** map of Long --> MessagePayloadMessage */
    97100    protected Map<Long, MessagePayloadMessage> _availableMessages;
     101
     102    /** hashes of lookups we are waiting for */
     103    protected final LinkedBlockingQueue<LookupWaiter> _pendingLookups = new LinkedBlockingQueue();
     104    protected final Object _bwReceivedLock = new Object();
     105    protected int[] _bwLimits;
    98106   
    99107    protected I2PClientMessageHandlerMap _handlerMap;
     
    787795    }
    788796
     797    /** called by the message handler */
     798    void destReceived(Destination d) {
     799        Hash h = d.calculateHash();
     800        for (LookupWaiter w : _pendingLookups) {
     801            if (w.hash.equals(h)) {
     802                w.destination = d;
     803                synchronized (w) {
     804                    w.notifyAll();
     805                }
     806            }
     807        }
     808    }
     809
     810    /** called by the message handler */
     811    void destLookupFailed(Hash h) {
     812        for (LookupWaiter w : _pendingLookups) {
     813            if (w.hash.equals(h)) {
     814                synchronized (w) {
     815                    w.notifyAll();
     816                }
     817            }
     818        }
     819    }
     820
     821    /** called by the message handler */
     822    void bwReceived(int[] i) {
     823        _bwLimits = i;
     824        synchronized (_bwReceivedLock) {
     825            _bwReceivedLock.notifyAll();
     826        }
     827    }
     828
     829    /**
     830     *  Simple object to wait for lookup replies
     831     *  @since 0.8.3
     832     */
     833    private static class LookupWaiter {
     834        /** the request */
     835        public final Hash hash;
     836        /** the reply */
     837        public Destination destination;
     838
     839        public LookupWaiter(Hash h) {
     840            this.hash = h;
     841        }
     842    }
     843
     844    /**
     845     *  Blocking. Waits a max of 10 seconds by default.
     846     *  See lookupDest with maxWait parameter to change.
     847     *  Implemented in 0.8.3 in I2PSessionImpl;
     848     *  previously was available only in I2PSimpleSession.
     849     *  Multiple outstanding lookups are now allowed.
     850     *  @return null on failure
     851     */
    789852    public Destination lookupDest(Hash h) throws I2PSessionException {
    790         return null;
    791     }
    792 
     853        return lookupDest(h, 10*1000);
     854    }
     855
     856    /**
     857     *  Blocking.
     858     *  @param maxWait ms
     859     *  @since 0.8.3
     860     *  @return null on failure
     861     */
     862    public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException {
     863        if (_closed)
     864            return null;
     865        LookupWaiter waiter = new LookupWaiter(h);
     866        _pendingLookups.offer(waiter);
     867        sendMessage(new DestLookupMessage(h));
     868        try {
     869            synchronized (waiter) {
     870                waiter.wait(maxWait);
     871            }
     872        } catch (InterruptedException ie) {}
     873        _pendingLookups.remove(waiter);
     874        return waiter.destination;
     875    }
     876
     877    /**
     878     *  Blocking. Waits a max of 5 seconds.
     879     *  But shouldn't take long.
     880     *  Implemented in 0.8.3 in I2PSessionImpl;
     881     *  previously was available only in I2PSimpleSession.
     882     *  Multiple outstanding lookups are now allowed.
     883     *  @return null on failure
     884     */
    793885    public int[] bandwidthLimits() throws I2PSessionException {
    794         return null;
     886        if (_closed)
     887            return null;
     888        sendMessage(new GetBandwidthLimitsMessage());
     889        try {
     890            synchronized (_bwReceivedLock) {
     891                _bwReceivedLock.wait(5*1000);
     892            }
     893        } catch (InterruptedException ie) {}
     894        return _bwLimits;
    795895    }
    796896
  • core/java/src/net/i2p/client/I2PSimpleSession.java

    r49b11bb4 r443abce  
    3434 */
    3535class I2PSimpleSession extends I2PSessionImpl2 {
    36     private boolean _destReceived;
    37     private /* FIXME final FIXME */ Object _destReceivedLock;
    38     private Destination _destination;
    39     private boolean _bwReceived;
    40     private /* FIXME final FIXME */ Object _bwReceivedLock;
    41     private int[] _bwLimits;
    4236
    4337    /**
     
    10599    }
    106100
    107     /** called by the message handler */
    108     void destReceived(Destination d) {
    109         _destReceived = true;
    110         _destination = d;
    111         synchronized (_destReceivedLock) {
    112             _destReceivedLock.notifyAll();
    113         }
    114     }
    115 
    116     void bwReceived(int[] i) {
    117         _bwReceived = true;
    118         _bwLimits = i;
    119         synchronized (_bwReceivedLock) {
    120             _bwReceivedLock.notifyAll();
    121         }
    122     }
    123 
    124     @Override
    125     public Destination lookupDest(Hash h) throws I2PSessionException {
    126         if (_closed)
    127             return null;
    128         _destReceivedLock = new Object();
    129         sendMessage(new DestLookupMessage(h));
    130         for (int i = 0; i < 10 && !_destReceived; i++) {
    131             try {
    132                 synchronized (_destReceivedLock) {
    133                     _destReceivedLock.wait(1000);
    134                 }
    135             } catch (InterruptedException ie) {}
    136         }
    137         _destReceived = false;
    138         return _destination;
    139     }
    140 
    141     @Override
    142     public int[] bandwidthLimits() throws I2PSessionException {
    143         if (_closed)
    144             return null;
    145         _bwReceivedLock = new Object();
    146         sendMessage(new GetBandwidthLimitsMessage());
    147         for (int i = 0; i < 5 && !_bwReceived; i++) {
    148             try {
    149                 synchronized (_bwReceivedLock) {
    150                     _bwReceivedLock.wait(1000);
    151                 }
    152             } catch (InterruptedException ie) {}
    153         }
    154         _bwReceived = false;
    155         return _bwLimits;
    156     }
    157 
    158101    /**
    159102     * Only map message handlers that we will use
  • core/java/src/net/i2p/client/naming/LookupDest.java

    r49b11bb4 r443abce  
    2323 * All calls are blocking and return null on failure.
    2424 * Timeout is set to 10 seconds in I2PSimpleSession.
     25 *
     26 * As of 0.8.3, standard I2PSessions support lookups,
     27 * including multiple lookups in parallel, and overriding
     28 * the default timeout.
     29 * Using an existing I2PSession is much more efficient and
     30 * flexible than using this class.
     31 *
    2532 */
    2633class LookupDest {
  • core/java/src/net/i2p/data/i2cp/DestReplyMessage.java

    r49b11bb4 r443abce  
    1414import net.i2p.data.DataHelper;
    1515import net.i2p.data.Destination;
     16import net.i2p.data.Hash;
    1617
    1718/**
    18  * Response to DestLookupMessage
    19  *
     19 * Response to DestLookupMessage.
     20 * As of 0.8.3, the response may include the hash from the request, indicating
     21 * a failure for a specific request.
     22 * Payload may be empty (failure), a Hash (failure), or a Destination.
    2023 */
    2124public class DestReplyMessage extends I2CPMessageImpl {
    2225    public final static int MESSAGE_TYPE = 35;
    2326    private Destination _dest;
     27    private Hash _hash;
    2428
    2529    public DestReplyMessage() {
     
    3135    }
    3236
     37    /**
     38     *  @param h non-null with non-null data
     39     *  @since 0.8.3
     40     */
     41    public DestReplyMessage(Hash h) {
     42        _hash = h;
     43    }
     44
    3345    public Destination getDestination() {
    3446        return _dest;
    3547    }
    3648
     49    /**
     50     *  @since 0.8.3
     51     */
     52    public Hash getHash() {
     53        return _hash;
     54    }
     55
    3756    protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException {
    38         try {
    39             Destination d = new Destination();
    40             d.readBytes(in);
    41             _dest = d;
    42         } catch (DataFormatException dfe) {
    43             _dest = null; // null dest allowed
     57        if (size == 0) {
     58            _dest = null;
     59            _hash = null;
     60        } else {
     61            try {
     62                if (size == Hash.HASH_LENGTH) {
     63                    Hash h = new Hash();
     64                    h.readBytes(in);
     65                    _hash = h;
     66                } else {
     67                    Destination d = new Destination();
     68                    d.readBytes(in);
     69                    _dest = d;
     70                }
     71            } catch (DataFormatException dfe) {
     72                _dest = null;
     73                _hash = null;
     74            }
    4475        }
    4576    }
    4677
    4778    protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
    48         if (_dest == null)
     79        if (_dest == null && _hash == null)
    4980            return new byte[0];  // null response allowed
     81        if (_dest == null && _hash != null)
     82            return _hash.getData();
    5083        ByteArrayOutputStream os = new ByteArrayOutputStream(_dest.size());
    5184        try {
     
    6699        if ((object != null) && (object instanceof DestReplyMessage)) {
    67100            DestReplyMessage msg = (DestReplyMessage) object;
    68             return DataHelper.eq(getDestination(), msg.getDestination());
     101            return DataHelper.eq(getDestination(), msg.getDestination()) &&
     102                   DataHelper.eq(getHash(), msg.getHash());
    69103        }
    70104        return false;
     
    76110        buf.append("[DestReplyMessage: ");
    77111        buf.append("\n\tDestination: ").append(_dest);
     112        buf.append("\n\tHash: ").append(_hash);
    78113        buf.append("]");
    79114        return buf.toString();
Note: See TracChangeset for help on using the changeset viewer.