Changeset ad24f14


Ignore:
Timestamp:
Mar 10, 2011 5:59:35 PM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
de815e2
Parents:
b6a0426 (diff), a3fb49a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

propagate from branch 'i2p.i2p' (head ca5b19055e887994435b0eb35978484f2489bb6e)

to branch 'i2p.i2p.zzz.naming' (head e71d7dc813c07bb2b6798ab74099efdfc1754f47)

Files:
25 added
7 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • LICENSE.txt

    rb6a0426 rad24f14  
    7373   See licenses/LICENSE-InstallCert.txt
    7474
     75   BlockFile:
     76   Copyright (c) 2006, Matthew Estes
     77   See licenses/LICENSE-BlockFile.txt
     78
    7579
    7680Router:
  • build.xml

    rb6a0426 rad24f14  
    258258            doctitle="I2P Javadocs for Release ${release.number} Build ${build.number}"
    259259            windowtitle="I2P Anonymous Network - Java Documentation - Version ${release.number}">
    260             <group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.crypto:org.bouncycastle.crypto.*:gnu.crypto.*:gnu.gettext:org.xlattice.crypto.filters:com.nettgryppa.security" />
     260            <group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.crypto:org.bouncycastle.crypto.*:gnu.crypto.*:gnu.gettext:org.xlattice.crypto.filters:com.nettgryppa.security:net.metanotion.*" />
    261261            <group title="Streaming Library" packages="net.i2p.client.streaming" />
    262262            <group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:org.cybergarage.*:org.freenetproject" />
  • core/java/src/net/i2p/I2PAppContext.java

    rb6a0426 rad24f14  
    88
    99import net.i2p.client.naming.NamingService;
    10 import net.i2p.client.naming.PetNameDB;
    1110import net.i2p.crypto.AESEngine;
    1211import net.i2p.crypto.CryptixAESEngine;
     
    7372    private SessionKeyManager _sessionKeyManager;
    7473    private NamingService _namingService;
    75     private PetNameDB _petnameDb;
    7674    private ElGamalEngine _elGamalEngine;
    7775    private ElGamalAESEngine _elGamalAESEngine;
     
    9088    private volatile boolean _sessionKeyManagerInitialized;
    9189    private volatile boolean _namingServiceInitialized;
    92     private volatile boolean _petnameDbInitialized;
    9390    private volatile boolean _elGamalEngineInitialized;
    9491    private volatile boolean _elGamalAESEngineInitialized;
     
    178175        _sessionKeyManager = null;
    179176        _namingService = null;
    180         _petnameDb = null;
    181177        _elGamalEngine = null;
    182178        _elGamalAESEngine = null;
     
    581577    }
    582578   
    583     /** @deprecated unused */
    584     public PetNameDB petnameDb() {
    585         if (!_petnameDbInitialized)
    586             initializePetnameDb();
    587         return _petnameDb;
    588     }
    589 
    590     /** @deprecated unused */
    591     private void initializePetnameDb() {
    592         synchronized (this) {
    593             if (_petnameDb == null) {
    594                 _petnameDb = new PetNameDB();
    595             }
    596             _petnameDbInitialized = true;
    597         }
    598     }
    599    
    600579    /**
    601580     * This is the ElGamal engine used within this context.  While it doesn't
  • core/java/src/net/i2p/client/naming/DummyNamingService.java

    rb6a0426 rad24f14  
    88package net.i2p.client.naming;
    99
     10import java.util.ArrayList;
     11import java.util.HashMap;
     12import java.util.List;
     13import java.util.Map;
     14import java.util.Properties;
     15
    1016import net.i2p.I2PAppContext;
    1117import net.i2p.data.Destination;
    1218
    1319/**
    14  * A Dummy naming service that can only handle base64 destinations.
     20 * A Dummy naming service that can only handle base64 and b32 destinations.
    1521 */
    1622class DummyNamingService extends NamingService {
     23    private final Map<String, CacheEntry> _cache;
     24
     25    private static final int BASE32_HASH_LENGTH = 52;   // 1 + Hash.HASH_LENGTH * 8 / 5
     26    public final static String PROP_B32 = "i2p.naming.hostsTxt.useB32";
     27    protected static final int CACHE_MAX_SIZE = 16;
     28    public static final int DEST_SIZE = 516;                    // Std. Base64 length (no certificate)
     29
    1730    /**
    1831     * The naming service should only be constructed and accessed through the
     
    2134     *
    2235     */
    23     protected DummyNamingService(I2PAppContext context) { super(context); }
    24     private DummyNamingService() { super(null); }
     36    protected DummyNamingService(I2PAppContext context) {
     37        super(context);
     38        _cache = new HashMap(CACHE_MAX_SIZE);
     39    }
    2540   
    2641    @Override
    27     public Destination lookup(String hostname) {
    28         return lookupBase64(hostname);
     42    public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
     43        Destination d = getCache(hostname);
     44        if (d != null)
     45            return d;
     46
     47        // If it's long, assume it's a key.
     48        if (hostname.length() >= 516) {
     49            d = lookupBase64(hostname);
     50            // What the heck, cache these too
     51            putCache(hostname, d);
     52            return d;
     53        }
     54
     55        // Try Base32 decoding
     56        if (hostname.length() == BASE32_HASH_LENGTH + 8 && hostname.endsWith(".b32.i2p") &&
     57            _context.getBooleanPropertyDefaultTrue(PROP_B32)) {
     58            d = LookupDest.lookupBase32Hash(_context, hostname.substring(0, BASE32_HASH_LENGTH));
     59            if (d != null) {
     60                putCache(hostname, d);
     61                return d;
     62            }
     63        }
     64
     65        return null;
     66    }
     67
     68    /**
     69     *  Provide basic caching for the service
     70     *  The service may override the age and/or size limit
     71     */
     72    /** Don't know why a dest would ever change but keep this short anyway */
     73    protected static final long CACHE_MAX_AGE = 7*60*1000;
     74
     75    private class CacheEntry {
     76        public Destination dest;
     77        public long exp;
     78        public CacheEntry(Destination d) {
     79            dest = d;
     80            exp = _context.clock().now() + CACHE_MAX_AGE;
     81        }
     82        public boolean isExpired() {
     83            return exp < _context.clock().now();
     84        }
     85    }
     86
     87    /**
     88     * Clean up when full.
     89     * Don't bother removing old entries unless full.
     90     * Caller must synchronize on _cache.
     91     */
     92    private void cacheClean() {
     93        if (_cache.size() < CACHE_MAX_SIZE)
     94            return;
     95        boolean full = true;
     96        String oldestKey = null;
     97        long oldestExp = Long.MAX_VALUE;
     98        List<String> deleteList = new ArrayList(CACHE_MAX_SIZE);
     99        for (Map.Entry<String, CacheEntry> entry : _cache.entrySet()) {
     100            CacheEntry ce = entry.getValue();
     101            if (ce.isExpired()) {
     102                deleteList.add(entry.getKey());
     103                full = false;
     104                continue;
     105            }
     106            if (oldestKey == null || ce.exp < oldestExp) {
     107                oldestKey = entry.getKey();
     108                oldestExp = ce.exp;
     109            }
     110        }
     111        if (full && oldestKey != null)
     112            deleteList.add(oldestKey);
     113        for (String s : deleteList) {
     114            _cache.remove(s);
     115        }
     116    }
     117
     118    protected void putCache(String s, Destination d) {
     119        if (d == null)
     120            return;
     121        synchronized (_cache) {
     122            _cache.put(s, new CacheEntry(d));
     123            cacheClean();
     124        }
     125    }
     126
     127    protected Destination getCache(String s) {
     128        synchronized (_cache) {
     129            CacheEntry ce = _cache.get(s);
     130            if (ce == null)
     131                return null;
     132            if (ce.isExpired()) {
     133                _cache.remove(s);
     134                return null;
     135            }
     136            return ce.dest;
     137        }
     138    }
     139
     140    /** @since 0.8.5 */
     141    protected void removeCache(String s) {
     142        synchronized (_cache) {
     143            _cache.remove(s);
     144        }
     145    }
     146
     147    /** @since 0.8.1 */
     148    public void clearCache() {
     149        synchronized (_cache) {
     150            _cache.clear();
     151        }
    29152    }
    30153}
  • core/java/src/net/i2p/client/naming/EepGetAndAddNamingService.java

    rb6a0426 rad24f14  
    3131 *
    3232 * @author zzz
     33 * @deprecated use HostsTxtNamingService.put()
    3334 * @since 0.7.9
    3435 */
  • core/java/src/net/i2p/client/naming/EepGetNamingService.java

    rb6a0426 rad24f14  
    88import java.util.ArrayList;
    99import java.util.List;
     10import java.util.Properties;
    1011import java.util.StringTokenizer;
    1112
     
    2627 * Cannot be used as the only NamingService! Be sure any naming service hosts
    2728 * are in hosts.txt.
     29 * Supports caching, b32, and b64.
    2830 *
    2931 * Sample config to put in configadvanced.jsp (restart required):
     
    3436 *
    3537 */
    36 public class EepGetNamingService extends NamingService {
     38public class EepGetNamingService extends DummyNamingService {
    3739
    3840    private final static String PROP_EEPGET_LIST = "i2p.naming.eepget.list";
     
    6062   
    6163    @Override
    62     public Destination lookup(String hostname) {
    63         // If it's long, assume it's a key.
    64         if (hostname.length() >= DEST_SIZE)
    65             return lookupBase64(hostname);
     64    public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
     65        Destination d = super.lookup(hostname, null, null);
     66        if (d != null)
     67            return d;
    6668
    6769        hostname = hostname.toLowerCase();
    68 
    69         // If you want b32, chain with HostsTxtNamingService
    70         if (hostname.length() == 60 && hostname.endsWith(".b32.i2p"))
    71             return null;
    72 
    73         // check the cache
    74         Destination d = getCache(hostname);
    75         if (d != null)
    76             return d;
    7770
    7871        List URLs = getURLs();
     
    10497
    10598    // FIXME allow larger Dests for non-null Certs
    106     private static final int DEST_SIZE = 516;                    // Std. Base64 length (no certificate)
    10799    private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
    108100    private String fetchAddr(String url, String hostname) {
  • core/java/src/net/i2p/client/naming/ExecNamingService.java

    rb6a0426 rad24f14  
    66
    77import java.io.InputStream;
     8import java.util.Properties;
    89
    910import net.i2p.I2PAppContext;
     
    2829 * Can be used from MetaNamingService, (e.g. after HostsTxtNamingService),
    2930 * or as the sole naming service.
     31 * Supports caching, b32, and b64.
    3032 *
    3133 * Sample chained config to put in configadvanced.jsp (restart required):
     
    4143 *
    4244 */
    43 public class ExecNamingService extends NamingService {
     45public class ExecNamingService extends DummyNamingService {
    4446
    4547    private final static String PROP_EXEC_CMD = "i2p.naming.exec.command";
     
    6062   
    6163    @Override
    62     public Destination lookup(String hostname) {
    63         // If it's long, assume it's a key.
    64         if (hostname.length() >= DEST_SIZE)
    65             return lookupBase64(hostname);
     64    public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
     65        Destination d = super.lookup(hostname, null, null);
     66        if (d != null)
     67            return d;
    6668
    6769        hostname = hostname.toLowerCase();
    68 
    69         // If you want b32, chain with HostsTxtNamingService
    70         if (hostname.length() == 60 && hostname.endsWith(".b32.i2p"))
    71             return null;
    72 
    73         // check the cache
    74         Destination d = getCache(hostname);
    75         if (d != null)
    76             return d;
    7770
    7871        // lookup
     
    8881
    8982    // FIXME allow larger Dests for non-null Certs
    90     private static final int DEST_SIZE = 516;                    // Std. Base64 length (no certificate)
    9183    private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
    9284    private String fetchAddr(String hostname) {
  • core/java/src/net/i2p/client/naming/HostsTxtNamingService.java

    rb6a0426 rad24f14  
    88package net.i2p.client.naming;
    99
    10 import java.io.BufferedReader;
    11 import java.io.File;
    12 import java.io.FileInputStream;
    13 import java.io.InputStreamReader;
    14 import java.io.IOException;
    1510import java.util.ArrayList;
    16 import java.util.Iterator;
    1711import java.util.List;
    1812import java.util.Properties;
    19 import java.util.Set;
    2013import java.util.StringTokenizer;
    2114
    2215import net.i2p.I2PAppContext;
    23 import net.i2p.data.DataFormatException;
    24 import net.i2p.data.DataHelper;
    2516import net.i2p.data.Destination;
    26 import net.i2p.data.Hash;
    27 import net.i2p.util.Log;
    2817
    2918/**
    30  * A naming service based on the "hosts.txt" file.
     19 * A naming service based on multiple "hosts.txt" files.
     20 * Supports .b32.i2p and {b64} lookups.
     21 * Supports caching.
     22 * All host names are converted to lower case.
    3123 */
    32 public class HostsTxtNamingService extends NamingService {
     24public class HostsTxtNamingService extends MetaNamingService {
    3325
    3426    /**
     
    3830     *
    3931     */
    40     public HostsTxtNamingService(I2PAppContext context) { super(context); }
    41     private HostsTxtNamingService() { super(null); }
     32    public HostsTxtNamingService(I2PAppContext context) {
     33        super(context, null);
     34        for (String name : getFilenames()) {
     35            addNamingService(new SingleFileNamingService(context, name), false);
     36        }
     37    }
    4238   
    4339    /**
     
    4642     */
    4743    public final static String PROP_HOSTS_FILE = "i2p.hostsfilelist";
    48     public final static String PROP_B32 = "i2p.naming.hostsTxt.useB32";
    4944
    50     /** default hosts.txt filename */
     45    /** default hosts.txt filenames */
    5146    public final static String DEFAULT_HOSTS_FILE =
    5247        "privatehosts.txt,userhosts.txt,hosts.txt";
    5348
    54     private final static Log _log = new Log(HostsTxtNamingService.class);
    55 
    56     private List getFilenames() {
     49    private List<String> getFilenames() {
    5750        String list = _context.getProperty(PROP_HOSTS_FILE, DEFAULT_HOSTS_FILE);
    5851        StringTokenizer tok = new StringTokenizer(list, ",");
    59         List rv = new ArrayList(tok.countTokens());
     52        List<String> rv = new ArrayList(tok.countTokens());
    6053        while (tok.hasMoreTokens())
    6154            rv.add(tok.nextToken());
     
    6356    }
    6457   
    65     private static final int BASE32_HASH_LENGTH = 52;   // 1 + Hash.HASH_LENGTH * 8 / 5
     58    @Override
     59    public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
     60        // If it's long, assume it's a key.
     61        if (hostname.length() >= DEST_SIZE)
     62            return lookupBase64(hostname);
     63        return super.lookup(hostname.toLowerCase(), lookupOptions, storedOptions);
     64    }
    6665
    6766    @Override
    68     public Destination lookup(String hostname) {
    69         Destination d = getCache(hostname);
    70         if (d != null)
    71             return d;
    72 
    73         // If it's long, assume it's a key.
    74         if (hostname.length() >= 516) {
    75             d = lookupBase64(hostname);
    76             // What the heck, cache these too
    77             putCache(hostname, d);
    78             return d;
    79         }
    80 
    81         // Try Base32 decoding
    82         if (hostname.length() == BASE32_HASH_LENGTH + 8 && hostname.endsWith(".b32.i2p") &&
    83             Boolean.valueOf(_context.getProperty(PROP_B32, "true")).booleanValue()) {
    84             d = LookupDest.lookupBase32Hash(_context, hostname.substring(0, BASE32_HASH_LENGTH));
    85             if (d != null) {
    86                 putCache(hostname, d);
    87                 return d;
    88             }
    89         }
    90 
    91         List filenames = getFilenames();
    92         for (int i = 0; i < filenames.size(); i++) {
    93             String hostsfile = (String)filenames.get(i);
    94             try {
    95                 File f = new File(_context.getRouterDir(), hostsfile);
    96                 if ( (f.exists()) && (f.canRead()) ) {
    97                     String key = getKey(f, hostname.toLowerCase());
    98                     if ( (key != null) && (key.trim().length() > 0) ) {
    99                         d = lookupBase64(key);
    100                         putCache(hostname, d);
    101                         return d;
    102                     }
    103                    
    104                 } else {
    105                     _log.warn("Hosts file " + hostsfile + " does not exist.");
    106                 }
    107             } catch (Exception ioe) {
    108                 _log.error("Error loading hosts file " + hostsfile, ioe);
    109             }
    110             // not found, continue to the next file
    111         }
    112         return null;
    113     }
    114    
    115     @Override
    116     public String reverseLookup(Destination dest) {
    117         String destkey = dest.toBase64();
    118         List filenames = getFilenames();
    119         for (int i = 0; i < filenames.size(); i++) {
    120             String hostsfile = (String)filenames.get(i);
    121             Properties hosts = new Properties();
    122             try {
    123                 File f = new File(_context.getRouterDir(), hostsfile);
    124                 if ( (f.exists()) && (f.canRead()) ) {
    125                     DataHelper.loadProps(hosts, f, true);
    126                     Set keyset = hosts.keySet();
    127                     Iterator iter = keyset.iterator();
    128                     while (iter.hasNext()) {
    129                         String host = (String)iter.next();
    130                         String key = hosts.getProperty(host);
    131                         if (destkey.equals(key))
    132                             return host;
    133                     }
    134                 }
    135             } catch (Exception ioe) {
    136                 _log.error("Error loading hosts file " + hostsfile, ioe);
    137             }
    138         }
    139         return null;
     67    public boolean put(String hostname, Destination d, Properties options) {
     68        return super.put(hostname.toLowerCase(), d, options);
    14069    }
    14170
    142     /** @deprecated unused */
    14371    @Override
    144     public String reverseLookup(Hash h) {
    145         List filenames = getFilenames();
    146         for (int i = 0; i < filenames.size(); i++) {
    147             String hostsfile = (String)filenames.get(i);
    148             Properties hosts = new Properties();
    149             try {
    150                 File f = new File(_context.getRouterDir(), hostsfile);
    151                 if ( (f.exists()) && (f.canRead()) ) {
    152                     DataHelper.loadProps(hosts, f, true);
    153                     Set keyset = hosts.keySet();
    154                     Iterator iter = keyset.iterator();
    155                     while (iter.hasNext()) {
    156                         String host = (String)iter.next();
    157                         String key = hosts.getProperty(host);
    158                         try {
    159                             Destination destkey = new Destination();
    160                             destkey.fromBase64(key);
    161                             if (h.equals(destkey.calculateHash()))
    162                                 return host;
    163                         } catch (DataFormatException dfe) {}
    164                     }
    165                 }
    166             } catch (Exception ioe) {
    167                 _log.error("Error loading hosts file " + hostsfile, ioe);
    168             }
    169         }
    170         return null;
     72    public boolean putIfAbsent(String hostname, Destination d, Properties options) {
     73        return super.putIfAbsent(hostname.toLowerCase(), d, options);
    17174    }
    17275
    173     /**
    174      *  Better than DataHelper.loadProps(), doesn't load the whole file into memory,
    175      *  and stops when it finds a match.
    176      *
    177      *  @param host lower case
    178      *  @since 0.7.13
    179      */
    180     private static String getKey(File file, String host) throws IOException {
    181         BufferedReader in = null;
    182         try {
    183             in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"), 16*1024);
    184             String line = null;
    185             while ( (line = in.readLine()) != null) {
    186                 if (!line.toLowerCase().startsWith(host + '='))
    187                     continue;
    188                 if (line.indexOf('#') > 0)  // trim off any end of line comment
    189                     line = line.substring(0, line.indexOf('#')).trim();
    190                 int split = line.indexOf('=');
    191                 return line.substring(split+1);   //.trim() ??????????????
    192             }
    193         } finally {
    194             if (in != null) try { in.close(); } catch (IOException ioe) {}
    195         }
    196         return null;
     76    @Override
     77    public boolean remove(String hostname, Properties options) {
     78        return super.remove(hostname.toLowerCase(), options);
    19779    }
    19880}
  • core/java/src/net/i2p/client/naming/MetaNamingService.java

    rb6a0426 rad24f14  
    33import java.lang.reflect.Constructor;
    44import java.util.ArrayList;
     5import java.util.Collections;
    56import java.util.Iterator;
    67import java.util.List;
     8import java.util.Properties;
    79import java.util.StringTokenizer;
     10import java.util.concurrent.CopyOnWriteArrayList;
    811
    912import net.i2p.I2PAppContext;
    1013import net.i2p.data.Destination;
    1114
    12 public class MetaNamingService extends NamingService {
     15/**
     16 * A naming service of multiple naming services.
     17 * Supports .b32.i2p and {b64} lookups.
     18 * Supports caching.
     19 */
     20public class MetaNamingService extends DummyNamingService {
    1321   
    1422    private final static String PROP_NAME_SERVICES = "i2p.nameservicelist";
    1523    private final static String DEFAULT_NAME_SERVICES =
    16         "net.i2p.client.naming.PetNameNamingService,net.i2p.client.naming.HostsTxtNamingService";
    17     private List _services;
     24        "net.i2p.client.naming.HostsTxtNamingService";
     25
     26    protected final List<NamingService> _services;
    1827   
    1928    public MetaNamingService(I2PAppContext context) {
    2029        super(context);
    21        
    2230        String list = _context.getProperty(PROP_NAME_SERVICES, DEFAULT_NAME_SERVICES);
    2331        StringTokenizer tok = new StringTokenizer(list, ",");
    24         _services = new ArrayList(tok.countTokens());
     32        _services = new CopyOnWriteArrayList();
    2533        while (tok.hasMoreTokens()) {
    2634            try {
    2735                Class cls = Class.forName(tok.nextToken());
    2836                Constructor con = cls.getConstructor(new Class[] { I2PAppContext.class });
    29                 _services.add(con.newInstance(new Object[] { context }));
     37                addNamingService((NamingService)con.newInstance(new Object[] { context }), false);
    3038            } catch (Exception ex) {
    31                 _services.add(new DummyNamingService(context)); // fallback
     39            }
     40        }
     41    }
     42   
     43    /**
     44     *  @param if non-null, services to be added. If null, this will only handle b32 and b64.
     45     *  @since 0.8.5
     46     */
     47    public MetaNamingService(I2PAppContext context, List<NamingService> services) {
     48        super(context);
     49        _services = new CopyOnWriteArrayList();
     50        if (services != null) {
     51            for (NamingService ns : services) {
     52                addNamingService(ns, false);
    3253            }
    3354        }
     
    3556   
    3657    @Override
    37     public Destination lookup(String hostname) {
    38         Iterator iter = _services.iterator();
    39         while (iter.hasNext()) {
    40             NamingService ns = (NamingService)iter.next();
    41             Destination dest = ns.lookup(hostname);
    42             if (dest != null) {
    43                 return dest;
     58    public boolean addNamingService(NamingService ns, boolean head) {
     59        if (head)
     60            _services.add(0, ns);
     61        else
     62            _services.add(ns);
     63        return true;
     64    }
     65
     66    @Override
     67    public List<NamingService> getNamingServices() {
     68        return Collections.unmodifiableList(_services);
     69    }
     70
     71    @Override
     72    public boolean removeNamingService(NamingService ns) {
     73        return  _services.remove(ns);
     74    }
     75
     76    @Override
     77    public void registerListener(NamingServiceListener nsl) {
     78        for (NamingService ns : _services) {
     79            ns.registerListener(nsl);
     80        }
     81    }
     82
     83    @Override
     84    public void unregisterListener(NamingServiceListener nsl) {
     85        for (NamingService ns : _services) {
     86            ns.unregisterListener(nsl);
     87        }
     88    }
     89
     90    @Override
     91    public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
     92        Destination d = super.lookup(hostname, null, null);
     93        if (d != null)
     94            return d;
     95
     96        for (NamingService ns : _services) {
     97            d = ns.lookup(hostname, lookupOptions, storedOptions);
     98            if (d != null) {
     99                putCache(hostname, d);
     100                return d;
    44101            }
    45102        }
    46         return lookupBase64(hostname);
     103        return null;
    47104    }
    48105   
    49106    @Override
    50     public String reverseLookup(Destination dest) {
    51         Iterator iter = _services.iterator();
    52         while (iter.hasNext()) {
    53             NamingService ns = (NamingService)iter.next();
    54             String hostname = ns.reverseLookup(dest);
    55             if (hostname != null) {
    56                 return hostname;
     107    public String reverseLookup(Destination dest, Properties options) {
     108        for (NamingService ns : _services) {
     109            String host = ns.reverseLookup(dest, options);
     110            if (host != null) {
     111                return host;
    57112            }
    58113        }
     
    60115    }
    61116
     117    /**
     118     *  Stores in the last service
     119     */
     120    @Override
     121    public boolean put(String hostname, Destination d, Properties options) {
     122        if (_services.isEmpty())
     123            return false;
     124        boolean rv = _services.get(_services.size() - 1).put(hostname, d, options);
     125        // overwrite any previous entry in case it changed
     126        if (rv)
     127            putCache(hostname, d);
     128        return rv;
     129    }
     130
     131    /**
     132     *  Stores in the last service
     133     */
     134    @Override
     135    public boolean putIfAbsent(String hostname, Destination d, Properties options) {
     136        if (_services.isEmpty())
     137            return false;
     138        return _services.get(_services.size() - 1).putIfAbsent(hostname, d, options);
     139    }
     140
     141    /**
     142     *  Removes from all services
     143     */
     144    @Override
     145    public boolean remove(String hostname, Properties options) {
     146        boolean rv = false;
     147        for (NamingService ns : _services) {
     148            if (ns.remove(hostname, options))
     149                rv = true;
     150        }
     151        if (rv)
     152            removeCache(hostname);
     153        return rv;
     154    }
    62155}
  • core/java/src/net/i2p/client/naming/NamingService.java

    rb6a0426 rad24f14  
    1010import java.lang.reflect.Constructor;
    1111import java.util.ArrayList;
    12 import java.util.HashMap;
     12import java.util.Collections;
    1313import java.util.Iterator;
     14import java.util.List;
    1415import java.util.Map;
     16import java.util.Properties;
     17import java.util.Set;
     18import java.util.concurrent.CopyOnWriteArraySet;
    1519
    1620import net.i2p.I2PAppContext;
     
    2630
    2731    private final static Log _log = new Log(NamingService.class);
    28     protected I2PAppContext _context;
    29     private /* FIXME final FIXME */ HashMap _cache;
     32    protected final I2PAppContext _context;
     33    protected final Set<NamingServiceListener> _listeners;
    3034
    3135    /** what classname should be used as the naming service impl? */
    3236    public static final String PROP_IMPL = "i2p.naming.impl";
    3337    private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService";
    34 
    35     protected static final int CACHE_MAX_SIZE = 16;
    36 
    3738   
    3839    /**
     
    4445    protected NamingService(I2PAppContext context) {
    4546        _context = context;
    46         _cache = new HashMap(CACHE_MAX_SIZE);
    47     }
    48     private NamingService() { // nop
     47        _listeners = new CopyOnWriteArraySet();
    4948    }
    5049   
     
    5453     * <code>null</code> if name is unknown.
    5554     */
    56     public abstract Destination lookup(String hostname);
     55    public Destination lookup(String hostname) {
     56        return lookup(hostname, null, null);
     57    }
    5758
    5859    /**
     
    6263     * <code>null</code> if no reverse lookup is possible.
    6364     */
    64     public String reverseLookup(Destination dest) { return null; };
     65    public String reverseLookup(Destination dest) {
     66        return reverseLookup(dest, null);
     67    }
    6568
    6669    /** @deprecated unused */
    67     public String reverseLookup(Hash h) { return null; };
     70    public String reverseLookup(Hash h) { return null; }
    6871
    6972    /**
     
    8386    }
    8487
     88    ///// New API Starts Here
     89
     90    /**
     91     *  @return Class simple name by default
     92     *  @since 0.8.5
     93     */
     94    public String getName() {
     95        return getClass().getSimpleName();
     96    }
     97
     98    /**
     99     *  @return NamingService-specific options or null
     100     *  @since 0.8.5
     101     */
     102    public Properties getConfiguration() {
     103        return null;
     104    }
     105
     106    /**
     107     *  @return success
     108     *  @since 0.8.5
     109     */
     110    public boolean setConfiguration(Properties p) {
     111        return true;
     112    }
     113
     114    // These are for daisy chaining (MetaNamingService)
     115
     116    /**
     117     *  @return chained naming services or null
     118     *  @since 0.8.5
     119     */
     120    public List<NamingService> getNamingServices() {
     121        return null;
     122    }
     123
     124    /**
     125     *  @return parent naming service or null if this is the root
     126     *  @since 0.8.5
     127     */
     128    public NamingService getParent() {
     129        return null;
     130    }
     131
     132    /**
     133     * Only for chaining-capable NamingServices. Add to end of the list.
     134     * @return success
     135     */
     136    public boolean addNamingService(NamingService ns) {
     137        return addNamingService(ns, false);
     138    }
     139
     140
     141    /**
     142     * Only for chaining-capable NamingServices
     143     * @param head or tail
     144     * @return success
     145     */
     146    public boolean addNamingService(NamingService ns, boolean head) {
     147        return false;
     148    }
     149
     150    /**
     151     *  Only for chaining-capable NamingServices
     152     *  @return success
     153     *  @since 0.8.5
     154     */
     155    public boolean removeNamingService(NamingService ns) {
     156        return false;
     157    }
     158
     159    // options would be used to specify public / private / master ...
     160    // or should we just daisy chain 3 HostsTxtNamingServices ?
     161    // that might be better... then addressbook only talks to the 'router' HostsTxtNamingService
     162
     163    /**
     164     *  @return number of entries or -1 if unknown
     165     *  @since 0.8.5
     166     */
     167    public int size() {
     168        return size(null);
     169    }
     170
     171    /**
     172     *  @param options NamingService-specific, can be null
     173     *  @return number of entries (matching the options if non-null) or -1 if unknown
     174     *  @since 0.8.5
     175     */
     176    public int size(Properties options) {
     177        return -1;
     178    }
     179
     180    /**
     181     *  @return all mappings
     182     *          or empty Map if none;
     183     *          Returned Map is not necessarily sorted, implementation dependent
     184     *  @since 0.8.5
     185     */
     186    public Map<String, Destination> getEntries() {
     187        return getEntries(null);
     188    }
     189
     190    /**
     191     *  @param options NamingService-specific, can be null
     192     *  @return all mappings (matching the options if non-null)
     193     *          or empty Map if none;
     194     *          Returned Map is not necessarily sorted, implementation dependent
     195     *  @since 0.8.5
     196     */
     197    public Map<String, Destination> getEntries(Properties options) {
     198        return Collections.EMPTY_MAP;
     199    }
     200
     201    /**
     202     *  This may be more or less efficient than getEntries()
     203     *  @param options NamingService-specific, can be null
     204     *  @return all mappings (matching the options if non-null)
     205     *          or empty Map if none;
     206     *          Returned Map is not necessarily sorted, implementation dependent
     207     *  @since 0.8.5
     208     */
     209    public Map<String, String> getBase64Entries(Properties options) {
     210        return Collections.EMPTY_MAP;
     211    }
     212
     213    /**
     214     *  @return all known host names
     215     *          or empty Set if none;
     216     *          Returned Set is not necessarily sorted, implementation dependent
     217     *  @since 0.8.5
     218     */
     219    public Set<String> getNames() {
     220        return getNames(null);
     221    }
     222
     223    /**
     224     *  @param options NamingService-specific, can be null
     225     *  @return all known host names (matching the options if non-null)
     226     *          or empty Set if none;
     227     *          Returned Set is not necessarily sorted, implementation dependent
     228     *  @since 0.8.5
     229     */
     230    public Set<String> getNames(Properties options) {
     231        return Collections.EMPTY_SET;
     232    }
     233
     234    /**
     235     *  @return success
     236     *  @since 0.8.5
     237     */
     238    public boolean put(String hostname, Destination d) {
     239        return put(hostname, d, null);
     240    }
     241
     242    /**
     243     *  @param options NamingService-specific, can be null
     244     *  @return success
     245     *  @since 0.8.5
     246     */
     247    public boolean put(String hostname, Destination d, Properties options) {
     248        return false;
     249    }
     250
     251    /**
     252     *  Fails if entry previously exists
     253     *  @return success
     254     *  @since 0.8.5
     255     */
     256    public boolean putIfAbsent(String hostname, Destination d) {
     257        return putIfAbsent(hostname, d, null);
     258    }
     259
     260    /**
     261     *  Fails if entry previously exists
     262     *  @param options NamingService-specific, can be null
     263     *  @return success
     264     *  @since 0.8.5
     265     */
     266    public boolean putIfAbsent(String hostname, Destination d, Properties options) {
     267        return false;
     268    }
     269
     270    /**
     271     *  @param options NamingService-specific, can be null
     272     *  @return success
     273     *  @since 0.8.5
     274     */
     275    public boolean putAll(Map<String, Destination> entries, Properties options) {
     276        boolean rv = true;
     277        for (Map.Entry<String, Destination> entry : entries.entrySet()) {
     278            if (!put(entry.getKey(), entry.getValue(), options))
     279                rv = false;
     280        }
     281        return rv;
     282    }
     283
     284    /**
     285     *  Fails if entry did not previously exist
     286     *  @param d may be null if only options are changing
     287     *  @param options NamingService-specific, can be null
     288     *  @return success
     289     *  @since 0.8.5
     290     */
     291    public boolean update(String hostname, Destination d, Properties options) {
     292        return false;
     293    }
     294
     295    /**
     296     *  @return success
     297     *  @since 0.8.5
     298     */
     299    public boolean remove(String hostname) {
     300        return remove(hostname, null);
     301    }
     302
     303    /**
     304     *  @param options NamingService-specific, can be null
     305     *  @return success
     306     *  @since 0.8.5
     307     */
     308    public boolean remove(String hostname, Properties options) {
     309        return false;
     310    }
     311
     312    /**
     313     *  Ask the NamingService to update its database
     314     *  Should this be a separate interface? This is what addressbook needs
     315     *  @param options NamingService-specific, can be null
     316     *  @since 0.8.5
     317     */
     318    public void requestUpdate(Properties options) {}
     319
     320    /**
     321     *  @since 0.8.5
     322     */
     323    public void registerListener(NamingServiceListener nsl) {
     324        _listeners.add(nsl);
     325    }
     326
     327    /**
     328     *  @since 0.8.5
     329     */
     330    public void unregisterListener(NamingServiceListener nsl) {
     331        _listeners.remove(nsl);
     332    }
     333
     334    /**
     335     *  Same as lookup(hostname) but with in and out options
     336     *  Note that whether this (and lookup(hostname)) resolve B32 addresses is
     337     *  NamingService-specific.
     338     *  @param lookupOptions input parameter, NamingService-specific, can be null
     339     *  @param storedOptions output parameter, NamingService-specific, any stored properties will be added if non-null
     340     *  @return dest or null
     341     *  @since 0.8.5
     342     */
     343    public abstract Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions);
     344
     345    /**
     346     *  Same as reverseLookup(dest) but with options
     347     *  @param options NamingService-specific, can be null
     348     *  @return host name or null
     349     *  @since 0.8.5
     350     */
     351    public String reverseLookup(Destination d, Properties options) {
     352        return null;
     353    }
     354
     355    /**
     356     *  Lookup a Base 32 address. This may require the router to fetch the LeaseSet,
     357     *  which may take quite a while.
     358     *  @param hostname must be {52 chars}.b32.i2p
     359     *  @param timeout in seconds; <= 0 means use router default
     360     *  @return dest or null
     361     *  @since 0.8.5
     362     */
     363    public Destination lookupBase32(String hostname, int timeout) {
     364        return null;
     365    }
     366
     367    /**
     368     *  Same as lookupB32 but with the SHA256 Hash precalculated
     369     *  @param timeout in seconds; <= 0 means use router default
     370     *  @return dest or null
     371     *  @since 0.8.5
     372     */
     373    public Destination lookup(Hash hash, int timeout) {
     374        return null;
     375    }
     376
     377    /**
     378     *  Parent will call when added.
     379     *  If this is the root naming service, the core will start it.
     380     *  Should not be called by others.
     381     *  @since 0.8.5
     382     */
     383    public void start() {}
     384
     385    /**
     386     *  Parent will call when removed.
     387     *  If this is the root naming service, the core will stop it.
     388     *  Should not be called by others.
     389     *  @since 0.8.5
     390     */
     391    public void stop() {}
     392
     393    //// End New API
     394
    85395    /**
    86396     * Get a naming service instance. This method ensures that there
     
    97407            instance = (NamingService)con.newInstance(new Object[] { context });
    98408        } catch (Exception ex) {
    99             _log.error("Cannot loadNaming service implementation", ex);
     409            _log.error("Cannot load naming service " + impl, ex);
    100410            instance = new DummyNamingService(context); // fallback
    101411        }
     
    103413    }
    104414
    105     /**
    106      *  Provide basic caching for the service
    107      *  The service may override the age and/or size limit
    108      */
    109     /** Don't know why a dest would ever change but keep this short anyway */
    110     protected static final long CACHE_MAX_AGE = 7*60*1000;
    111 
    112     private class CacheEntry {
    113         public Destination dest;
    114         public long exp;
    115         public CacheEntry(Destination d) {
    116             dest = d;
    117             exp = _context.clock().now() + CACHE_MAX_AGE;
    118         }
    119         public boolean isExpired() {
    120             return exp < _context.clock().now();
    121         }
    122     }
    123 
    124     /**
    125      * Clean up when full.
    126      * Don't bother removing old entries unless full.
    127      * Caller must synchronize on _cache.
    128      */
    129     private void cacheClean() {
    130         if (_cache.size() < CACHE_MAX_SIZE)
    131             return;
    132         boolean full = true;
    133         Object oldestKey = null;
    134         long oldestExp = Long.MAX_VALUE;
    135         ArrayList deleteList = new ArrayList(CACHE_MAX_SIZE);
    136         for (Iterator iter = _cache.entrySet().iterator(); iter.hasNext(); ) {
    137             Map.Entry entry = (Map.Entry) iter.next();
    138             CacheEntry ce = (CacheEntry) entry.getValue();
    139             if (ce.isExpired()) {
    140                 deleteList.add(entry.getKey());
    141                 full = false;
    142                 continue;
    143             }
    144             if (oldestKey == null || ce.exp < oldestExp) {
    145                 oldestKey = entry.getKey();
    146                 oldestExp = ce.exp;
    147             }
    148         }
    149         if (full && oldestKey != null)
    150             deleteList.add(oldestKey);
    151         for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
    152             _cache.remove(iter.next());
    153         }
    154     }
    155 
    156     protected void putCache(String s, Destination d) {
    157         if (d == null)
    158             return;
    159         synchronized (_cache) {
    160             _cache.put(s, new CacheEntry(d));
    161             cacheClean();
    162         }
    163     }
    164 
    165     protected Destination getCache(String s) {
    166         synchronized (_cache) {
    167             CacheEntry ce = (CacheEntry) _cache.get(s);
    168             if (ce == null)
    169                 return null;
    170             if (ce.isExpired()) {
    171                 _cache.remove(s);
    172                 return null;
    173             }
    174             return ce.dest;
    175         }
    176     }
    177 
    178     /** @since 0.8.1 */
    179     public void clearCache() {
    180         synchronized (_cache) {
    181             _cache.clear();
    182         }
    183     }
    184415}
Note: See TracChangeset for help on using the changeset viewer.