Changeset 9eefe1e


Ignore:
Timestamp:
Jan 27, 2014 4:47:22 PM (6 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
b2f4fde
Parents:
5d32224 (diff), b91f041 (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.zzz.i2cp' (head d4ac8162a4ba299ac912640f19076c3c90afdc67)

to branch 'i2p.i2p' (head adc5102c93383e01c74b87f04449dc9c307f6e75)

Files:
3 added
21 edited

Legend:

Unmodified
Added
Removed
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java

    r5d32224 r9eefe1e  
    4747import java.util.List;
    4848import java.util.Locale;
     49import java.util.Map;
    4950import java.util.Properties;
    5051import java.util.Set;
     
    5859import net.i2p.client.I2PClientFactory;
    5960import net.i2p.client.I2PSession;
     61import net.i2p.client.I2PSessionException;
     62import net.i2p.client.I2PSimpleClient;
    6063import net.i2p.client.naming.NamingService;
    6164import net.i2p.data.Base64;
     
    6972import net.i2p.util.EventDispatcherImpl;
    7073import net.i2p.util.Log;
     74import net.i2p.util.OrderedProperties;
    7175
    7276/**
     
    8892    public boolean ownDest = false;
    8993
    90     /** the I2CP port */
     94    /** the I2CP port, non-null */
    9195    public String port = System.getProperty(I2PClient.PROP_TCP_PORT, "7654");
    92     /** the I2CP host */
     96    /** the I2CP host, non-null */
    9397    public String host = System.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
    9498    /** the listen-on host. Sadly the listen-on port does not have a field. */
     
    169173                BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
    170174                while (true) {
    171                     System.out.print("I2PTunnel>");
     175                    System.out.print("I2PTunnel> ");
    172176                    String cmd = r.readLine();
    173177                    if (cmd == null) break;
     
    294298        } else if (cmdname.equals("owndest")) {
    295299            runOwnDest(args, l);
     300        } else if (cmdname.equals("auth")) {
     301            runAuth(args, l);
    296302        } else {
    297303            l.log("Unknown command [" + cmdname + "]");
     
    309315        l.log("Command list:");
    310316        // alphabetical please...
    311         l.log("client <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
    312         l.log("clientoptions[ key=value]*");
    313         l.log("close [forced] <jobnumber>|all");
    314         l.log("config <i2phost> <i2pport>");
    315         l.log("connectclient <port> [<sharedClient>] [<proxy>]");
    316         l.log("genkeys <privkeyfile> [<pubkeyfile>]");
    317         l.log("gentextkeys");
    318         l.log("httpbidirserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
    319         l.log("httpclient <port> [<sharedClient>] [<proxy>]");
    320         l.log("httpserver <host> <port> <spoofedhost> <privkeyfile>");
    321         l.log("ircclient <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
    322         l.log("list");
    323         l.log("listen_on <ip>");
    324         l.log("lookup <name>");
    325         l.log("owndest yes|no");
    326         l.log("ping <args>");
    327         l.log("quit");
    328         l.log("read_timeout <msecs>");
    329         l.log("run <commandfile>");
    330         l.log("server <host> <port> <privkeyfile>");
    331         l.log("textserver <host> <port> <privkey>");
     317        l.log("  auth <username> <password>");
     318        l.log("  client <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
     319        l.log("  clientoptions [-acx] [key=value ]*");
     320        l.log("  close [forced] <jobnumber>|all");
     321        l.log("  config [-s] <i2phost> <i2pport>");
     322        l.log("  connectclient <port> [<sharedClient>] [<proxy>]");
     323        l.log("  genkeys <privkeyfile> [<pubkeyfile>]");
     324        l.log("  gentextkeys");
     325        l.log("  httpbidirserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
     326        l.log("  httpclient <port> [<sharedClient>] [<proxy>]");
     327        l.log("  httpserver <host> <port> <spoofedhost> <privkeyfile>");
     328        l.log("  ircclient <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
     329        l.log("  list");
     330        l.log("  listen_on <ip>");
     331        l.log("  lookup <name>");
     332        l.log("  owndest yes|no");
     333        l.log("  ping <args>");
     334        l.log("  quit");
     335        l.log("  read_timeout <msecs>");
     336        l.log("  run <commandfile>");
     337        l.log("  server <host> <port> <privkeyfile>");
     338        l.log("  textserver <host> <port> <privkey>");
    332339    }
    333340   
     
    346353     */
    347354    public void runClientOptions(String args[], Logging l) {
    348         _clientOptions.clear();
    349         if (args != null) {
    350             for (int i = 0; i < args.length; i++) {
     355        if (args != null && args.length > 0) {
     356            int i = 0;
     357            if (args[0].equals("-a")) {
     358                i++;
     359            } else if (args[0].equals("-c")) {
     360                _clientOptions.clear();
     361                l.log("Client options cleared");
     362                return;
     363            } else if (args[0].equals("-x")) {
     364                i++;
     365                for ( ; i < args.length; i++) {
     366                     if (_clientOptions.remove(args[i]) != null)
     367                        l.log("Removed " + args[i]);
     368                }
     369                return;
     370            } else {
     371                _clientOptions.clear();
     372            }
     373            for ( ; i < args.length; i++) {
    351374                int index = args[i].indexOf('=');
    352375                if (index <= 0) continue;
     
    354377                String val = args[i].substring(index+1);
    355378                _clientOptions.setProperty(key, val);
     379            }
     380        } else {
     381            l.log("Usage:");
     382            l.log("  clientoptions [key=value ]*     // sets current options");
     383            l.log("  clientoptions -a [key=value ]*  // adds to current options");
     384            l.log("  clientoptions -c                // clears current options");
     385            l.log("  clientoptions -x [key ]*        // removes listed options");
     386            l.log("Current options:");
     387            Properties p = new OrderedProperties();
     388            p.putAll(_clientOptions);
     389            for (Map.Entry<Object, Object> e : p.entrySet()) {
     390                l.log("  [" + e.getKey() + "] = [" + e.getValue() + ']');
    356391            }
    357392        }
     
    11481183     */
    11491184    private void runConfig(String args[], Logging l) {
     1185        if (args.length >= 2) {
     1186            int i = 0;
     1187            if (args[0].equals("-s")) {
     1188                _clientOptions.setProperty("i2cp.SSL", "true");
     1189                i++;
     1190            } else {
     1191                _clientOptions.remove("i2cp.SSL");
     1192            }
     1193            host = args[i++];
     1194            listenHost = host;
     1195            port = args[i];
     1196            notifyEvent("configResult", "ok");
     1197        } else {
     1198            l.log("Usage:");
     1199            l.log("  config [-s] <i2phost> <i2pport>");
     1200            l.log("  sets the connection to the i2p router.");
     1201            l.log("Current setting:");
     1202            boolean ssl = Boolean.parseBoolean(_clientOptions.getProperty("i2cp.SSL"));
     1203            l.log("  " + host + ' ' + port + (ssl ? " SSL" : ""));
     1204            notifyEvent("configResult", "error");
     1205        }
     1206    }
     1207
     1208    /**
     1209     * Specify the i2cp username and password
     1210     *
     1211     * @param args {username, password}
     1212     * @param l logger to receive events and output
     1213     * @since 0.9.10
     1214     */
     1215    private void runAuth(String args[], Logging l) {
    11501216        if (args.length == 2) {
    1151             host = args[0];
    1152             listenHost = host;
    1153             port = args[1];
    1154             notifyEvent("configResult", "ok");
    1155         } else {
    1156             l.log("config <i2phost> <i2pport>");
    1157             l.log("  sets the connection to the i2p router.");
    1158             notifyEvent("configResult", "error");
     1217            _clientOptions.setProperty("i2cp.username", args[0]);
     1218            _clientOptions.setProperty("i2cp.password", args[1]);
     1219        } else {
     1220            l.log("Usage:");
     1221            l.log("  auth <username> <password>");
     1222            l.log("  Sets the i2cp credentials");
    11591223        }
    11601224    }
     
    14161480        } else {
    14171481            try {
    1418                 Destination dest = destFromName(args[0]);
     1482                boolean ssl = Boolean.parseBoolean(_clientOptions.getProperty("i2cp.SSL"));
     1483                String user = _clientOptions.getProperty("i2cp.username");
     1484                String pw = _clientOptions.getProperty("i2cp.password");
     1485                Destination dest = destFromName(args[0], host, port, ssl, user, pw);
    14191486                if (dest == null) {
    1420                     l.log("Unknown host");
     1487                    l.log("Unknown host: " + args[0]);
    14211488                    notifyEvent("lookupResult", "unkown host");
    14221489                } else {
     
    14251492                }
    14261493            } catch (DataFormatException dfe) {
    1427                 l.log("Unknown or invalid host");
     1494                l.log("Unknown or invalid host: " + args[0]);
    14281495                notifyEvent("lookupResult", "invalid host");
    14291496            }
     
    14421509    private void runPing(String allargs, Logging l) {
    14431510        if (allargs.length() != 0) {
    1444             I2PTunnelTask task;
    1445             // pings always use the main destination
    1446             task = new I2Ping(allargs, l, false, this, this);
     1511            _clientOptions.setProperty(I2Ping.PROP_COMMAND, allargs);
     1512            I2PTunnelTask task = new I2Ping(l, ownDest, this, this);
    14471513            addtask(task);
    14481514            notifyEvent("pingTaskId", Integer.valueOf(task.getId()));
    14491515        } else {
    1450             l.log("ping <opts> <dest>");
     1516            l.log("ping <opts> <b64dest|host>");
    14511517            l.log("ping <opts> -h (pings all hosts in hosts.txt)");
    14521518            l.log("ping <opts> -l <destlistfile> (pings a list of hosts in a file)");
     
    14551521                  "     -m maxSimultaneousPings (default 10)\n" +
    14561522                  "     -n numberOfPings (default 3)\n" +
    1457                   "     -t timeout (ms, default 5000)\n");
     1523                  "     -t timeout (ms, default 30000)\n");
    14581524            l.log("   Tests communication with peers.\n");
    14591525            notifyEvent("pingTaskId", Integer.valueOf(-1));
     
    16001666     */
    16011667    public static Destination destFromName(String name) throws DataFormatException {
     1668        return destFromName(name, null, null, false, null, null);
     1669    }
     1670
     1671    /**
     1672     *  @param i2cpHost may be null
     1673     *  @param i2cpPort may be null
     1674     *  @param user may be null
     1675     *  @param pw may be null
     1676     *  @since 0.9.10
     1677     */
     1678    private static Destination destFromName(String name, String i2cpHost,
     1679                                            String i2cpPort, boolean isSSL,
     1680                                            String user, String pw) throws DataFormatException {
    16021681
    16031682        if ((name == null) || (name.trim().length() <= 0)) throw new DataFormatException("Empty destination provided");
     
    16431722        } else {
    16441723            // ask naming service
     1724            name = name.trim();
    16451725            NamingService inst = ctx.namingService();
    1646             return inst.lookup(name);
     1726            boolean b32 = name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p");
     1727            Destination d = null;
     1728            if (ctx.isRouterContext() || !b32) {
     1729                // Local lookup.
     1730                // Even though we could do b32 outside router ctx here,
     1731                // we do it below instead so we can set the host and port,
     1732                // which we can't do with lookup()
     1733                d = inst.lookup(name);
     1734                if (d != null || ctx.isRouterContext() || name.length() >= 516)
     1735                    return d;
     1736            }
     1737            // Outside router context only,
     1738            // try simple session to ask the router.
     1739            I2PClient client = new I2PSimpleClient();
     1740            Properties opts = new Properties();
     1741            if (i2cpHost != null)
     1742                opts.put(I2PClient.PROP_TCP_HOST, i2cpHost);
     1743            if (i2cpPort != null)
     1744                opts.put(I2PClient.PROP_TCP_PORT, i2cpPort);
     1745            opts.put("i2cp.SSL", Boolean.toString(isSSL));
     1746            if (user != null)
     1747                opts.put("i2cp.username", user);
     1748            if (pw != null)
     1749                opts.put("i2cp.password", pw);
     1750            I2PSession session = null;
     1751            try {
     1752                session = client.createSession(null, opts);
     1753                session.connect();
     1754                d = session.lookupDest(name);
     1755            } catch (I2PSessionException ise) {
     1756                if (log.shouldLog(Log.WARN))
     1757                    log.warn("Lookup via router failed", ise);
     1758            } finally {
     1759                if (session != null) {
     1760                    try { session.destroySession(); } catch (I2PSessionException ise) {}
     1761                }
     1762            }
     1763            return d;
    16471764        }
    16481765    }
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java

    r5d32224 r9eefe1e  
    5252    protected boolean _ownDest;
    5353
    54     protected Destination dest = null;
     54    protected Destination dest;
    5555    private int localPort;
    5656
    57     private boolean listenerReady = false;
     57    /**
     58     *  Protected for I2Ping since 0.9.10. Not for use outside package.
     59     */
     60    protected boolean listenerReady;
    5861
    5962    protected ServerSocket ss;
    6063
    6164    private final Object startLock = new Object();
    62     private boolean startRunning = false;
     65    private boolean startRunning;
    6366
    6467    // private Object closeLock = new Object();
     
    6972
    7073    // true if we are chained from a server.
    71     private boolean chained = false;
     74    private boolean chained;
    7275
    7376    /** how long to wait before dropping an idle thread */
     
    583586    }
    584587
    585     public final void run() {
     588    /**
     589     *  Non-final since 0.9.10.
     590     *  Any overrides must set listenerReady = true.
     591     */
     592    public void run() {
    586593        try {
    587594            InetAddress addr = getListenHost(l);
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java

    r5d32224 r9eefe1e  
    77import java.io.FileReader;
    88import java.io.IOException;
     9import java.net.Socket;
    910import java.util.ArrayList;
    1011import java.util.List;
     12import java.util.Locale;
    1113
    1214import net.i2p.I2PAppContext;
    1315import net.i2p.I2PException;
     16import net.i2p.client.I2PSession;
     17import net.i2p.client.I2PSessionException;
    1418import net.i2p.client.streaming.I2PSocketManager;
    1519import net.i2p.data.Destination;
     
    1822import net.i2p.util.Log;
    1923
    20 public class I2Ping extends I2PTunnelTask implements Runnable {
    21     private final static Log _log = new Log(I2Ping.class);
    22 
    23     private int PING_COUNT = 3;
     24/**
     25 *  Warning - not necessarily a stable API.
     26 *  Used by I2PTunnel CLI only. Consider this sample code.
     27 *  Not for use outside this package.
     28 */
     29public class I2Ping extends I2PTunnelClientBase {
     30
     31    public static final String PROP_COMMAND = "command";
     32
     33    private static final int PING_COUNT = 3;
    2434    private static final int CPING_COUNT = 5;
    25     private static final int PING_TIMEOUT = 5000;
     35    private static final int PING_TIMEOUT = 30*1000;
    2636
    2737    private static final long PING_DISTANCE = 1000;
     
    2939    private int MAX_SIMUL_PINGS = 10; // not really final...
    3040
    31     private boolean countPing = false;
    32     private boolean reportTimes = true;
    33 
    34     private I2PSocketManager sockMgr;
    35     private Logging l;
    36     private boolean finished = false;
    37     private String command;
    38     private long timeout = PING_TIMEOUT;
     41
     42    private volatile boolean finished;
    3943
    4044    private final Object simulLock = new Object();
    41     private int simulPings = 0;
    42     private long lastPingTime = 0;
    43 
    44     private final Object lock = new Object(), slock = new Object();
    45 
    46     //public I2Ping(String cmd, Logging l,
    47     //            boolean ownDest) {
    48     //  I2Ping(cmd, l, (EventDispatcher)null);
    49     //}
    50 
    51     public I2Ping(String cmd, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel) {
    52         super("I2Ping [" + cmd + "]", notifyThis, tunnel);
    53         this.l = l;
    54         command = cmd;
    55         synchronized (slock) {
    56             if (ownDest) {
    57                 sockMgr = I2PTunnelClient.buildSocketManager(tunnel);
    58             } else {
    59                 sockMgr = I2PTunnelClient.getSocketManager(tunnel);
    60             }
    61         }
    62         Thread t = new I2PAppThread(this);
    63         t.setName("Client");
    64         t.start();
    65         open = true;
    66     }
    67 
     45    private int simulPings;
     46    private long lastPingTime;
     47
     48    /**
     49     *  tunnel.getOptions must contain "command".
     50     *  @throws IllegalArgumentException if it doesn't
     51     */
     52    public I2Ping(Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel) {
     53        super(-1, ownDest, l, notifyThis, "I2Ping", tunnel);
     54        if (!tunnel.getClientOptions().containsKey(PROP_COMMAND)) {
     55            // todo clean up
     56            throw new IllegalArgumentException("Options does not contain " + PROP_COMMAND);
     57        }
     58    }
     59
     60    /**
     61     *  Overrides super. No client ServerSocket is created.
     62     */
     63    @Override
    6864    public void run() {
     65        // Notify constructor that port is ready
     66        synchronized (this) {
     67            listenerReady = true;
     68            notify();
     69        }
    6970        l.log("*** I2Ping results:");
    7071        try {
    71             runCommand(command);
     72            runCommand(getTunnel().getClientOptions().getProperty(PROP_COMMAND));
    7273        } catch (InterruptedException ex) {
    7374            l.log("*** Interrupted");
     
    7778        }
    7879        l.log("*** Finished.");
    79         synchronized (lock) {
    80             finished = true;
    81         }
     80        finished = true;
    8281        close(false);
    8382    }
    8483
    8584    public void runCommand(String cmd) throws InterruptedException, IOException {
     85      long timeout = PING_TIMEOUT;
     86      int count = PING_COUNT;
     87      boolean countPing = false;
     88      boolean reportTimes = true;
    8689      while (true) {
    8790        if (cmd.startsWith("-t ")) { // timeout
     
    9396            } else {
    9497                timeout = Long.parseLong(cmd.substring(0, pos));
     98                // convenience, convert msec to sec
     99                if (timeout < 100)
     100                    timeout *= 1000;
    95101                cmd = cmd.substring(pos + 1);
    96102            }
     
    112118                return;
    113119            } else {
    114                 PING_COUNT = Integer.parseInt(cmd.substring(0, pos));
     120                count = Integer.parseInt(cmd.substring(0, pos));
    115121                cmd = cmd.substring(pos + 1);
    116122            }
    117123        } else if (cmd.startsWith("-c ")) { // "count" ping
    118124            countPing = true;
     125            count = CPING_COUNT;
    119126            cmd = cmd.substring(3);
    120127        } else if (cmd.equals("-h")) { // ping all hosts
     
    132139                    line = line.substring(0, line.indexOf("="));
    133140                }
    134                 pingHandlers.add(new PingHandler(line));
     141                PingHandler ph = new PingHandler(line, count, timeout, countPing, reportTimes);
     142                ph.start();
     143                pingHandlers.add(ph);
    135144                if (++i > 1)
    136145                    reportTimes = false;
     
    141150            return;
    142151        } else {
    143             Thread t = new PingHandler(cmd);
     152            Thread t = new PingHandler(cmd, count, timeout, countPing, reportTimes);
     153            t.start();
    144154            t.join();
    145155            return;
     
    148158    }
    149159
     160    @Override
    150161    public boolean close(boolean forced) {
    151162        if (!open) return true;
    152         synchronized (lock) {
    153             if (!forced && !finished) {
    154                 l.log("There are still pings running!");
    155                 return false;
    156             }
    157             l.log("Closing pinger " + toString());
    158             l.log("Pinger closed.");
    159             open = false;
    160             return true;
    161         }
    162     }
    163 
    164     public boolean ping(Destination dest) throws I2PException {
     163        super.close(forced);
     164        if (!forced && !finished) {
     165            l.log("There are still pings running!");
     166            return false;
     167        }
     168        l.log("Closing pinger " + toString());
     169        l.log("Pinger closed.");
     170        return true;
     171    }
     172
     173    private boolean ping(Destination dest, long timeout) throws I2PException {
    165174        try {
    166175            synchronized (simulLock) {
     
    187196    }
    188197
    189     public class PingHandler extends I2PAppThread {
    190         private String destination;
    191 
    192         public PingHandler(String dest) {
     198    /**
     199     *  Does nothing.
     200     *  @since 0.9.10
     201     */
     202    protected void clientConnectionRun(Socket s) {}
     203
     204    private class PingHandler extends I2PAppThread {
     205        private final String destination;
     206        private final int cnt;
     207        private final long timeout;
     208        private final boolean countPing;
     209        private final boolean reportTimes;
     210
     211        /**
     212         *  As of 0.9.10, does NOT start itself.
     213         *  Caller must call start()
     214         *  @param dest b64 or b32 or host name
     215         */
     216        public PingHandler(String dest, int count, long timeout, boolean countPings, boolean report) {
    193217            this.destination = dest;
     218            cnt = count;
     219            this.timeout = timeout;
     220            countPing = countPings;
     221            reportTimes = report;
    194222            setName("PingHandler for " + dest);
    195             start();
    196223        }
    197224
     
    199226        public void run() {
    200227            try {
    201                 Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(destination);
     228                Destination dest = lookup(destination);
    202229                if (dest == null) {
    203                     synchronized (lock) { // Logger is not thread safe
    204                         l.log("Unresolvable: " + destination + "");
    205                     }
     230                    l.log("Unresolvable: " + destination);
    206231                    return;
    207232                }
     
    209234                int fail = 0;
    210235                long totalTime = 0;
    211                 int cnt = countPing ? CPING_COUNT : PING_COUNT;
    212236                StringBuilder pingResults = new StringBuilder(2 * cnt + destination.length() + 3);
    213237                for (int i = 0; i < cnt; i++) {
    214238                    boolean sent;
    215                     sent = ping(dest);
     239                    sent = ping(dest, timeout);
    216240                    if (countPing) {
    217241                        if (!sent) {
     
    245269                }
    246270                pingResults.append("  ").append(destination);
    247                 synchronized (lock) { // Logger is not thread safe
    248                     l.log(pingResults.toString());
    249                 }
     271                l.log(pingResults.toString());
    250272            } catch (I2PException ex) {
    251273                _log.error("Error pinging " + destination, ex);
    252274            }
    253275        }
     276
     277        /**
     278         *  @param name b64 or b32 or host name
     279         *  @since 0.9.10
     280         */
     281        private Destination lookup(String name) {
     282            I2PAppContext ctx = I2PAppContext.getGlobalContext();
     283            boolean b32 = name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p");
     284            if (ctx.isRouterContext() && !b32) {
     285                // Local lookup.
     286                // Even though we could do b32 outside router ctx here,
     287                // we do it below instead so we can use the session,
     288                // which we can't do with lookup()
     289                Destination dest = ctx.namingService().lookup(name);
     290                if (dest != null || ctx.isRouterContext() || name.length() >= 516)
     291                    return dest;
     292            }
     293            try {
     294                I2PSession sess = sockMgr.getSession();
     295                return sess.lookupDest(name);
     296            } catch (I2PSessionException ise) {
     297                _log.error("Error looking up " + name, ise);
     298                return null;
     299            }
     300        }
    254301    }
    255302}
  • apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java

    r5d32224 r9eefe1e  
    594594        PacketLocal packet = new PacketLocal(_context, peer);
    595595        packet.setSendStreamId(id.longValue());
    596         packet.setFlag(Packet.FLAG_ECHO);
    597         packet.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
     596        packet.setFlag(Packet.FLAG_ECHO |
     597                       Packet.FLAG_NO_ACK |
     598                       Packet.FLAG_SIGNATURE_INCLUDED);
    598599        packet.setOptionalFrom(_session.getMyDestination());
    599600        //if ( (keyToUse != null) && (tagsToSend != null) ) {
  • apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java

    r5d32224 r9eefe1e  
    296296    public boolean isFlagSet(int flag) { return 0 != (_flags & flag); }
    297297
     298    /**
     299     *  @param flag bitmask of any flag(s)
     300     */
    298301    public void setFlag(int flag) { _flags |= flag; }
    299302
     303    /**
     304     *  @param flag bitmask of any flag(s)
     305     *  @param set true to set, false to clear
     306     */
    300307    public void setFlag(int flag, boolean set) {
    301308        if (set)
     
    305312    }
    306313
    307     public void setFlags(int flags) { _flags = flags; }
     314    private void setFlags(int flags) { _flags = flags; }
    308315
    309316    /** the signature on the packet (only included if the flag for it is set)
  • apps/streaming/java/src/net/i2p/client/streaming/impl/PacketHandler.java

    r5d32224 r9eefe1e  
    350350        } else {
    351351            PacketLocal pong = new PacketLocal(_context, packet.getOptionalFrom());
    352             pong.setFlag(Packet.FLAG_ECHO, true);
    353             pong.setFlag(Packet.FLAG_SIGNATURE_INCLUDED, false);
     352            pong.setFlag(Packet.FLAG_ECHO | Packet.FLAG_NO_ACK);
    354353            pong.setReceiveStreamId(packet.getSendStreamId());
    355354            _manager.getPacketQueue().enqueue(pong);
  • apps/streaming/java/src/net/i2p/client/streaming/impl/PacketQueue.java

    r5d32224 r9eefe1e  
    110110                options.setTagThreshold(MIN_TAG_THRESHOLD);
    111111            } else if (packet.isFlagSet(FLAGS_FINAL_TAGS)) {
    112                 options.setSendLeaseSet(false);
     112                if (packet.isFlagSet(Packet.FLAG_ECHO)) {
     113                    // Send LS for PING, not for PONG
     114                    if (packet.getSendStreamId() <= 0)  // pong
     115                        options.setSendLeaseSet(false);
     116                } else {
     117                    options.setSendLeaseSet(false);
     118                }
    113119                options.setTagsToSend(FINAL_TAGS_TO_SEND);
    114120                options.setTagThreshold(FINAL_TAG_THRESHOLD);
  • core/java/src/net/i2p/client/ClientWriterRunner.java

    r5d32224 r9eefe1e  
    99import java.util.concurrent.atomic.AtomicLong;
    1010
     11import net.i2p.I2PAppContext;
    1112import net.i2p.data.i2cp.I2CPMessage;
    1213import net.i2p.data.i2cp.I2CPMessageException;
    1314import net.i2p.internal.PoisonI2CPMessage;
    1415import net.i2p.util.I2PAppThread;
     16import net.i2p.util.Log;
    1517
    1618/**
     
    2628    private final BlockingQueue<I2CPMessage> _messagesToWrite;
    2729    private static final AtomicLong __Id = new AtomicLong();
     30    //private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ClientWriterRunner.class);
    2831
    2932    private static final int MAX_QUEUE_SIZE = 32;
    3033    private static final long MAX_SEND_WAIT = 10*1000;
    3134   
    32     /** starts the thread too */
     35    /**
     36     *  As of 0.9.11 does not start the thread, caller must call startWriting()
     37     */
    3338    public ClientWriterRunner(OutputStream out, I2PSessionImpl session) {
    3439        _out = new BufferedOutputStream(out);
    3540        _session = session;
    3641        _messagesToWrite = new LinkedBlockingQueue<I2CPMessage>(MAX_QUEUE_SIZE);
     42    }
     43
     44    /**
     45     *  @since 0.9.11
     46     */
     47    public void startWriting() {
    3748        Thread t = new I2PAppThread(this, "I2CP Client Writer " + __Id.incrementAndGet(), true);
    3849        t.start();
     
    7788            try {
    7889                msg.writeMessage(_out);
    79                 _out.flush();
     90                if (_messagesToWrite.isEmpty())
     91                    _out.flush();
    8092            } catch (I2CPMessageException ime) {
    8193                _session.propogateError("Error writing out the message", ime);
  • core/java/src/net/i2p/client/I2PClientMessageHandlerMap.java

    r5d32224 r9eefe1e  
    1414import net.i2p.data.i2cp.DestReplyMessage;
    1515import net.i2p.data.i2cp.DisconnectMessage;
     16import net.i2p.data.i2cp.HostReplyMessage;
    1617import net.i2p.data.i2cp.MessagePayloadMessage;
    1718import net.i2p.data.i2cp.MessageStatusMessage;
     
    4142        highest = Math.max(highest, SetDateMessage.MESSAGE_TYPE);
    4243        highest = Math.max(highest, DestReplyMessage.MESSAGE_TYPE);
     44        highest = Math.max(highest, HostReplyMessage.MESSAGE_TYPE);
    4345        highest = Math.max(highest, BandwidthLimitsMessage.MESSAGE_TYPE);
    4446        highest = Math.max(highest, RequestVariableLeaseSetMessage.MESSAGE_TYPE);
     
    5456        _handlers[BandwidthLimitsMessage.MESSAGE_TYPE] = new BWLimitsMessageHandler(context);
    5557        _handlers[RequestVariableLeaseSetMessage.MESSAGE_TYPE] = new RequestVariableLeaseSetMessageHandler(context);
     58        _handlers[HostReplyMessage.MESSAGE_TYPE] = new HostReplyMessageHandler(context);
    5659    }
    5760
  • core/java/src/net/i2p/client/I2PSession.java

    r5d32224 r9eefe1e  
    215215
    216216    /**
     217     *  Lookup a Destination by Hash.
    217218     *  Blocking.
    218219     *  @param maxWait ms
     
    221222     */
    222223    public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException;
     224
     225    /**
     226     *  Ask the router to lookup a Destination by host name.
     227     *  Blocking. Waits a max of 10 seconds by default.
     228     *
     229     *  This only makes sense for a b32 hostname, OR outside router context.
     230     *  Inside router context, just query the naming service.
     231     *  Outside router context, this does NOT query the context naming service.
     232     *  Do that first if you expect a local addressbook.
     233     *
     234     *  This will log a warning for non-b32 in router context.
     235     *
     236     *  Suggested implementation:
     237     *
     238     *<pre>
     239     *  if (name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
     240     *      if (session != null)
     241     *          return session.lookup(Hash.create(Base32.decode(name.toLowerCase(Locale.US).substring(0, 52))));
     242     *      else
     243     *          return ctx.namingService().lookup(name); // simple session for xxx.b32.i2p handled by naming service (optional if you need lookup w/o an existing session)
     244     *  } else if (ctx.isRouterContext()) {
     245     *      return ctx.namingService().lookup(name); // hostname from router's naming service
     246     *  } else {
     247     *      Destination d = ctx.namingService().lookup(name); // local naming svc, optional
     248     *      if (d != null)
     249     *          return d;
     250     *      if (session != null)
     251     *          return session.lookup(name);
     252     *      // simple session (optional if you need lookup w/o an existing session)
     253     *      Destination rv = null;
     254     *      I2PClient client = new I2PSimpleClient();
     255     *      Properties opts = new Properties();
     256     *      opts.put(I2PClient.PROP_TCP_HOST, host);
     257     *      opts.put(I2PClient.PROP_TCP_PORT, port);
     258     *      I2PSession session = null;
     259     *      try {
     260     *          session = client.createSession(null, opts);
     261     *          session.connect();
     262     *          rv = session.lookupDest(name);
     263     *      } finally {
     264     *          if (session != null)
     265     *              session.destroySession();
     266     *      }
     267     *      return rv;
     268     *  }
     269     *</pre>
     270     *
     271     *  Requires router side to be 0.9.11 or higher. If the router is older,
     272     *  this will return null immediately.
     273     *
     274     *  @since 0.9.11
     275     */
     276    public Destination lookupDest(String name) throws I2PSessionException;
     277
     278    /**
     279     *  Ask the router to lookup a Destination by host name.
     280     *  Blocking. See above for details.
     281     *  @param maxWait ms
     282     *  @since 0.9.11
     283     *  @return null on failure
     284     */
     285    public Destination lookupDest(String name, long maxWait) throws I2PSessionException;
    223286
    224287    /**
  • core/java/src/net/i2p/client/I2PSessionImpl.java

    r5d32224 r9eefe1e  
    2020import java.util.ArrayList;
    2121import java.util.List;
     22import java.util.Locale;
    2223import java.util.Map;
    2324import java.util.Properties;
    2425import java.util.concurrent.ConcurrentHashMap;
    2526import java.util.concurrent.LinkedBlockingQueue;
     27import java.util.concurrent.atomic.AtomicInteger;
    2628
    2729import net.i2p.CoreVersion;
    2830import net.i2p.I2PAppContext;
     31import net.i2p.data.Base32;
    2932import net.i2p.data.DataFormatException;
    3033import net.i2p.data.Destination;
     
    3639import net.i2p.data.i2cp.GetBandwidthLimitsMessage;
    3740import net.i2p.data.i2cp.GetDateMessage;
     41import net.i2p.data.i2cp.HostLookupMessage;
    3842import net.i2p.data.i2cp.I2CPMessage;
    3943import net.i2p.data.i2cp.I2CPMessageReader;
     
    4751import net.i2p.util.LHMCache;
    4852import net.i2p.util.Log;
     53import net.i2p.util.OrderedProperties;
    4954import net.i2p.util.SimpleTimer;
    5055import net.i2p.util.VersionComparator;
     
    99104    /** hashes of lookups we are waiting for */
    100105    protected final LinkedBlockingQueue<LookupWaiter> _pendingLookups = new LinkedBlockingQueue<LookupWaiter>();
     106    private final AtomicInteger _lookupID = new AtomicInteger();
    101107    protected final Object _bwReceivedLock = new Object();
    102108    protected volatile int[] _bwLimits;
     
    104110    protected final I2PClientMessageHandlerMap _handlerMap;
    105111   
    106     /** used to seperate things out so we can get rid of singletons */
     112    /** used to separate things out so we can get rid of singletons */
    107113    protected final I2PAppContext _context;
    108114
     
    115121    protected enum State {
    116122        OPENING,
     123        /** @since 0.9.11 */
     124        GOTDATE,
    117125        OPEN,
    118126        CLOSING,
     
    122130    private State _state = State.CLOSED;
    123131    protected final Object _stateLock = new Object();
    124 
    125     /** have we received the current date from the router yet? */
    126     private volatile boolean _dateReceived;
    127     /** lock that we wait upon, that the SetDateMessageHandler notifies */
    128     private final Object _dateReceivedLock = new Object();
    129132
    130133    /**
     
    140143    private final boolean _fastReceive;
    141144    private volatile boolean _routerSupportsFastReceive;
    142 
    143     /**
     145    private volatile boolean _routerSupportsHostLookup;
     146
     147    /**
     148     *  Since 0.9.11, key is either a Hash or a String
    144149     *  @since 0.8.9
    145150     */
    146     private static final Map<Hash, Destination> _lookupCache = new LHMCache<Hash, Destination>(16);
     151    private static final Map<Object, Destination> _lookupCache = new LHMCache<Object, Destination>(16);
     152    private static final String MIN_HOST_LOOKUP_VERSION = "0.9.11";
     153    private static final boolean TEST_LOOKUP = false;
    147154
    148155    /** SSL interface (only) @since 0.8.3 */
    149156    protected static final String PROP_ENABLE_SSL = "i2cp.SSL";
     157    protected static final String PROP_USER = "i2cp.username";
     158    protected static final String PROP_PW = "i2cp.password";
    150159
    151160    private static final long VERIFY_USAGE_TIME = 60*1000;
     
    160169                                     (routerVersion != null && routerVersion.length() > 0 &&
    161170                                      VersionComparator.comp(routerVersion, MIN_FAST_VERSION) >= 0);
    162         _dateReceived = true;
    163         synchronized (_dateReceivedLock) {
    164             _dateReceivedLock.notifyAll();
     171        _routerSupportsHostLookup = _context.isRouterContext() ||
     172                                    TEST_LOOKUP ||
     173                                     (routerVersion != null && routerVersion.length() > 0 &&
     174                                      VersionComparator.comp(routerVersion, MIN_HOST_LOOKUP_VERSION) >= 0);
     175        synchronized (_stateLock) {
     176            if (_state == State.OPENING) {
     177                _state = State.GOTDATE;
     178                _stateLock.notifyAll();
     179            }
    165180        }
    166181    }
     
    206221            _signingPrivateKey = null;
    207222        }
     223        _routerSupportsFastReceive = _context.isRouterContext();
     224        _routerSupportsHostLookup = _context.isRouterContext();
    208225    }
    209226
     
    240257        if ((!_context.isRouterContext()) &&
    241258            _context.getBooleanProperty("i2cp.auth") &&
    242             ((!opts.containsKey("i2cp.username")) || (!opts.containsKey("i2cp.password")))) {
    243             String configUser = _context.getProperty("i2cp.username");
    244             String configPW = _context.getProperty("i2cp.password");
     259            ((!opts.containsKey(PROP_USER)) || (!opts.containsKey(PROP_PW)))) {
     260            String configUser = _context.getProperty(PROP_USER);
     261            String configPW = _context.getProperty(PROP_PW);
    245262            if (configUser != null && configPW != null) {
    246                 options.setProperty("i2cp.username", configUser);
    247                 options.setProperty("i2cp.password", configPW);
     263                options.setProperty(PROP_USER, configUser);
     264                options.setProperty(PROP_PW, configPW);
    248265            }
    249266        }
     
    400417                        break;
    401418                    case OPENING:
     419                    case GOTDATE:
    402420                        wasOpening = true;
    403421                        try {
     
    456474                    out.flush();
    457475                    _writer = new ClientWriterRunner(out, this);
     476                    _writer.startWriting();
    458477                    InputStream in = new BufferedInputStream(_socket.getInputStream(), BUF_SIZE);
    459478                    _reader = new I2CPMessageReader(in, this);
     
    463482            _reader.startReading();
    464483            if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Before getDate");
    465             sendMessage(new GetDateMessage(CoreVersion.VERSION));
    466             if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "After getDate / begin waiting for a response");
    467             int waitcount = 0;
    468             while (!_dateReceived) {
    469                 if (waitcount++ > 30) {
    470                     throw new IOException("No handshake received from the router");
    471                 }
    472                 synchronized (_dateReceivedLock) {
    473                     // InterruptedException caught below
    474                     _dateReceivedLock.wait(1000);
    475                 }
    476             }
    477             if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "After received a SetDate response");
     484            Properties auth = null;
     485            if ((!_context.isRouterContext()) && _options.containsKey(PROP_USER) && _options.containsKey(PROP_PW)) {
     486                // Only supported by routers 0.9.11 or higher, but we don't know the version yet.       
     487                // Auth will also be sent in the SessionConfig.
     488                auth = new OrderedProperties();
     489                auth.setProperty(PROP_USER, _options.getProperty(PROP_USER));
     490                auth.setProperty(PROP_PW, _options.getProperty(PROP_PW));
     491            }
     492            sendMessage(new GetDateMessage(CoreVersion.VERSION, auth));
     493            waitForDate();
    478494
    479495            if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Before producer.connect()");
     
    482498
    483499            // wait until we have created a lease set
    484             waitcount = 0;
     500            int waitcount = 0;
    485501            while (_leaseSet == null) {
    486502                if (waitcount++ > 5*60) {
     
    526542
    527543    /**
     544     *  @since 0.9.11 moved from connect()
     545     */
     546    protected void waitForDate() throws InterruptedException, IOException {
     547            if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "After getDate / begin waiting for a response");
     548            int waitcount = 0;
     549            while (true) {
     550                if (waitcount++ > 30) {
     551                    throw new IOException("No handshake received from the router");
     552                }
     553                synchronized(_stateLock) {
     554                    if (_state == State.GOTDATE)
     555                        break;
     556                    if (_state != State.OPENING)
     557                        throw new IOException("Socket closed");
     558                    // InterruptedException caught by caller
     559                    _stateLock.wait(1000);
     560                }
     561            }
     562            if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "After received a SetDate response");
     563    }
     564
     565    /**
    528566     * Pull the unencrypted data from the message that we've already prefetched and
    529567     * notified the user that its available.
     
    891929     */
    892930    protected void disconnect() {
     931        State oldState;
    893932        synchronized(_stateLock) {
    894933            if (_state == State.CLOSING || _state == State.CLOSED)
    895934                return;
     935            oldState = _state;
    896936            changeState(State.CLOSING);
    897937        }
    898938        if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Disconnect() called", new Exception("Disconnect"));
    899         if (shouldReconnect()) {
     939        // don't try to reconnect if it failed before GETTDATE
     940        if (oldState != State.OPENING && shouldReconnect()) {
    900941            if (reconnect()) {
    901942                if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "I2CP reconnection successful");
     
    9641005    }
    9651006
    966     /** called by the message handler */
     1007    /**
     1008     *  Called by the message handler
     1009     *  on reception of DestReplyMessage
     1010     */
    9671011    void destReceived(Destination d) {
    9681012        Hash h = d.calculateHash();
     
    9711015        }
    9721016        for (LookupWaiter w : _pendingLookups) {
    973             if (w.hash.equals(h)) {
     1017            if (h.equals(w.hash)) {
    9741018                w.destination = d;
    9751019                synchronized (w) {
     
    9801024    }
    9811025
    982     /** called by the message handler */
     1026    /**
     1027     *  Called by the message handler
     1028     *  on reception of DestReplyMessage
     1029     */
    9831030    void destLookupFailed(Hash h) {
    9841031        for (LookupWaiter w : _pendingLookups) {
    985             if (w.hash.equals(h)) {
     1032            if (h.equals(w.hash)) {
     1033                synchronized (w) {
     1034                    w.notifyAll();
     1035                }
     1036            }
     1037        }
     1038    }
     1039
     1040    /**
     1041     *  Called by the message handler
     1042     *  on reception of HostReplyMessage
     1043     *  @since 0.9.11
     1044     */
     1045    void destReceived(long nonce, Destination d) {
     1046        // notify by hash
     1047        destReceived(d);
     1048        // notify by nonce
     1049        for (LookupWaiter w : _pendingLookups) {
     1050            if (nonce == w.nonce) {
     1051                w.destination = d;
     1052                if (w.name != null) {
     1053                    synchronized (_lookupCache) {
     1054                        _lookupCache.put(w.name, d);
     1055                    }
     1056                }
     1057                synchronized (w) {
     1058                    w.notifyAll();
     1059                }
     1060            }
     1061        }
     1062    }
     1063
     1064    /**
     1065     *  Called by the message handler
     1066     *  on reception of HostReplyMessage
     1067     *  @since 0.9.11
     1068     */
     1069    void destLookupFailed(long nonce) {
     1070        for (LookupWaiter w : _pendingLookups) {
     1071            if (nonce == w.nonce) {
    9861072                synchronized (w) {
    9871073                    w.notifyAll();
     
    10041090     */
    10051091    private static class LookupWaiter {
    1006         /** the request */
     1092        /** the request (Hash mode) */
    10071093        public final Hash hash;
     1094        /** the request (String mode) */
     1095        public final String name;
     1096        /** the request (nonce mode) */
     1097        public final long nonce;
    10081098        /** the reply */
    10091099        public volatile Destination destination;
    10101100
    10111101        public LookupWaiter(Hash h) {
     1102            this(h, -1);
     1103        }
     1104
     1105        /** @since 0.9.11 */
     1106        public LookupWaiter(Hash h, long nonce) {
    10121107            this.hash = h;
     1108            this.name = null;
     1109            this.nonce = nonce;
     1110        }
     1111
     1112        /** @since 0.9.11 */
     1113        public LookupWaiter(String name, long nonce) {
     1114            this.hash = null;
     1115            this.name = name;
     1116            this.nonce = nonce;
    10131117        }
    10141118    }
     
    10381142                return rv;
    10391143        }
    1040         if (isClosed())
     1144        if (isClosed()) {
     1145            if (_log.shouldLog(Log.INFO))
     1146                _log.info("Session closed, cannot lookup " + h);
    10411147            return null;
    1042         LookupWaiter waiter = new LookupWaiter(h);
     1148        }
     1149        LookupWaiter waiter;
     1150        long nonce;
     1151        if (_routerSupportsHostLookup) {
     1152            nonce = _lookupID.incrementAndGet() & 0x7fffffff;
     1153            waiter = new LookupWaiter(h, nonce);
     1154        } else {
     1155            nonce = 0; // won't be used
     1156            waiter = new LookupWaiter(h);
     1157        }
    10431158        _pendingLookups.offer(waiter);
    10441159        try {
    1045             sendMessage(new DestLookupMessage(h));
     1160            if (_routerSupportsHostLookup) {
     1161                if (_log.shouldLog(Log.INFO))
     1162                    _log.info("Sending HostLookup for " + h);
     1163                SessionId id = _sessionId;
     1164                if (id == null)
     1165                    id = new SessionId(65535);
     1166                sendMessage(new HostLookupMessage(id, h, nonce, maxWait));
     1167            } else {
     1168                if (_log.shouldLog(Log.INFO))
     1169                    _log.info("Sending DestLookup for " + h);
     1170                sendMessage(new DestLookupMessage(h));
     1171            }
     1172            try {
     1173                synchronized (waiter) {
     1174                    waiter.wait(maxWait);
     1175                }
     1176            } catch (InterruptedException ie) {
     1177                throw new I2PSessionException("Interrupted", ie);
     1178            }
     1179        } finally {
     1180            _pendingLookups.remove(waiter);
     1181        }
     1182        return waiter.destination;
     1183    }
     1184
     1185    /**
     1186     *  Ask the router to lookup a Destination by host name.
     1187     *  Blocking. Waits a max of 10 seconds by default.
     1188     *
     1189     *  This only makes sense for a b32 hostname, OR outside router context.
     1190     *  Inside router context, just query the naming service.
     1191     *  Outside router context, this does NOT query the context naming service.
     1192     *  Do that first if you expect a local addressbook.
     1193     *
     1194     *  This will log a warning for non-b32 in router context.
     1195     *
     1196     *  See interface for suggested implementation.
     1197     *
     1198     *  Requires router side to be 0.9.11 or higher. If the router is older,
     1199     *  this will return null immediately.
     1200     *
     1201     *  @since 0.9.11
     1202     */
     1203    public Destination lookupDest(String name) throws I2PSessionException {
     1204        return lookupDest(name, 10*1000);
     1205    }
     1206
     1207    /**
     1208     *  Ask the router to lookup a Destination by host name.
     1209     *  Blocking. See above for details.
     1210     *  @param maxWait ms
     1211     *  @since 0.9.11
     1212     *  @return null on failure
     1213     */
     1214    public Destination lookupDest(String name, long maxWait) throws I2PSessionException {
     1215        if (name.length() == 0)
     1216            return null;
     1217        // Shortcut for b64
     1218        if (name.length() >= 516) {
     1219            try {
     1220                return new Destination(name);
     1221            } catch (DataFormatException dfe) {
     1222                return null;
     1223            }
     1224        }
     1225        // won't fit in Mapping
     1226        if (name.length() >= 256 && !_context.isRouterContext())
     1227            return null;
     1228        synchronized (_lookupCache) {
     1229            Destination rv = _lookupCache.get(name);
     1230            if (rv != null)
     1231                return rv;
     1232        }
     1233        if (isClosed()) {
     1234            if (_log.shouldLog(Log.INFO))
     1235                _log.info("Session closed, cannot lookup " + name);
     1236            return null;
     1237        }
     1238        if (!_routerSupportsHostLookup) {
     1239            // do them a favor and convert to Hash lookup
     1240            if (name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p"))
     1241                return lookupDest(Hash.create(Base32.decode(name.toLowerCase(Locale.US).substring(0, 52))), maxWait);
     1242            // else unsupported
     1243            if (_log.shouldLog(Log.WARN))
     1244                _log.warn("Router does not support HostLookup for " + name);
     1245            return null;
     1246        }
     1247        int nonce = _lookupID.incrementAndGet() & 0x7fffffff;
     1248        LookupWaiter waiter = new LookupWaiter(name, nonce);
     1249        _pendingLookups.offer(waiter);
     1250        try {
     1251            if (_log.shouldLog(Log.INFO))
     1252                _log.info("Sending HostLookup for " + name);
     1253            SessionId id = _sessionId;
     1254            if (id == null)
     1255                id = new SessionId(65535);
     1256            sendMessage(new HostLookupMessage(id, name, nonce, maxWait));
    10461257            try {
    10471258                synchronized (waiter) {
  • core/java/src/net/i2p/client/I2PSimpleSession.java

    r5d32224 r9eefe1e  
    1515import java.util.Properties;
    1616
     17import net.i2p.CoreVersion;
    1718import net.i2p.I2PAppContext;
    1819import net.i2p.data.i2cp.BandwidthLimitsMessage;
    1920import net.i2p.data.i2cp.DestReplyMessage;
     21import net.i2p.data.i2cp.DisconnectMessage;
     22import net.i2p.data.i2cp.GetDateMessage;
     23import net.i2p.data.i2cp.HostReplyMessage;
    2024import net.i2p.data.i2cp.I2CPMessageReader;
     25import net.i2p.data.i2cp.SetDateMessage;
    2126import net.i2p.internal.InternalClientManager;
    2227import net.i2p.internal.QueuedI2CPMessageReader;
    2328import net.i2p.util.I2PSSLSocketFactory;
     29import net.i2p.util.Log;
     30import net.i2p.util.OrderedProperties;
    2431
    2532/**
     
    6976                    _queue = mgr.connect();
    7077                    _reader = new QueuedI2CPMessageReader(_queue, this);
     78                    _reader.startReading();
    7179                } else {
    7280                    if (Boolean.parseBoolean(getOptions().getProperty(PROP_ENABLE_SSL))) {
     
    8694                    out.flush();
    8795                    _writer = new ClientWriterRunner(out, this);
     96                    _writer.startWriting();
    8897                    InputStream in = new BufferedInputStream(_socket.getInputStream(), BUF_SIZE);
    8998                    _reader = new I2CPMessageReader(in, this);
     99                    _reader.startReading();
    90100                }
     101            }
     102            // must be out of synch block for writer to get unblocked
     103            if (!_context.isRouterContext()) {
     104                Properties opts = getOptions();
     105                // Send auth message if required
     106                // Auth was not enforced on a simple session until 0.9.11
     107                // We will get disconnected for router version < 0.9.11 since it doesn't
     108                // support the AuthMessage
     109                if ((!opts.containsKey(PROP_USER)) && (!opts.containsKey(PROP_PW))) {
     110                    // auto-add auth if not set in the options
     111                    String configUser = _context.getProperty(PROP_USER);
     112                    String configPW = _context.getProperty(PROP_PW);
     113                    if (configUser != null && configPW != null) {
     114                        opts.setProperty(PROP_USER, configUser);
     115                        opts.setProperty(PROP_PW, configPW);
     116                    }
     117                }
     118                if (opts.containsKey(PROP_USER) && opts.containsKey(PROP_PW)) {
     119                    Properties auth = new OrderedProperties();
     120                    auth.setProperty(PROP_USER, opts.getProperty(PROP_USER));
     121                    auth.setProperty(PROP_PW, opts.getProperty(PROP_PW));
     122                    sendMessage(new GetDateMessage(CoreVersion.VERSION, auth));
     123                } else {
     124                    // we must now send a GetDate even in SimpleSession, or we won't know
     125                    // what version we are talking with and cannot use HostLookup
     126                    sendMessage(new GetDateMessage(CoreVersion.VERSION));
     127                }
     128                waitForDate();
    91129            }
    92130            // we do not receive payload messages, so we do not need an AvailabilityNotifier
    93131            // ... or an Idle timer, or a VerifyUsage
    94             _reader.startReading();
    95132            success = true;
     133            if (_log.shouldLog(Log.INFO))
     134                _log.info(getPrefix() + " simple session connected");
     135        } catch (InterruptedException ie) {
     136            throw new I2PSessionException("Interrupted", ie);
    96137        } catch (UnknownHostException uhe) {
    97138            throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe);
     
    116157        public SimpleMessageHandlerMap(I2PAppContext context) {
    117158            int highest = Math.max(DestReplyMessage.MESSAGE_TYPE, BandwidthLimitsMessage.MESSAGE_TYPE);
     159            highest = Math.max(highest, DisconnectMessage.MESSAGE_TYPE);
     160            highest = Math.max(highest, HostReplyMessage.MESSAGE_TYPE);
     161            highest = Math.max(highest, SetDateMessage.MESSAGE_TYPE);
    118162            _handlers = new I2CPMessageHandler[highest+1];
    119163            _handlers[DestReplyMessage.MESSAGE_TYPE] = new DestReplyMessageHandler(context);
    120164            _handlers[BandwidthLimitsMessage.MESSAGE_TYPE] = new BWLimitsMessageHandler(context);
     165            _handlers[DisconnectMessage.MESSAGE_TYPE] = new DisconnectMessageHandler(context);
     166            _handlers[HostReplyMessage.MESSAGE_TYPE] = new HostReplyMessageHandler(context);
     167            _handlers[SetDateMessage.MESSAGE_TYPE] = new SetDateMessageHandler(context);
    121168        }
    122169    }
  • core/java/src/net/i2p/client/naming/LookupDest.java

    r5d32224 r9eefe1e  
    3535
    3636    private static final long DEFAULT_TIMEOUT = 15*1000;
     37    private static final String PROP_ENABLE_SSL = "i2cp.SSL";
     38    private static final String PROP_USER = "i2cp.username";
     39    private static final String PROP_PW = "i2cp.password";
    3740
    3841    protected LookupDest(I2PAppContext context) {}
     
    6265        I2PClient client = new I2PSimpleClient();
    6366        Properties opts = new Properties();
    64         String s = ctx.getProperty(I2PClient.PROP_TCP_HOST);
    65         if (s != null)
    66             opts.put(I2PClient.PROP_TCP_HOST, s);
    67         s = ctx.getProperty(I2PClient.PROP_TCP_PORT);
    68         if (s != null)
    69             opts.put(I2PClient.PROP_TCP_PORT, s);
     67        if (!ctx.isRouterContext()) {
     68            String s = ctx.getProperty(I2PClient.PROP_TCP_HOST);
     69            if (s != null)
     70                opts.put(I2PClient.PROP_TCP_HOST, s);
     71            s = ctx.getProperty(I2PClient.PROP_TCP_PORT);
     72            if (s != null)
     73                opts.put(I2PClient.PROP_TCP_PORT, s);
     74            s = ctx.getProperty(PROP_ENABLE_SSL);
     75            if (s != null)
     76                opts.put(PROP_ENABLE_SSL, s);
     77            s = ctx.getProperty(PROP_USER);
     78            if (s != null)
     79                opts.put(PROP_USER, s);
     80            s = ctx.getProperty(PROP_PW);
     81            if (s != null)
     82                opts.put(PROP_PW, s);
     83        }
    7084        I2PSession session = null;
    7185        try {
  • core/java/src/net/i2p/data/i2cp/GetDateMessage.java

    r5d32224 r9eefe1e  
    1313import java.io.IOException;
    1414import java.io.InputStream;
     15import java.util.Map;
     16import java.util.Properties;
    1517
    1618import net.i2p.data.DataFormatException;
    1719import net.i2p.data.DataHelper;
     20import net.i2p.util.OrderedProperties;
    1821
    1922/**
    20  * Request the other side to send us what they think the current time is/
     23 * Request the other side to send us what they think the current time is.
    2124 * Only supported from client to router.
    2225 *
    2326 * Since 0.8.7, optionally include a version string.
     27 * Since 0.9.10, optionally include options.
    2428 */
    2529public class GetDateMessage extends I2CPMessageImpl {
    2630    public final static int MESSAGE_TYPE = 32;
    2731    private String _version;
     32    private Properties _options;
    2833
    2934    public GetDateMessage() {
     
    4146
    4247    /**
     48     *  @param version the client's version String to be sent to the router; may be null;
     49     *                 must be non-null if options is non-null and non-empty.
     50     *  @param options Client options to be sent to the router; primarily for authentication; may be null;
     51     *                 keys and values 255 bytes (not chars) max each
     52     *  @since 0.9.10
     53     */
     54    public GetDateMessage(String version, Properties options) {
     55        super();
     56        if (version == null && options != null && !options.isEmpty())
     57            throw new IllegalArgumentException();
     58        _version = version;
     59        _options = options;
     60    }
     61
     62    /**
    4363     *  @return may be null
    4464     *  @since 0.8.7
     
    4868    }
    4969
     70    /**
     71     *  Retrieve any configuration options for the connection.
     72     *  Primarily for authentication.
     73     *
     74     *  @return may be null
     75     *  @since 0.9.10
     76     */
     77    public Properties getOptions() {
     78        return _options;
     79    }
     80
    5081    @Override
    5182    protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException {
     
    5384            try {
    5485                _version = DataHelper.readString(in);
     86                if (size > 1 + _version.length())  // assume ascii
     87                    _options = DataHelper.readProperties(in);
    5588            } catch (DataFormatException dfe) {
    5689                throw new I2CPMessageException("Bad version string", dfe);
     
    6396        if (_version == null)
    6497            return new byte[0];
    65         ByteArrayOutputStream os = new ByteArrayOutputStream(16);
     98        ByteArrayOutputStream os = new ByteArrayOutputStream(_options != null ? 128 : 16);
    6699        try {
    67100            DataHelper.writeString(os, _version);
     101            if (_options != null && !_options.isEmpty())
     102                DataHelper.writeProperties(os, _options, true);  // UTF-8
    68103        } catch (DataFormatException dfe) {
    69104            throw new I2CPMessageException("Error writing out the message data", dfe);
     
    81116        buf.append("[GetDateMessage]");
    82117        buf.append("\n\tVersion: ").append(_version);
     118        if (_options != null && !_options.isEmpty()) {
     119            buf.append("\n\tOptions: #: ").append(_options.size());
     120            Properties sorted = new OrderedProperties();
     121            sorted.putAll(_options);
     122            for (Map.Entry<Object, Object> e : sorted.entrySet()) {
     123                String key = (String) e.getKey();
     124                String val = (String) e.getValue();
     125                buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
     126            }
     127        }
    83128        return buf.toString();
    84129    }
  • core/java/src/net/i2p/data/i2cp/I2CPMessageHandler.java

    r5d32224 r9eefe1e  
    2323
    2424    /**
     25     *  This is huge. Mainly to catch a completly bogus response, possibly not an I2CP socket.
     26     *  @since 0.9.10
     27     */
     28    public static final int MAX_LENGTH = 128*1024;
     29
     30    /**
    2531     * Read an I2CPMessage from the stream and return the fully populated object.
    2632     *
     
    3238     */
    3339    public static I2CPMessage readMessage(InputStream in) throws IOException, I2CPMessageException {
    34         int length = -1;
     40        int length;
    3541        try {
    3642            length = (int) DataHelper.readLong(in, 4);
     
    3844            throw new IOException("Connection closed");
    3945        }
     46        if (length > MAX_LENGTH)
     47            throw new I2CPMessageException("Invalid message length specified");
    4048        try {
    41             if (length < 0) throw new I2CPMessageException("Invalid message length specified");
    4249            int type = (int) DataHelper.readLong(in, 1);
    4350            I2CPMessage msg = createMessage(type);
     51            // Note that the readMessage() calls don't, in general, read and discard
     52            // extra data, so we can't add new fields to the end of messages
     53            // in a compatible way. And the readers could read beyond the length too.
     54            // To fix this we'd have to read into a BAOS/BAIS or use a filter input stream
    4455            msg.readMessage(in, length, type);
    4556            return msg;
     
    5364     *
    5465     */
    55     private static I2CPMessage createMessage(int type) throws IOException,
     66    private static I2CPMessage createMessage(int type) throws
    5667                                                       I2CPMessageException {
    5768        switch (type) {
     
    98109        case BandwidthLimitsMessage.MESSAGE_TYPE:
    99110            return new BandwidthLimitsMessage();
     111        case HostLookupMessage.MESSAGE_TYPE:
     112            return new HostLookupMessage();
     113        case HostReplyMessage.MESSAGE_TYPE:
     114            return new HostReplyMessage();
    100115        default:
    101116            throw new I2CPMessageException("The type " + type + " is an unknown I2CP message");
  • core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java

    r5d32224 r9eefe1e  
    111111         *
    112112         * @param reader I2CPMessageReader to notify
    113          * @param error Exception that was thrown
     113         * @param error Exception that was thrown, non-null
    114114         */
    115115        public void readError(I2CPMessageReader reader, Exception error);
  • core/java/src/net/i2p/data/i2cp/SessionConfig.java

    r5d32224 r9eefe1e  
    9090
    9191    /**
    92      * Configure the session with the given options
     92     * Configure the session with the given options;
     93     * keys and values 255 bytes (not chars) max each
    9394     *
    9495     * @param options Properties for this session
  • core/java/src/net/i2p/data/i2cp/SessionId.java

    r5d32224 r9eefe1e  
    3030    }
    3131
     32    /**
     33     *  @param id 0-65535
     34     *  @since 0.9.11
     35     */
     36    public SessionId(int id) {
     37        if (id < 0 || id > 65535)
     38            throw new IllegalArgumentException();
     39        _sessionId = id;
     40    }
     41
    3242    public int getSessionId() {
    3343        return _sessionId;
     
    3646    /** @param id 0-65535 */
    3747    public void setSessionId(int id) {
     48        if (id < 0 || id > 65535)
     49            throw new IllegalArgumentException();
    3850        _sessionId = id;
    3951    }
  • router/java/src/net/i2p/router/client/ClientConnectionRunner.java

    r5d32224 r9eefe1e  
    336336     *  See ClientMessageEventListener.handleCreateSession()
    337337     *  for why we don't send a SessionStatusMessage when we do this.
     338     *  @param reason will be truncated to 255 bytes
    338339     */
    339340    void disconnectClient(String reason) {
     
    342343
    343344    /**
     345     * @param reason will be truncated to 255 bytes
    344346     * @param logLevel e.g. Log.WARN
    345347     * @since 0.8.2
     
    352354                     + _config);
    353355        DisconnectMessage msg = new DisconnectMessage();
     356        if (reason.length() > 255)
     357            reason = reason.substring(0, 255);
    354358        msg.setReason(reason);
    355359        try {
  • router/java/src/net/i2p/router/client/ClientMessageEventListener.java

    r5d32224 r9eefe1e  
    2121import net.i2p.data.i2cp.GetBandwidthLimitsMessage;
    2222import net.i2p.data.i2cp.GetDateMessage;
     23import net.i2p.data.i2cp.HostLookupMessage;
    2324import net.i2p.data.i2cp.I2CPMessage;
    2425import net.i2p.data.i2cp.I2CPMessageException;
     
    5152    protected final ClientConnectionRunner _runner;
    5253    private final boolean  _enforceAuth;
     54    private volatile boolean _authorized;
    5355   
    5456    private static final String PROP_AUTH = "i2cp.auth";
     57    /** if true, user/pw must be in GetDateMessage */
     58    private static final String PROP_AUTH_STRICT = "i2cp.strictAuth";
    5559
    5660    /**
     
    6266        _runner = runner;
    6367        _enforceAuth = enforceAuth;
     68        if ((!_enforceAuth) || !_context.getBooleanProperty(PROP_AUTH))
     69            _authorized = true;
    6470        _context.statManager().createRateStat("client.distributeTime", "How long it took to inject the client message into the router", "ClientMessages", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    6571    }
     
    7379        if (_log.shouldLog(Log.DEBUG))
    7480            _log.debug("Message received: \n" + message);
     81        int type = message.getType();
     82        if (!_authorized) {
     83            // TODO change to default true
     84            boolean strict = _context.getBooleanProperty(PROP_AUTH_STRICT);
     85            if ((strict && type != GetDateMessage.MESSAGE_TYPE) ||
     86                (type != CreateSessionMessage.MESSAGE_TYPE &&
     87                 type != GetDateMessage.MESSAGE_TYPE &&
     88                 type != DestLookupMessage.MESSAGE_TYPE &&
     89                 type != GetBandwidthLimitsMessage.MESSAGE_TYPE)) {
     90                _log.error("Received message type " + type + " without required authentication");
     91                _runner.disconnectClient("Authorization required");
     92                return;
     93            }
     94        }
    7595        switch (message.getType()) {
    7696            case GetDateMessage.MESSAGE_TYPE:
     
    103123            case DestLookupMessage.MESSAGE_TYPE:
    104124                handleDestLookup((DestLookupMessage)message);
     125                break;
     126            case HostLookupMessage.MESSAGE_TYPE:
     127                handleHostLookup((HostLookupMessage)message);
    105128                break;
    106129            case ReconfigureSessionMessage.MESSAGE_TYPE:
     
    125148            _log.error("Error occurred", error);
    126149        // Is this is a little drastic for an unknown message type?
     150        // Send the whole exception string over for diagnostics
     151        _runner.disconnectClient(error.toString());
    127152        _runner.stopRunning();
    128153    }
     
    138163        if (clientVersion != null)
    139164            _runner.setClientVersion(clientVersion);
     165        Properties props = message.getOptions();
     166        if (!checkAuth(props))
     167            return;
    140168        try {
    141169            // only send version if the client can handle it (0.8.7 or greater)
     
    175203
    176204        // Auth, since 0.8.2
    177         if (_enforceAuth && _context.getBooleanProperty(PROP_AUTH)) {
    178                 Properties props = in.getOptions();
    179                 String user = props.getProperty("i2cp.username");
    180                 String pw = props.getProperty("i2cp.password");
    181                 if (user == null || user.length() == 0 || pw == null || pw.length() == 0) {
    182                     _log.error("I2CP auth failed for client: " + props.getProperty("inbound.nickname"));
    183                     _runner.disconnectClient("Authorization required to create session, specify i2cp.username and i2cp.password in session options");
    184                     return;
    185                 }
    186                 PasswordManager mgr = new PasswordManager(_context);
    187                 if (!mgr.checkHash(PROP_AUTH, user, pw)) {
    188                     _log.error("I2CP auth failed for client: " + props.getProperty("inbound.nickname") + " user: " + user);
    189                     _runner.disconnectClient("Authorization failed for Create Session, user = " + user);
    190                     return;
    191                 }
    192                 if (_log.shouldLog(Log.INFO))
    193                     _log.info("I2CP auth success for client: " + props.getProperty("inbound.nickname") + " user: " + user);
    194         }
     205        Properties inProps = in.getOptions();
     206        if (!checkAuth(inProps))
     207            return;
    195208
    196209        SessionId sessionId = new SessionId();
     
    214227    }
    215228   
     229    /**
     230     *  Side effect - sets _authorized.
     231     *  Side effect - disconnects session if not authorized.
     232     *
     233     *  @param props contains i2cp.username and i2cp.password, may be null
     234     *  @return success
     235     *  @since 0.9.11
     236     */
     237    private boolean checkAuth(Properties props) {
     238        if (_authorized)
     239            return true;
     240        if (_enforceAuth && _context.getBooleanProperty(PROP_AUTH)) {
     241            String user = null;
     242            String pw = null;
     243            if (props != null) {
     244                user = props.getProperty("i2cp.username");
     245                pw = props.getProperty("i2cp.password");
     246            }
     247            if (user == null || user.length() == 0 || pw == null || pw.length() == 0) {
     248                _log.error("I2CP auth failed");
     249                _runner.disconnectClient("Authorization required, specify i2cp.username and i2cp.password in options");
     250                _authorized = false;
     251                return false;
     252            }
     253            PasswordManager mgr = new PasswordManager(_context);
     254            if (!mgr.checkHash(PROP_AUTH, user, pw)) {
     255                _log.error("I2CP auth failed user: " + user);
     256                _runner.disconnectClient("Authorization failed, user = " + user);
     257                _authorized = false;
     258                return false;
     259            }
     260            if (_log.shouldLog(Log.INFO))
     261                _log.info("I2CP auth success user: " + user);
     262        }
     263        _authorized = true;
     264        return true;
     265    }
     266
    216267    /**
    217268     *  Override for testing
     
    317368
    318369    /**
     370     * override for testing
     371     * @since 0.9.11
     372     */
     373    protected void handleHostLookup(HostLookupMessage message) {
     374        _context.jobQueue().addJob(new LookupDestJob(_context, _runner, message.getReqID(),
     375                                                     message.getTimeout(), message.getSessionId(),
     376                                                     message.getHash(), message.getHostname()));
     377    }
     378
     379    /**
    319380     * Message's Session ID ignored. This doesn't support removing previously set options.
    320381     * Nor do we bother with message.getSessionConfig().verifySignature() ... should we?
  • router/java/src/net/i2p/router/client/LookupDestJob.java

    r5d32224 r9eefe1e  
    55package net.i2p.router.client;
    66
     7import java.util.Locale;
     8
     9import net.i2p.data.Base32;
    710import net.i2p.data.Destination;
    811import net.i2p.data.Hash;
    912import net.i2p.data.LeaseSet;
    1013import net.i2p.data.i2cp.DestReplyMessage;
     14import net.i2p.data.i2cp.HostReplyMessage;
     15import net.i2p.data.i2cp.I2CPMessage;
    1116import net.i2p.data.i2cp.I2CPMessageException;
     17import net.i2p.data.i2cp.SessionId;
    1218import net.i2p.router.JobImpl;
    1319import net.i2p.router.RouterContext;
    1420
    1521/**
    16  * Look up the lease of a hash, to convert it to a Destination for the client
     22 * Look up the lease of a hash, to convert it to a Destination for the client.
     23 * Or, since 0.9.11, lookup a host name in the naming service.
    1724 */
    1825class LookupDestJob extends JobImpl {
    1926    private final ClientConnectionRunner _runner;
     27    private final long _reqID;
     28    private final long _timeout;
    2029    private final Hash _hash;
     30    private final String _name;
     31    private final SessionId _sessID;
     32
     33    private static final long DEFAULT_TIMEOUT = 15*1000;
    2134
    2235    public LookupDestJob(RouterContext context, ClientConnectionRunner runner, Hash h) {
     36        this(context, runner, -1, DEFAULT_TIMEOUT, null, h, null);
     37    }
     38
     39    /**
     40     *  One of h or name non-null
     41     *  @param reqID must be >= 0 if name != null
     42     *  @param sessID must non-null if reqID >= 0
     43     *  @since 0.9.11
     44     */
     45    public LookupDestJob(RouterContext context, ClientConnectionRunner runner,
     46                         long reqID, long timeout, SessionId sessID, Hash h, String name) {
    2347        super(context);
     48        if ((h == null && name == null) ||
     49            (h != null && name != null) ||
     50            (reqID >= 0 && sessID == null) ||
     51            (reqID < 0 && name != null))
     52            throw new IllegalArgumentException();
    2453        _runner = runner;
     54        _reqID = reqID;
     55        _timeout = timeout;
     56        _sessID = sessID;
     57        if (name != null && name.length() == 60) {
     58            // convert a b32 lookup to a hash lookup
     59            String nlc = name.toLowerCase(Locale.US);
     60            if (nlc.endsWith(".b32.i2p")) {
     61                byte[] b = Base32.decode(nlc.substring(0, 52));
     62                if (b != null && b.length == Hash.HASH_LENGTH) {
     63                    h = Hash.create(b);
     64                    name = null;
     65                }
     66            }
     67        }
    2568        _hash = h;
     69        _name = name;
    2670    }
    2771   
    28     public String getName() { return "LeaseSet Lookup for Client"; }
     72    public String getName() { return _name != null ?
     73                                     "HostName Lookup for Client" :
     74                                     "LeaseSet Lookup for Client";
     75    }
     76
    2977    public void runJob() {
    30         DoneJob done = new DoneJob(getContext());
    31         // TODO add support for specifying the timeout in the lookup message
    32         getContext().netDb().lookupLeaseSet(_hash, done, done, 15*1000);
     78        if (_name != null) {
     79            // inline, ignore timeout
     80            Destination d = getContext().namingService().lookup(_name);
     81            if (d != null)
     82                returnDest(d);
     83            else
     84                returnFail();
     85        } else {
     86            DoneJob done = new DoneJob(getContext());
     87            getContext().netDb().lookupLeaseSet(_hash, done, done, _timeout);
     88        }
    3389    }
    3490
     
    4399                returnDest(ls.getDestination());
    44100            else
    45                 returnHash(_hash);
     101                returnFail();
    46102        }
    47103    }
    48104
    49105    private void returnDest(Destination d) {
    50         DestReplyMessage msg = new DestReplyMessage(d);
     106        I2CPMessage msg;
     107        if (_reqID >= 0)
     108            msg = new HostReplyMessage(_sessID, d, _reqID);
     109        else
     110            msg = new DestReplyMessage(d);
    51111        try {
    52112            _runner.doSend(msg);
     
    58118     *  @since 0.8.3
    59119     */
    60     private void returnHash(Hash h) {
    61         DestReplyMessage msg = new DestReplyMessage(h);
     120    private void returnFail() {
     121        I2CPMessage msg;
     122        if (_reqID >= 0)
     123            msg = new HostReplyMessage(_sessID, HostReplyMessage.RESULT_FAILURE, _reqID);
     124        else
     125            msg = new DestReplyMessage(_hash);
    62126        try {
    63127            _runner.doSend(msg);
Note: See TracChangeset for help on using the changeset viewer.