diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelManager.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelManager.java
deleted file mode 100644
index 3b76c5e32c501088284f505c24cbb3a1c9926908..0000000000000000000000000000000000000000
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelManager.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
- * (c) 2003 - 2004 mihi
- */
-
-package net.i2p.i2ptunnel;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-
-import net.i2p.data.DataFormatException;
-import net.i2p.data.Destination;
-import net.i2p.util.Clock;
-import net.i2p.util.I2PThread;
-import net.i2p.util.Log;
-
-/**
- * Quick and dirty socket listener to control an I2PTunnel.  
- * Basically run this class as TunnelManager [listenHost] [listenPort] and 
- * then send it commands on that port.  Commands are one shot deals -
- * Send a command + newline, get a response plus newline, then get disconnected.
- * <p />
- * <b>Implemented commands:</b>
- * <pre>
- * -------------------------------------------------
- * lookup &lt;name&gt;\n
- * --
- * &lt;base64 of the destination&gt;\n
- *  or
- * &lt;error message, usually 'Unknown host'&gt;\n
- * 
- *  Lookup the public key of a named destination (i.e. listed in hosts.txt)
- * -------------------------------------------------
- * genkey\n
- * --
- * &lt;base64 of the destination&gt;\t&lt;base64 of private data&gt;\n
- * 
- *  Generates a new public and private key pair
- * -------------------------------------------------
- * convertprivate &lt;base64 of privkey&gt;
- * --
- * &lt;base64 of destination&gt;\n
- *  or
- * &lt;error message&gt;\n
- *
- *  Returns the destination (pubkey) of a given private key. 
- * -------------------------------------------------
- * listen_on &lt;ip&gt;\n
- * --
- * ok\n
- *  or
- * error\n
- * 
- *  Sets the ip address clients will listen on. By default this is the
- *  localhost (127.0.0.1)
- * -------------------------------------------------
- * openclient &lt;listenPort&gt; &lt;peer&gt;[ &lt;sharedClient&gt;]\n
- * --
- * ok [&lt;jobId&gt;]\n
- *  or
- * ok &lt;listenPort&gt; [&lt;jobId&gt;]\n
- *  or
- * error\n
- * 
- *  Open a tunnel on the given &lt;listenport&gt; to the destination specified
- *  by &lt;peer&gt;. If &lt;listenPort&gt; is 0 a free port is picked and returned in
- *  the reply message. Otherwise the short reply message is used.
- *  Peer can be the base64 of the destination, a file with the public key
- *  specified as 'file:&lt;filename&gt;' or the name of a destination listed in
- *  hosts.txt. The &lt;jobId&gt; returned together with "ok" and &lt;listenport&gt; can
- *  later be used as argument for the "close" command.
- *  &lt;sharedClient&gt; indicates if this httpclient shares tunnels with other
- *  clients or not (just use 'true' and 'false'
- * -------------------------------------------------
- * openhttpclient &lt;listenPort&gt; [&lt;sharedClient&gt;] [&lt;proxy&gt;]\n
- * --
- * ok [&lt;jobId&gt;]\n
- *  or
- * ok &lt;listenPort&gt; [&lt;jobId&gt;]\n
- *  or
- * error\n
- * 
- *  Open an HTTP proxy through the I2P on the given
- *  &lt;listenport&gt;. &lt;proxy&gt; (optional) specifies a
- *  destination to be used as an outbound proxy, to access normal WWW
- *  sites out of the .i2p domain. If &lt;listenPort&gt; is 0 a free
- *  port is picked and returned in the reply message. Otherwise the
- *  short reply message is used.  &lt;proxy&gt; can be the base64 of the
- *  destination, a file with the public key specified as
- *  'file:&lt;filename&gt;' or the name of a destination listed in
- *  hosts.txt. The &lt;jobId&gt; returned together with "ok" and
- *  &lt;listenport&gt; can later be used as argument for the "close"
- *  command.
- *  &lt;sharedClient&gt; indicates if this httpclient shares tunnels with other
- *  clients or not (just use 'true' and 'false'
- * -------------------------------------------------
- * opensockstunnel &lt;listenPort&gt;\n
- * --
- * ok [&lt;jobId&gt;]\n
- *  or
- * ok &lt;listenPort&gt; [&lt;jobId&gt;]\n
- *  or
- * error\n
- * 
- *  Open an SOCKS tunnel through the I2P on the given
- *  &lt;listenport&gt;. If &lt;listenPort&gt; is 0 a free port is
- *  picked and returned in the reply message. Otherwise the short
- *  reply message is used.  The &lt;jobId&gt; returned together with
- *  "ok" and &lt;listenport&gt; can later be used as argument for the
- *  "close" command.
- * -------------------------------------------------
- * openserver &lt;serverHost&gt; &lt;serverPort&gt; &lt;serverKeys&gt;\n
- * --
- * ok [&lt;jobId&gt;]\n
- *  or
- * error\n
- * 
- *  Starts receiving traffic for the destination specified by &lt;serverKeys&gt;
- *  and forwards it to the &lt;serverPort&gt; of &lt;serverHost&gt;.
- *  &lt;serverKeys&gt; is the base 64 encoded private key set of the local
- *  destination. The &lt;joId&gt; returned together with "ok" can later be used
- *  as argument for the "close" command.
- * -------------------------------------------------
- * close [forced] &lt;jobId&gt;\n
- *  or
- * close [forced] all\n
- * --
- * ok\n
- *  or
- * error\n
- * 
- *  Closes the job specified by &lt;jobId&gt; or all jobs. Use the list command
- *  for a list of running jobs.
- *  Normally a connection job is not closed when it still has an active
- *  connection. Use the optional 'forced' keyword to close connections
- *  regardless of their use.
- * -------------------------------------------------
- * list\n
- * --
- *  Example output:
- * 
- * [0] i2p.dnsalias.net/69.55.226.145:5555 &lt;- C:\i2pKeys\squidPriv
- * [1] 8767 -&gt; HTTPClient
- * [2] 7575 -&gt; file:C:\i2pKeys\squidPub
- * [3] 5252 -&gt; sCcSANIO~f4AQtCNI1BvDp3ZBS~9Ag5O0k0Msm7XBWWz5eOnZWL3MQ-2rxlesucb9XnpASGhWzyYNBpWAfaIB3pux1J1xujQLOwscMIhm7T8BP76Ly5jx6BLZCYrrPj0BI0uV90XJyT~4UyQgUlC1jzFQdZ9HDgBPJDf1UI4-YjIwEHuJgdZynYlQ1oUFhgno~HhcDByXO~PDaO~1JDMDbBEfIh~v6MgmHp-Xchod1OfKFrxFrzHgcJbn7E8edTFjZA6JCi~DtFxFelQz1lSBd-QB1qJnA0g-pVL5qngNUojXJCXs4qWcQ7ICLpvIc-Fpfj-0F1gkVlGDSGkb1yLH3~8p4czYgR3W5D7OpwXzezz6clpV8kmbd~x2SotdWsXBPRhqpewO38coU4dJG3OEUbuYmdN~nJMfWbmlcM1lXzz2vBsys4sZzW6dV3hZnbvbfxNTqbdqOh-KXi1iAzXv7CVTun0ubw~CfeGpcAqutC5loRUq7Mq62ngOukyv8Z9AAAA
- *
- *  Lists descriptions of all running jobs. The exact format of the
- *  description depends on the type of job.
- * -------------------------------------------------
- * </pre>
- *
- *
- * @deprecated this isn't run by default, and no one seems to use it, and has
- *             lots of things to maintain.  so, at some point this may dissapear
- *             unless someone pipes up ;)
- */
-public class TunnelManager implements Runnable {
-    private final static Log _log = new Log(TunnelManager.class);
-    private I2PTunnel _tunnel;
-    private ServerSocket _socket;
-    private boolean _keepAccepting;
-
-    public TunnelManager(int listenPort) {
-        this(null, listenPort);
-    }
-
-    public TunnelManager(String listenHost, int listenPort) {
-        _tunnel = new I2PTunnel();
-        _keepAccepting = true;
-        try {
-            if (listenHost != null) {
-                _socket = new ServerSocket(listenPort, 0, InetAddress.getByName(listenHost));
-                _log.info("Listening for tunnel management clients on " + listenHost + ":" + listenPort);
-            } else {
-                _socket = new ServerSocket(listenPort);
-                _log.info("Listening for tunnel management clients on localhost:" + listenPort);
-            }
-        } catch (Exception e) {
-            _log.error("Error starting up tunnel management listener on " + listenPort, e);
-        }
-    }
-
-    public static void main(String args[]) {
-        int port = 7676;
-        String host = null;
-        if (args.length == 1) {
-            try {
-                port = Integer.parseInt(args[0]);
-            } catch (NumberFormatException nfe) {
-                _log.error("Usage: TunnelManager [host] [port]");
-                return;
-            }
-        } else if (args.length == 2) {
-            host = args[0];
-            try {
-                port = Integer.parseInt(args[1]);
-            } catch (NumberFormatException nfe) {
-                _log.error("Usage: TunnelManager [host] [port]");
-                return;
-            }
-        }
-
-        TunnelManager mgr = new TunnelManager(host, port);
-        Thread t = new I2PThread(mgr, "Listener");
-        t.start();
-    }
-
-    public void run() {
-        if (_socket == null) {
-            _log.error("Unable to start listening, since the socket was not bound.  Already running?");
-            return;
-        }
-        _log.debug("Running");
-        try {
-            while (_keepAccepting) {
-                Socket socket = _socket.accept();
-                _log.debug("Client accepted");
-                if (socket != null) {
-                    Thread t = new I2PThread(new TunnelManagerClientRunner(this, socket));
-                    t.setName("TunnelManager Client");
-                    t.setPriority(I2PThread.MIN_PRIORITY);
-                    t.start();
-                }
-            }
-        } catch (IOException ioe) {
-            _log.error("Error accepting connections", ioe);
-        } catch (Exception e) {
-            _log.error("Other error?!", e);
-        } finally {
-            if (_socket != null) try {
-                _socket.close();
-            } catch (IOException ioe) {
-            }
-        }
-        try {
-            Thread.sleep(5000);
-        } catch (InterruptedException ie) {
-        }
-    }
-
-    public void error(String msg, OutputStream out) throws IOException {
-        out.write(msg.getBytes());
-        out.write('\n');
-    }
-
-    public void processQuit(OutputStream out) throws IOException {
-        out.write("Nice try".getBytes());
-        out.write('\n');
-    }
-
-    public void processList(OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        long startCommand = Clock.getInstance().now();
-        _tunnel.runCommand("list", buf);
-        Object obj = _tunnel.waitEventValue("listDone");
-        long endCommand = Clock.getInstance().now();
-        String str = buf.getBuffer();
-        _log.debug("ListDone complete after " + (endCommand - startCommand) + "ms: [" + str + "]");
-        out.write(str.getBytes());
-        out.write('\n');
-        buf.ignoreFurtherActions();
-    }
-
-    public void processListenOn(String ip, OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand("listen_on " + ip, buf);
-        String status = (String) _tunnel.waitEventValue("listen_onResult");
-        out.write((status + "\n").getBytes());
-        buf.ignoreFurtherActions();
-    }
-
-    /**
-     * "lookup <name>" returns with the result in base64, else "Unknown host" [or something like that],
-     * then a newline.
-     *
-     */
-    public void processLookup(String name, OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand("lookup " + name, buf);
-        String rv = (String) _tunnel.waitEventValue("lookupResult");
-        out.write(rv.getBytes());
-        out.write('\n');
-        buf.ignoreFurtherActions();
-    }
-
-    public void processTestDestination(String destKey, OutputStream out) throws IOException {
-        try {
-            Destination d = new Destination();
-            d.fromBase64(destKey);
-            out.write("valid\n".getBytes());
-        } catch (DataFormatException dfe) {
-            out.write("invalid\n".getBytes());
-        }
-        out.flush();
-    }
-
-    public void processConvertPrivate(String priv, OutputStream out) throws IOException {
-        try {
-            Destination dest = new Destination();
-            dest.fromBase64(priv);
-            String str = dest.toBase64();
-            out.write(str.getBytes());
-            out.write('\n');
-        } catch (DataFormatException dfe) {
-            _log.error("Error converting private data", dfe);
-            out.write("Error converting private key\n".getBytes());
-        }
-    }
-
-    public void processClose(String which, boolean forced, OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand((forced ? "close forced " : "close ") + which, buf);
-        String str = (String) _tunnel.waitEventValue("closeResult");
-        out.write((str + "\n").getBytes());
-        buf.ignoreFurtherActions();
-    }
-
-    /**
-     * "genkey" returns with the base64 of the destination, followed by a tab, then the base64 of that
-     * destination's private keys, then a newline.
-     *
-     */
-    public void processGenKey(OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand("gentextkeys", buf);
-        String priv = (String) _tunnel.waitEventValue("privateKey");
-        String pub = (String) _tunnel.waitEventValue("publicDestination");
-        out.write((pub + "\t" + priv).getBytes());
-        out.write('\n');
-        buf.ignoreFurtherActions();
-    }
-
-    public void processOpenClient(int listenPort, String peer, String sharedClient, OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand("client " + listenPort + " " + peer + " " + sharedClient, buf);
-        Integer taskId = (Integer) _tunnel.waitEventValue("clientTaskId");
-        if (taskId.intValue() < 0) {
-            out.write("error\n".getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-        String rv = (String) _tunnel.waitEventValue("openClientResult");
-        if (rv.equals("error")) {
-            out.write((rv + "\n").getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-
-        if (listenPort != 0) {
-            out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-        Integer port = (Integer) _tunnel.waitEventValue("clientLocalPort");
-        out.write((rv + " " + port.intValue() + " [" + taskId.intValue() + "]\n").getBytes());
-        buf.ignoreFurtherActions();
-    }
-
-    public void processOpenHTTPClient(int listenPort, String sharedClient, String proxy, OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand("httpclient " + listenPort + " " + sharedClient + " " + proxy, buf);
-        Integer taskId = (Integer) _tunnel.waitEventValue("httpclientTaskId");
-        if (taskId.intValue() < 0) {
-            out.write("error\n".getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-        String rv = (String) _tunnel.waitEventValue("openHTTPClientResult");
-        if (rv.equals("error")) {
-            out.write((rv + "\n").getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-
-        if (listenPort != 0) {
-            out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-        Integer port = (Integer) _tunnel.waitEventValue("clientLocalPort");
-        out.write((rv + " " + port.intValue() + " [" + taskId.intValue() + "]\n").getBytes());
-        buf.ignoreFurtherActions();
-    }
-
-    public void processOpenSOCKSTunnel(int listenPort, OutputStream out) throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand("sockstunnel " + listenPort, buf);
-        Integer taskId = (Integer) _tunnel.waitEventValue("sockstunnelTaskId");
-        if (taskId.intValue() < 0) {
-            out.write("error\n".getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-        String rv = (String) _tunnel.waitEventValue("openSOCKSTunnelResult");
-        if (rv.equals("error")) {
-            out.write((rv + "\n").getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-
-        if (listenPort != 0) {
-            out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-        Integer port = (Integer) _tunnel.waitEventValue("clientLocalPort");
-        out.write((rv + " " + port.intValue() + " [" + taskId.intValue() + "]\n").getBytes());
-        buf.ignoreFurtherActions();
-    }
-
-    public void processOpenServer(String serverHost, int serverPort, String privateKeys, OutputStream out)
-                                                                                                          throws IOException {
-        BufferLogger buf = new BufferLogger();
-        _tunnel.runCommand("textserver " + serverHost + " " + serverPort + " " + privateKeys, buf);
-        Integer taskId = (Integer) _tunnel.waitEventValue("serverTaskId");
-        if (taskId.intValue() < 0) {
-            out.write("error\n".getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-
-        String rv = (String) _tunnel.waitEventValue("openServerResult");
-
-        if (rv.equals("error")) {
-            out.write((rv + "\n").getBytes());
-            buf.ignoreFurtherActions();
-            return;
-        }
-
-        out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
-        buf.ignoreFurtherActions();
-    }
-
-    /**
-     * Frisbee.
-     *
-     */
-    public void unknownCommand(String command, OutputStream out) throws IOException {
-        out.write("Unknown command: ".getBytes());
-        out.write(command.getBytes());
-        out.write("\n".getBytes());
-    }
-}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelManagerClientRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelManagerClientRunner.java
deleted file mode 100644
index 6bd9bb730df47faa1d8d124cc6c8b93b6ceaa3e2..0000000000000000000000000000000000000000
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelManagerClientRunner.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
- * (c) 2003 - 2004 mihi
- */
-
-package net.i2p.i2ptunnel;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.Socket;
-import java.util.StringTokenizer;
-
-import net.i2p.util.Log;
-
-/**
- * Runner thread that reads commands from the socket and fires off commands to
- * the TunnelManager
- *
- */
-class TunnelManagerClientRunner implements Runnable {
-    private final static Log _log = new Log(TunnelManagerClientRunner.class);
-    private TunnelManager _mgr;
-    private Socket _clientSocket;
-
-    public TunnelManagerClientRunner(TunnelManager mgr, Socket socket) {
-        _clientSocket = socket;
-        _mgr = mgr;
-    }
-
-    public void run() {
-        _log.debug("Client running");
-        try {
-            BufferedReader reader = new BufferedReader(new InputStreamReader(_clientSocket.getInputStream()));
-            OutputStream out = _clientSocket.getOutputStream();
-
-            String cmd = reader.readLine();
-            if (cmd != null) processCommand(cmd, out);
-        } catch (IOException ioe) {
-            _log.error("Error processing client commands", ioe);
-        } finally {
-            if (_clientSocket != null) try {
-                _clientSocket.close();
-            } catch (IOException ioe) {
-            }
-        }
-        _log.debug("Client closed");
-    }
-
-    /**
-     * Parse the command string and fire off the appropriate tunnelManager method,
-     * sending the results to the output stream
-     */
-    private void processCommand(String command, OutputStream out) throws IOException {
-        _log.debug("Processing [" + command + "]");
-        StringTokenizer tok = new StringTokenizer(command);
-        if (!tok.hasMoreTokens()) {
-            _mgr.unknownCommand(command, out);
-        } else {
-            String cmd = tok.nextToken();
-            if ("quit".equalsIgnoreCase(cmd)) {
-                _mgr.processQuit(out);
-            } else if ("lookup".equalsIgnoreCase(cmd)) {
-                if (tok.hasMoreTokens())
-                    _mgr.processLookup(tok.nextToken(), out);
-                else
-                    _mgr.error("Usage: lookup <hostname>", out);
-            } else if ("testdestination".equalsIgnoreCase(cmd)) {
-                if (tok.hasMoreTokens())
-                    _mgr.processTestDestination(tok.nextToken(), out);
-                else
-                    _mgr.error("Usage: testdestination <publicDestination>", out);
-            } else if ("convertprivate".equalsIgnoreCase(cmd)) {
-                if (tok.hasMoreTokens())
-                    _mgr.processConvertPrivate(tok.nextToken(), out);
-                else
-                    _mgr.error("Usage: convertprivate <privateData>", out);
-            } else if ("close".equalsIgnoreCase(cmd)) {
-                if (tok.hasMoreTokens()) {
-                    String closeArg;
-                    if ((closeArg = tok.nextToken()).equals("forced")) {
-                        if (tok.hasMoreTokens()) {
-                            _mgr.processClose(tok.nextToken(), true, out);
-                        } else {
-                            _mgr.error("Usage: close [forced] <jobnumber>|all", out);
-                        }
-                    } else {
-                        _mgr.processClose(closeArg, false, out);
-                    }
-                } else {
-                    _mgr.error("Usage: close [forced] <jobnumber>|all", out);
-                }
-            } else if ("genkey".equalsIgnoreCase(cmd)) {
-                _mgr.processGenKey(out);
-            } else if ("list".equalsIgnoreCase(cmd)) {
-                _mgr.processList(out);
-            } else if ("listen_on".equalsIgnoreCase(cmd)) {
-                if (tok.hasMoreTokens()) {
-                    _mgr.processListenOn(tok.nextToken(), out);
-                } else {
-                    _mgr.error("Usage: listen_on <ip>", out);
-                }
-            } else if ("openclient".equalsIgnoreCase(cmd)) {
-                int listenPort = 0;
-                String peer = null;
-                String sharedClient = null;
-                int numTokens = tok.countTokens();
-                if (numTokens < 2 || numTokens > 3) {
-                    _mgr.error("Usage: openclient <listenPort> <peer> <sharedClient>", out);
-                    return;
-                }
-                try {
-                    listenPort = Integer.parseInt(tok.nextToken());
-                    peer = tok.nextToken();
-                    if (tok.hasMoreTokens())
-                        sharedClient = tok.nextToken();
-                    else
-                        sharedClient = "true";
-                    _mgr.processOpenClient(listenPort, peer, sharedClient, out);
-                } catch (NumberFormatException nfe) {
-                    _mgr.error("Bad listen port", out);
-                    return;
-                }
-            } else if ("openhttpclient".equalsIgnoreCase(cmd)) {
-                int listenPort = 0;
-                String proxy = "squid.i2p";
-                String sharedClient = "true";
-                int numTokens = tok.countTokens();
-                if (numTokens < 1 || numTokens > 3) {
-                    _mgr.error("Usage: openhttpclient <listenPort> [<sharedClient>] [<proxy>]", out);
-                    return;
-                }
-                try {
-                    listenPort = Integer.parseInt(tok.nextToken());
-                    if (tok.hasMoreTokens()) {
-                        String val = tok.nextToken();
-                        if (tok.hasMoreTokens()) {
-                            sharedClient = val;
-                            proxy = tok.nextToken();
-                        } else {
-                            if ( ("true".equals(val)) || ("false".equals(val)) ) {
-                                sharedClient = val;
-                            } else {
-                                proxy = val;
-                            }
-                        }
-                    }
-                    _mgr.processOpenHTTPClient(listenPort, sharedClient, proxy, out);
-                } catch (NumberFormatException nfe) {
-                    _mgr.error("Bad listen port", out);
-                    return;
-                }
-            } else if ("opensockstunnel".equalsIgnoreCase(cmd)) {
-                int listenPort = 0;
-                if (!tok.hasMoreTokens()) {
-                    _mgr.error("Usage: opensockstunnel <listenPort>", out);
-                    return;
-                }
-                try {
-                    String portStr = tok.nextToken();
-                    listenPort = Integer.parseInt(portStr);
-                } catch (NumberFormatException nfe) {
-                    _mgr.error("Bad listen port", out);
-                    return;
-                }
-                if (tok.hasMoreTokens()) {
-                    _mgr.error("Usage: opensockstunnel <listenport>", out);
-                    return;
-                }
-                _mgr.processOpenSOCKSTunnel(listenPort, out);
-            } else if ("openserver".equalsIgnoreCase(cmd)) {
-                int listenPort = 0;
-                String serverHost = null;
-                String serverKeys = null;
-                if (!tok.hasMoreTokens()) {
-                    _mgr.error("Usage: openserver <serverHost> <serverPort> <serverKeys>", out);
-                    return;
-                }
-                serverHost = tok.nextToken();
-
-                if (!tok.hasMoreTokens()) {
-                    _mgr.error("Usage: openserver <serverHost> <serverPort> <serverKeys>", out);
-                    return;
-                }
-                try {
-                    String portStr = tok.nextToken();
-                    listenPort = Integer.parseInt(portStr);
-                } catch (NumberFormatException nfe) {
-                    _mgr.error("Bad listen port", out);
-                    return;
-                }
-                if (!tok.hasMoreTokens()) {
-                    _mgr.error("Usage: openserver <serverHost> <serverPort> <serverKeys>", out);
-                    return;
-                }
-                serverKeys = tok.nextToken();
-                _mgr.processOpenServer(serverHost, listenPort, serverKeys, out);
-            } else {
-                _mgr.unknownCommand(command, out);
-            }
-        }
-    }
-}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
index 8cf396102e296565ecf71cf7dbcd0a734d324d92..8b039732e7c3e6c073184780685dbc93294a86ce 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
@@ -28,7 +28,8 @@ public class ConfigNetHandler extends FormHandler {
     private boolean _reseedRequested;
     private boolean _saveRequested;
     private boolean _timeSyncEnabled;
-    private String _port;
+    private String _tcpPort;
+    private String _udpPort;
     private String _inboundRate;
     private String _inboundBurst;
     private String _outboundRate;
@@ -56,8 +57,11 @@ public class ConfigNetHandler extends FormHandler {
     public void setHostname(String hostname) { 
         _hostname = (hostname != null ? hostname.trim() : null); 
     }
-    public void setPort(String port) { 
-        _port = (port != null ? port.trim() : null); 
+    public void setTcpPort(String port) { 
+        _tcpPort = (port != null ? port.trim() : null); 
+    }
+    public void setUdpPort(String port) { 
+        _udpPort = (port != null ? port.trim() : null); 
     }
     public void setInboundrate(String rate) { 
         _inboundRate = (rate != null ? rate.trim() : null); 
@@ -207,14 +211,25 @@ public class ConfigNetHandler extends FormHandler {
                 restartRequired = true;
             }
         }
-        if ( (_port != null) && (_port.length() > 0) ) {
+        if ( (_tcpPort != null) && (_tcpPort.length() > 0) ) {
             String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT);
-            if ( (oldPort == null) && (_port.equals("8887")) ) {
+            if ( (oldPort == null) && (_tcpPort.equals("8887")) ) {
+                // still on default.. noop
+            } else if ( (oldPort == null) || (!oldPort.equalsIgnoreCase(_tcpPort)) ) {
+                // its not the default OR it has changed
+                _context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT, _tcpPort);
+                addFormNotice("Updating TCP port from " + oldPort + " to " + _tcpPort);
+                restartRequired = true;
+            }
+        }
+        if ( (_udpPort != null) && (_udpPort.length() > 0) ) {
+            String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_UDP_PORT);
+            if ( (oldPort == null) && (_udpPort.equals("8887")) ) {
                 // still on default.. noop
-            } else if ( (oldPort == null) || (!oldPort.equalsIgnoreCase(_port)) ) {
+            } else if ( (oldPort == null) || (!oldPort.equalsIgnoreCase(_udpPort)) ) {
                 // its not the default OR it has changed
-                _context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT, _port);
-                addFormNotice("Updating TCP port from " + oldPort + " to " + _port);
+                _context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT, _udpPort);
+                addFormNotice("Updating UDP port from " + oldPort + " to " + _udpPort);
                 restartRequired = true;
             }
         }
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
index fa66bac35e45ce2616cb1f9e4cb08aefe97ad6f5..12e01852a567c6aa0c7d983313532a56c03b7d22 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
@@ -24,11 +24,13 @@ public class ConfigNetHelper {
     /** copied from various private TCP components */
     public final static String PROP_I2NP_TCP_HOSTNAME = "i2np.tcp.hostname";
     public final static String PROP_I2NP_TCP_PORT = "i2np.tcp.port";
+    public final static String PROP_I2NP_UDP_PORT = "i2np.udp.port";
+    public final static String PROP_I2NP_INTERNAL_UDP_PORT = "i2np.udp.internalPort";
     
     public String getHostname() {
         return _context.getProperty(PROP_I2NP_TCP_HOSTNAME);
     }
-    public String getPort() {
+    public String getTcpPort() {
         int port = 8887;
         String val = _context.getProperty(PROP_I2NP_TCP_PORT);
         if (val != null) {
@@ -41,6 +43,21 @@ public class ConfigNetHelper {
         return "" + port;
     }
     
+    public String getUdpPort() {
+        int port = 8887;
+        String val = _context.getProperty(PROP_I2NP_UDP_PORT);
+        if (val == null)
+            val = _context.getProperty(PROP_I2NP_INTERNAL_UDP_PORT);
+        if (val != null) {
+            try {
+                port = Integer.parseInt(val);
+            } catch (NumberFormatException nfe) {
+                // ignore, use default from above
+            }
+        }
+        return "" + port;
+    }
+    
     public String getEnableTimeSyncChecked() {
         String disabled = _context.getProperty(Timestamper.PROP_DISABLED, "false");
         if ( (disabled != null) && ("true".equalsIgnoreCase(disabled)) )
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java
index 3aa0dd90e4b51fd06f5f08e47e9a1a082f691025..bcb2af1d5842e00cd02a2d8a532a8ac3ab0322fb 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java
@@ -6,6 +6,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.StringTokenizer;
 
+import net.i2p.util.Log;
 import net.i2p.stat.StatManager;
 
 /**
@@ -22,6 +23,7 @@ public class ConfigStatsHandler extends FormHandler {
     public ConfigStatsHandler() {
         super();
         _stats = new ArrayList();
+        _explicitFilter = false;
     }
     
     protected void processForm() {
@@ -36,29 +38,16 @@ public class ConfigStatsHandler extends FormHandler {
         if (stats != null) {
             for (int i = 0; i < stats.length; i++) {
                 String cur = stats[i].trim();
+                if (_log.shouldLog(Log.DEBUG))
+                    _log.debug("Stat: [" + cur + "]");
                 if ( (cur.length() > 0) && (!_stats.contains(cur)) )
                     _stats.add(cur);
             }
         }
+        if (_log.shouldLog(Log.DEBUG))
+            _log.debug("Updated stats: " + _stats);
     }
 
-    public void setStatList(String stat) { 
-        if (stat != null) {
-            if (stat.indexOf(',') != -1) {
-                StringTokenizer tok = new StringTokenizer(stat, ",");
-                while (tok.hasMoreTokens()) {
-                    String cur = tok.nextToken().trim();
-                    if ( (cur.length() > 0) && (!_stats.contains(cur)) )
-                        _stats.add(cur);
-                }
-            } else {
-                stat = stat.trim();
-                if ( (stat.length() > 0) && (!_stats.contains(stat)) )
-                    _stats.add(stat);
-            }
-        }
-    }
-    
     public void setExplicitFilter(String foo) { _explicitFilter = true; }
     public void setExplicitFilterValue(String filter) { _explicitFilterValue = filter; }
     
@@ -74,7 +63,19 @@ public class ConfigStatsHandler extends FormHandler {
         
         if (_explicitFilter) {
             _stats.clear();
-            setStatList(_explicitFilterValue);
+            
+            if (_explicitFilterValue.indexOf(',') != -1) {
+                StringTokenizer tok = new StringTokenizer(_explicitFilterValue, ",");
+                while (tok.hasMoreTokens()) {
+                    String cur = tok.nextToken().trim();
+                    if ( (cur.length() > 0) && (!_stats.contains(cur)) )
+                        _stats.add(cur);
+                }
+            } else {
+                String stat = _explicitFilterValue.trim();
+                if ( (stat.length() > 0) && (!_stats.contains(stat)) )
+                    _stats.add(stat);
+            }
         }
         
         StringBuffer stats = new StringBuffer();
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
index 9f14c8b16b6f70009f25724cefd84616b08d76e1..1d66037afe5beeb4893c6be5093cd3f09d7bab93 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
@@ -4,6 +4,7 @@ import java.util.List;
 import java.util.ArrayList;
 
 import net.i2p.router.RouterContext;
+import net.i2p.util.Log;
 
 /**
  * Simple form handler base class - does not depend on servlets or jsp,
@@ -16,6 +17,7 @@ import net.i2p.router.RouterContext;
  */
 public class FormHandler {
     protected RouterContext _context;
+    protected Log _log;
     private String _nonce;
     protected String _action;
     private List _errors;
@@ -41,6 +43,7 @@ public class FormHandler {
     public void setContextId(String contextId) {
         try {
             _context = ContextHelper.getContext(contextId);
+            _log = _context.logManager().getLog(getClass());
         } catch (Throwable t) {
             t.printStackTrace();
         }
diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp
index 3209ce3f98fcc2b1b4bf06fe66e19fd9f4d59975..99735f68b7f9fa29cd6b32db19a08f0cd49b90a3 100644
--- a/apps/routerconsole/jsp/config.jsp
+++ b/apps/routerconsole/jsp/config.jsp
@@ -28,13 +28,13 @@
  <input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce")%>" />
  <input type="hidden" name="action" value="blah" />
 
- TCP port:
-     <input name="port" type="text" size="4" value="<jsp:getProperty name="nethelper" property="port" />" /> <br />
+ UDP port: <i><jsp:getProperty name="nethelper" property="udpPort" /></i><br />
+<!-- <input name="udpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="udpPort" />" /><br /> -->
+<b>You must poke a hole in your firewall or NAT (if applicable) to receive new inbound UDP packets on 
+this port from arbitrary peers (this requirement will be removed in i2p 0.6.1, but is necessary now)</b><br />
+ TCP port: <input name="tcpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="tcpPort" />" /> <br />
  <b>You must poke a hole in your firewall or NAT (if applicable) so that you can receive inbound TCP
- connections on it.</b>  Nothing will work if you don't.  Sorry.  We know how to make it so
- this restriction won't be necessary, but its later on in the 
- <a href="http://www.i2p.net/roadmap">roadmap</a> and we only have so many coder-hours (but if you want
- to help, please <a href="http://www.i2p.net/getinvolved">get involved!</a>)
+ connections on it (this requirement will be removed in i2p 0.6.1, but is necessary now)</b>
  <hr />
  
  <b>Bandwidth limiter</b><br />
@@ -57,7 +57,7 @@
     packets on port 123 to one of the pool.ntp.org machines (or some other SNTP server).</i>
  <hr />
  <input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br />
- <i>Changing the TCP port will force a 'soft restart' - dropping your connections and clients as 
+ <i>Changing the TCP or UDP port will force a 'soft restart' - dropping your connections and clients as 
     if the router was stopped and restarted.  <b>Please be patient</b> - it may take
     a few seconds to complete.</i>
  </form>
@@ -73,6 +73,13 @@
  "i2p.reseedURL=someURL" (e.g. java -Di2p.reseedURL=http://dev.i2p.net/i2pdb/ ...).  You can
  also do it manually by getting routerInfo-*.dat files from someone (a friend, someone on IRC,
  whatever) and saving them to your netDb/ directory.</p>
+<p>
+ With the SSU transport, the internal UDP port may be different from the external 
+ UDP port (in case of a firewall/NAT) - the UDP port field above specifies the 
+ external one and assumes they are the same, but if you want to set the internal 
+ port to something else, you can add "i2np.udp.internalPort=1234" to the
+ <a href="configadvanced.jsp">advanced</a> config and restart the router.
+</p>
 </div>
 
 </body>
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java
index aeab27d665803f56f74f3bd04ded1474fbf4ab49..710798b8750d9b963d668896fdc4e772f93b0b45 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java
@@ -33,7 +33,7 @@ public class ConnectionPacketHandler {
         boolean ok = verifyPacket(packet, con);
         if (!ok) {
             if ( (!packet.isFlagSet(Packet.FLAG_RESET)) && (_log.shouldLog(Log.ERROR)) )
-                _log.error("Packet does NOT verify: " + packet);
+                _log.error("Packet does NOT verify: " + packet + " on " + con);
             packet.releasePayload();
             return;
         }
@@ -305,16 +305,16 @@ public class ConnectionPacketHandler {
                     if (packet.getSequenceNum() <= 2) {
                         return true;
                     } else {
-                        if (_log.shouldLog(Log.WARN))
-                            _log.warn("Packet without RST or SYN where we dont know stream ID: " 
+                        if (_log.shouldLog(Log.ERROR))
+                            _log.error("Packet without RST or SYN where we dont know stream ID: " 
                                       + packet);
                         return false;
                     }
                 }
             } else {
                 if (!DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) {
-                    if (_log.shouldLog(Log.WARN))
-                        _log.warn("Packet received with the wrong reply stream id: " 
+                    if (_log.shouldLog(Log.ERROR))
+                        _log.error("Packet received with the wrong reply stream id: " 
                                   + con + " / " + packet);
                     return false;
                 } else {
@@ -331,8 +331,8 @@ public class ConnectionPacketHandler {
         if (DataHelper.eq(con.getReceiveStreamId(), packet.getSendStreamId())) {
             boolean ok = packet.verifySignature(_context, packet.getOptionalFrom(), null);
             if (!ok) {
-                if (_log.shouldLog(Log.WARN))
-                    _log.warn("Received unsigned / forged RST on " + con);
+                if (_log.shouldLog(Log.ERROR))
+                    _log.error("Received unsigned / forged RST on " + con);
                 return;
             } else {
                 if (_log.shouldLog(Log.DEBUG))
diff --git a/core/java/src/net/i2p/CoreVersion.java b/core/java/src/net/i2p/CoreVersion.java
index d587fa5faa6ec891c46cba9d6e9040248490a2fa..17d8502055b12e554733fa44634e32b48e20bf04 100644
--- a/core/java/src/net/i2p/CoreVersion.java
+++ b/core/java/src/net/i2p/CoreVersion.java
@@ -14,8 +14,8 @@ package net.i2p;
  *
  */
 public class CoreVersion {
-    public final static String ID = "$Revision: 1.34 $ $Date: 2005/04/06 10:43:26 $";
-    public final static String VERSION = "0.5.0.7";
+    public final static String ID = "$Revision: 1.35 $ $Date: 2005/04/20 15:14:20 $";
+    public final static String VERSION = "0.6";
 
     public static void main(String args[]) {
         System.out.println("I2P Core version: " + VERSION);
diff --git a/core/java/src/net/i2p/client/I2CPMessageProducer.java b/core/java/src/net/i2p/client/I2CPMessageProducer.java
index 068e41dafe32657d147ab6914ccd37b26e78a825..9af1fbd19ccb3ea2d40bbdeb739752ac8f5d2691 100644
--- a/core/java/src/net/i2p/client/I2CPMessageProducer.java
+++ b/core/java/src/net/i2p/client/I2CPMessageProducer.java
@@ -121,7 +121,7 @@ class I2CPMessageProducer {
      * garlic crypto added by the router)
      *
      */
-    static final boolean END_TO_END_CRYPTO = true;
+    static final boolean END_TO_END_CRYPTO = false;
     
     /**
      * Create a new signed payload and send it off to the destination
diff --git a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java
index 7fc4df6a748e823e0a5c7d1ea149ca394f3533f6..0fda386c0fca6f4b5033a54ff688bc5f579bb787 100644
--- a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java
+++ b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java
@@ -260,7 +260,10 @@ public class DHSessionKeyBuilder {
      *
      */
     public byte[] getMyPublicValueBytes() {
-        BigInteger bi = getMyPublicValue();
+        return toByteArray(getMyPublicValue());
+    }
+    
+    private static final byte[] toByteArray(BigInteger bi) {
         byte data[] = bi.toByteArray();
         byte rv[] = new byte[256];
         if (data.length == 257) // high byte has the sign bit
@@ -299,6 +302,9 @@ public class DHSessionKeyBuilder {
     public BigInteger getPeerPublicValue() {
         return _peerValue;
     }
+    public byte[] getPeerPublicValueBytes() {
+        return toByteArray(getPeerPublicValue());
+    }
 
     /**
      * Retrieve the session key, calculating it if necessary (and if possible).
diff --git a/core/java/src/net/i2p/util/BufferedRandomSource.java b/core/java/src/net/i2p/util/BufferedRandomSource.java
index 8103a56e067595ea3cded86a8be16d5dfcf68d0d..e344b5a2ae531b9d82004c2f689ecf3b54e96036 100644
--- a/core/java/src/net/i2p/util/BufferedRandomSource.java
+++ b/core/java/src/net/i2p/util/BufferedRandomSource.java
@@ -225,4 +225,4 @@ public class BufferedRandomSource extends RandomSource {
         }
         return buf.toString();
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/test/net/i2p/crypto/DHSessionKeyBuilderTest.java b/core/java/test/net/i2p/crypto/DHSessionKeyBuilderTest.java
index 416954e43c898f6ecb565ccc68ff4c84d29d110f..c91948d55b9e76833d7e286f6090030bec9d01af 100644
--- a/core/java/test/net/i2p/crypto/DHSessionKeyBuilderTest.java
+++ b/core/java/test/net/i2p/crypto/DHSessionKeyBuilderTest.java
@@ -25,9 +25,13 @@ public class DHSessionKeyBuilderTest extends TestCase {
             DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder();
             DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder();
             BigInteger pub1 = builder1.getMyPublicValue();
-            builder2.setPeerPublicValue(pub1);
             BigInteger pub2 = builder2.getMyPublicValue();
-            builder1.setPeerPublicValue(pub2);
+            try {
+                builder2.setPeerPublicValue(pub1);
+                builder1.setPeerPublicValue(pub2);
+            } catch (DHSessionKeyBuilder.InvalidPublicParameterException ippe) {
+                assertTrue(ippe.getMessage(), true);
+            }
             SessionKey key1 = builder1.getSessionKey();
             SessionKey key2 = builder2.getSessionKey();
 
@@ -44,4 +48,4 @@ public class DHSessionKeyBuilderTest extends TestCase {
             assertEquals(origVal, tranVal);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/test/net/i2p/data/MessagePayloadMessageTest.java b/core/java/test/net/i2p/data/MessagePayloadMessageTest.java
index bdd71bf7d18463044000adc502d5042b26a5d645..f818ade52d7e207fbe9f32ff35f4073ca673c4cc 100644
--- a/core/java/test/net/i2p/data/MessagePayloadMessageTest.java
+++ b/core/java/test/net/i2p/data/MessagePayloadMessageTest.java
@@ -30,9 +30,9 @@ import net.i2p.util.Log;
  public class MessagePayloadMessageTest extends StructureTest {
     public DataStructure createDataStructure() throws DataFormatException {
         MessagePayloadMessage msg = new MessagePayloadMessage();
-        msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure());
+        msg.setMessageId(123);
         msg.setPayload((Payload)(new PayloadTest()).createDataStructure());
-        msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure());
+        msg.setSessionId(321);
         return msg; 
     }
     public DataStructure createStructureToRead() { return new MessagePayloadMessage(); }
@@ -56,4 +56,4 @@ import net.i2p.util.Log;
         assertEquals(orig, ds);
     }
     
-}
\ No newline at end of file
+}
diff --git a/core/java/test/net/i2p/data/MessageStatusMessageTest.java b/core/java/test/net/i2p/data/MessageStatusMessageTest.java
index c042fe918ca876b8652508d051b8c7eef55be7be..cd8aabc67a31ea9fbd438b300a671562d62204bc 100644
--- a/core/java/test/net/i2p/data/MessageStatusMessageTest.java
+++ b/core/java/test/net/i2p/data/MessageStatusMessageTest.java
@@ -22,8 +22,8 @@ import net.i2p.data.i2cp.SessionId;
 public class MessageStatusMessageTest extends StructureTest {
     public DataStructure createDataStructure() throws DataFormatException {
         MessageStatusMessage msg = new MessageStatusMessage();
-        msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure());
-        msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure());
+        msg.setSessionId(42);
+        msg.setMessageId(41);
         msg.setSize(1024*1024*42L);
         msg.setStatus(MessageStatusMessage.STATUS_AVAILABLE);
         msg.setNonce(1);
diff --git a/core/java/test/net/i2p/data/ReceiveMessageBeginMessageTest.java b/core/java/test/net/i2p/data/ReceiveMessageBeginMessageTest.java
index 9bb09a9dae930892ecebf91d8f91083ad033fa9a..19edd8a61064bc98af075d30d49b12a05ad89452 100644
--- a/core/java/test/net/i2p/data/ReceiveMessageBeginMessageTest.java
+++ b/core/java/test/net/i2p/data/ReceiveMessageBeginMessageTest.java
@@ -22,8 +22,8 @@ import net.i2p.data.i2cp.SessionId;
 public class ReceiveMessageBeginMessageTest extends StructureTest {
     public DataStructure createDataStructure() throws DataFormatException {
         ReceiveMessageBeginMessage msg = new ReceiveMessageBeginMessage();
-        msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure());
-        msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure());
+        msg.setSessionId(321);
+        msg.setMessageId(123);
         return msg; 
     }
     public DataStructure createStructureToRead() { return new ReceiveMessageBeginMessage(); }
diff --git a/core/java/test/net/i2p/data/ReceiveMessageEndMessageTest.java b/core/java/test/net/i2p/data/ReceiveMessageEndMessageTest.java
index 6402dcee3a774ea893714f41af18a2b8fad6020c..4e33406d5d9aa3944a4cb47dba2db041671a618a 100644
--- a/core/java/test/net/i2p/data/ReceiveMessageEndMessageTest.java
+++ b/core/java/test/net/i2p/data/ReceiveMessageEndMessageTest.java
@@ -22,8 +22,8 @@ import net.i2p.data.i2cp.SessionId;
 public class ReceiveMessageEndMessageTest extends StructureTest {
     public DataStructure createDataStructure() throws DataFormatException {
         ReceiveMessageEndMessage msg = new ReceiveMessageEndMessage();
-        msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure());
-        msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure());
+        msg.setSessionId(321);
+        msg.setMessageId(123);
         return msg; 
     }
     public DataStructure createStructureToRead() { return new ReceiveMessageEndMessage(); }
diff --git a/history.txt b/history.txt
index c30f9e23dafd9b41ce42f8824f4dc03b6e291506..599496efa224c38fdbcaec287ddad3008b68a248 100644
--- a/history.txt
+++ b/history.txt
@@ -1,4 +1,23 @@
-$Id: history.txt,v 1.216 2005/07/21 17:37:16 jrandom Exp $
+$Id: history.txt,v 1.217 2005/07/22 19:15:59 jrandom Exp $
+
+* 2005-07-27  0.6 released
+
+2005-07-27  jrandom
+    * Enabled SSU as the default top priority transport, adjusting the 
+      config.jsp page accordingly.
+    * Add verification fields to the SSU and TCP connection negotiation (not
+      compatible with previous builds)
+    * Enable the backwards incompatible tunnel crypto change as documented in
+      tunnel-alt.html (have each hop encrypt the received IV before using it,
+      then encrypt it again before sending it on)
+    * Disable the I2CP encryption, leaving in place the end to end garlic 
+      encryption (another backwards incompatible change)
+    * Adjust the protocol versions on the TCP and SSU transports so that they
+      won't talk to older routers.
+    * Fix up the config stats handling again
+    * Fix a rare off-by-one in the SSU fragmentation
+    * Reduce some unnecessary netDb resending by inluding the peers queried
+      successfully in the store redundancy count.
 
 2005-07-22  jrandom
     * Use the small thread pool for I2PTunnelHTTPServer (already used for 
diff --git a/initialNews.xml b/initialNews.xml
index 95048d59f3a06a6c6742aeb052192cc46ec660a7..04c5c35ef4a90a496f71ccc01571d88bbb3f2831 100644
--- a/initialNews.xml
+++ b/initialNews.xml
@@ -1,12 +1,12 @@
-<i2p.news date="$Date: 2005/04/06 10:43:25 $">
- <i2p.release version="0.5.0.7" date="2005/04/20" minVersion="0.5.0.4"
+<i2p.news date="$Date: 2005/04/20 15:14:18 $">
+ <i2p.release version="0.6" date="2005/07/27" minVersion="0.6"
               anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
               publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
               anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/April-2005/000709.html" 
               publicannouncement="http://dev.i2p.net/pipermail/i2p/April-2005/000709.html" />
- <i2p.notes date="2005/04/19"
-            anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/April-2005/000708.html"
-            publicurl="http://dev.i2p.net/pipermail/i2p/April-2005/000708.html"
+ <i2p.notes date="2005/07/26"
+            anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-July/000823.html"
+            publicurl="http://dev.i2p.net/pipermail/i2p/2005-July/000823.html"
             anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting138"
             publiclogs="http://www.i2p.net/meeting138" />
 <h1>Congratulations on getting I2P installed!</h1>
diff --git a/installer/install.xml b/installer/install.xml
index 567e9c2da1056d66aa0e832ed5197553ecd166f1..4f4e9670fcfca86f7b669b30decdd9aea3b3a7af 100644
--- a/installer/install.xml
+++ b/installer/install.xml
@@ -4,7 +4,7 @@
 
     <info>
         <appname>i2p</appname>
-        <appversion>0.5.0.7</appversion>
+        <appversion>0.6</appversion>
         <authors>
             <author name="I2P" email="support@i2p.net"/>
         </authors>
diff --git a/news.xml b/news.xml
index ae8936df2317356b13a2f9c88d116e3356e146c9..bdab5b05d8c941d715d1722109e8fee10ab9fbf7 100644
--- a/news.xml
+++ b/news.xml
@@ -1,20 +1,15 @@
-<i2p.news date="$Date: 2005/07/11 22:56:42 $">
- <i2p.release version="0.5.0.7" date="2005/04/20" minVersion="0.5.0.4"
+<i2p.news date="$Date: 2005/07/13 16:59:01 $">
+ <i2p.release version="0.7" date="2005/07/27" minVersion="0.6"
               anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
               publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
               anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-April/000709.html" 
               publicannouncement="http://dev.i2p.net/pipermail/i2p/2005-April/000709.html" />
  <i2p.notes date="2005/04/19"
-            anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-April/000723.html"
-            publicurl="http://dev.i2p.net/pipermail/i2p/2005-April/000723.html"
+            anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-July/000823.html"
+            publicurl="http://dev.i2p.net/pipermail/i2p/2005-July/000823.html"
             anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting139"
             publiclogs="http://www.i2p.net/meeting138" />
-Thanks to those helping out with the SSU test - there have been lots
-of updates lately, so upgrading to the latest CVS HEAD (currently
-0.5.0.7-14 as of 2005/07/13) would be worthwhile, and the archived 
-i2pupdate.zip mentioned 
-<a href="http://dev.i2p.net/~jrandom/ssu_test.txt">before</a> 
-may not always be up to date.
+Welcome to the new 0.6 series of releases, using the new SSU transport!
 <br />
 </i2p.news>
 
diff --git a/readme.html b/readme.html
index 88108d0cced5b497d2bf231a502ee0073857734c..d1e36dc298953c225df2ff71559c3686a18c7336 100644
--- a/readme.html
+++ b/readme.html
@@ -15,11 +15,10 @@ listed (if not, <a href="#trouble">see below</a>).  Once those are up, you can:<
          <li><a href="http://duck.i2p/">duck.i2p</a>: duck's eepsite, with links to other active sites</li>
          <li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li>
          <li><a href="http://orion.i2p/">orion.i2p</a>: a site which tracks eepsite uptime and changes</li>
-         <li><a href="http://files.i2p/">files.i2p</a>: a search engine that tries to keep track of things on I2P</li>
          <li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li>
          <li><a href="http://www.i2p/">www.i2p</a>: a secure and anonymous connection to <a href="http://www.i2p.net/">www.i2p.net</a></li>
          <li><a href="http://dev.i2p/">dev.i2p</a>: a secure and anonymous connection to <a href="http://dev.i2p.net/">dev.i2p.net</a></li>
-         <li>Freenet proxies: <a href="http://fproxy.i2p/">fproxy.i2p</a> and <a href="http://freenet.eco.i2p/">freenet.eco.i2p</a></li>
+         <li>Freenet proxies: <a href="http://fproxy.i2p/">fproxy.i2p</a></li>
      </ul>
      There are many more eepsites - just follow the links from the ones you see,
      bookmark your favorites, and visit them often!</li>
@@ -56,7 +55,7 @@ IRC (be sure to split it into two lines, as its too long for one).</p>
 
 <p>If the left hand side has a warning, telling you to check your NAT or firewall, please
 see the <a href="/config.jsp">config page</a> and make sure that you can receive <b>inbound
-TCP connections on port 8887</b> (or another port that you specify).  Problems forwarding
+TCP and UDP connections on port 8887</b> (or another port that you specify).  Problems forwarding
 that port account for the vast majority of issues people run into.  When it says 
 "Active: 72/85", the "72" means how many peers you are connected with now, and "85" means 
 how many you have spoken with recently - if that first number is 0, you can bet that there
diff --git a/router/doc/tunnel-alt.html b/router/doc/tunnel-alt.html
index 1b868e949dd6e443bbda3d7c3f18a8ffb8ab6d37..8749e202800a13be4b9578f0d84b1e2969dd70fa 100644
--- a/router/doc/tunnel-alt.html
+++ b/router/doc/tunnel-alt.html
@@ -1,4 +1,4 @@
-<code>$Id: tunnel-alt.html,v 1.7 2005/02/16 19:48:18 jrandom Exp $</code>
+<code>$Id: tunnel-alt.html,v 1.8 2005/07/07 16:16:57 jrandom Exp $</code>
 <pre>
 1) <a href="#tunnel.overview">Tunnel overview</a>
 2) <a href="#tunnel.operation">Tunnel operation</a>
@@ -173,9 +173,12 @@ the initial preprocessed data.</p>
 the same previous hop as before (initialized when the first message comes through
 the tunnel).  If the previous peer is a different router, or if the message has
 already been seen, the message is dropped.  The participant then encrypts the 
-data with AES256/CBC using the participant's layer key and the received IV, 
-updates the IV by encrypting it with AES256/ECB using the participant's IV key,
-then forwards the tuple {nextTunnelId, nextIV, encryptedData} to the next hop.</p>
+received IV with AES256/ECB using their IV key to determine the current IV, uses 
+that IV with the participant's layer key to encrypt the data, encrypts the 
+current IV with AES256/ECB using their IV key again, then forwards the tuple 
+{nextTunnelId, nextIV, encryptedData} to the next hop.  This double encryption
+of the IV (both before and after use) help address a certain class of
+confirmation attacks.</p>
 
 <p>Duplicate message detection is handled by a decaying Bloom filter on message
 IVs.  Each router maintains a single Bloom filter to contain the XOR of the IV and
diff --git a/router/doc/udp.html b/router/doc/udp.html
index ac1eb9256605013236e2b87320bbb5199654c1e7..bafe3411d2a1df7e0924e2d5bffc5a24e83c2bbe 100644
--- a/router/doc/udp.html
+++ b/router/doc/udp.html
@@ -1,4 +1,4 @@
-<code>$Id: udp.html,v 1.12 2005/04/09 18:15:53 jrandom Exp $</code>
+<code>$Id: udp.html,v 1.13 2005/05/01 15:08:08 jrandom Exp $</code>
 
 <h1>Secure Semireliable UDP (SSU)</h1>
 <b>DRAFT</b>
@@ -141,7 +141,7 @@ around briefly, to address packet loss and reordering.</p>
         <li>4 byte timestamp (seconds from the epoch) for use in the DSA 
             signature</li>
         <li>40 byte DSA signature of the critical exchanged data 
-            (Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's
+            (X + Y + Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's
             new relay tag + Bob's signed on time), encrypted with another 
             layer of encryption using the negotiated sessionKey.  The IV 
             is reused here.</li>
@@ -197,7 +197,7 @@ bits 4-7: total identity fragments</pre></li>
         <li>on the last identity fragment, the signed on time is
             included after the identity fragment, and the last 40 
             bytes contain the DSA signature of the critical exchanged 
-            data (Alice's IP + Alice's port + Bob's IP + Bob's port
+            data (X + Y + Alice's IP + Alice's port + Bob's IP + Bob's port
             + Alice's new relay key + Alice's signed on time)</li>
         </ul></td></tr>
 <tr><td align="right" valign="top"><b>Key used:</b></td>
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 01616a7f6883d63d9e34bf41033d50fe911457f6..679cbddcdabcafadd42a231d5677f7eddd2843ca 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
  *
  */
 public class RouterVersion {
-    public final static String ID = "$Revision: 1.207 $ $Date: 2005/07/21 17:37:15 $";
-    public final static String VERSION = "0.5.0.7";
-    public final static long BUILD = 19;
+    public final static String ID = "$Revision: 1.208 $ $Date: 2005/07/22 19:15:58 $";
+    public final static String VERSION = "0.6";
+    public final static long BUILD = 0;
     public static void main(String args[]) {
         System.out.println("I2P Router version: " + VERSION);
         System.out.println("Router ID: " + RouterVersion.ID);
diff --git a/router/java/src/net/i2p/router/StatisticsManager.java b/router/java/src/net/i2p/router/StatisticsManager.java
index e3983f655f494de880f6039e0fdfb09945d40ece..ff49f8e0d84206d8f70eb2369e03f956fffd9be9 100644
--- a/router/java/src/net/i2p/router/StatisticsManager.java
+++ b/router/java/src/net/i2p/router/StatisticsManager.java
@@ -102,12 +102,12 @@ public class StatisticsManager implements Service {
             stats.putAll(_context.profileManager().summarizePeers(_publishedStats));
 
             includeThroughput(stats);
-            includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
+            //includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
             includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
-            includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
+            //includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
             includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 });
-            includeRate("tunnel.fullFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
-            includeRate("tunnel.smallFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
+            //includeRate("tunnel.fullFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
+            //includeRate("tunnel.smallFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
             includeRate("tunnel.testFailedTime", stats, new long[] { 60*60*1000 });
             
             includeRate("tunnel.buildFailure", stats, new long[] { 60*60*1000 });
@@ -117,22 +117,26 @@ public class StatisticsManager implements Service {
             includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 });
             includeRate("tunnel.corruptMessage", stats, new long[] { 60*60*1000l, 3*60*60*1000l });
             
-            includeRate("router.throttleTunnelProbTestSlow", stats, new long[] { 60*60*1000 });
-            includeRate("router.throttleTunnelProbTooFast", stats, new long[] { 60*60*1000 });
-            includeRate("router.throttleTunnelProcessingTime1m", stats, new long[] { 60*60*1000 });
+            //includeRate("router.throttleTunnelProbTestSlow", stats, new long[] { 60*60*1000 });
+            //includeRate("router.throttleTunnelProbTooFast", stats, new long[] { 60*60*1000 });
+            //includeRate("router.throttleTunnelProcessingTime1m", stats, new long[] { 60*60*1000 });
 
             includeRate("router.fastPeers", stats, new long[] { 60*60*1000 });
 
             includeRate("clock.skew", stats, new long[] { 10*60*1000, 3*60*60*1000, 24*60*60*1000 });
             
-            includeRate("transport.sendProcessingTime", stats, new long[] { 60*60*1000 });
-            includeRate("jobQueue.jobRunSlow", stats, new long[] { 10*60*1000l, 60*60*1000l });
+            //includeRate("transport.sendProcessingTime", stats, new long[] { 60*60*1000 });
+            //includeRate("jobQueue.jobRunSlow", stats, new long[] { 10*60*1000l, 60*60*1000l });
             includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*60*1000 });
             includeRate("tunnel.participatingTunnels", stats, new long[] { 5*60*1000, 60*60*1000 });
             includeRate("tunnel.testSuccessTime", stats, new long[] { 60*60*1000l, 24*60*60*1000l });
             includeRate("client.sendAckTime", stats, new long[] { 60*60*1000 }, true);
-            includeRate("stream.con.sendDuplicateSize", stats, new long[] { 60*60*1000 });
-            includeRate("stream.con.receiveDuplicateSize", stats, new long[] { 60*60*1000 });
+            includeRate("udp.sendConfirmTime", stats, new long[] { 10*60*1000 });
+            includeRate("udp.sendVolleyTime", stats, new long[] { 10*60*1000 });
+            includeRate("udp.ignoreRecentDuplicate", stats, new long[] { 10*60*1000 });
+            includeRate("udp.congestionOccurred", stats, new long[] { 10*60*1000 });
+            //includeRate("stream.con.sendDuplicateSize", stats, new long[] { 60*60*1000 });
+            //includeRate("stream.con.receiveDuplicateSize", stats, new long[] { 60*60*1000 });
             stats.setProperty("stat_uptime", DataHelper.formatDuration(_context.router().getUptime()));
             stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
             _log.debug("Publishing peer rankings");
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
index a8359e09faf3a53fb5fa9c7319f2d46ee58b1568..dcdd7405f028690809c024845c927b8de2b88c9c 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
@@ -281,7 +281,7 @@ class StoreJob extends JobImpl {
             getContext().profileManager().dbStoreSent(_peer.getIdentity().getHash(), howLong);
             getContext().statManager().addRateData("netDb.ackTime", howLong, howLong);
 
-            if (_state.getSuccessful().size() >= REDUNDANCY) {
+            if (_state.getCompleteCount() >= REDUNDANCY) {
                 succeed();
             } else {
                 sendNext();
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java
index 584f3eb3a4e9cceb8da3092e77fbea590b410ec0..12520f992f76cef095243d9f0fd7776d432e52d0 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java
@@ -21,6 +21,7 @@ class StoreState {
     private HashSet _successfulExploratoryPeers;
     private HashSet _failedPeers;
     private HashSet _attemptedPeers;
+    private int _completeCount;
     private volatile long _completed;
     private volatile long _started;
 
@@ -34,8 +35,10 @@ class StoreState {
         _pendingPeers = new HashSet(16);
         _pendingPeerTimes = new HashMap(16);
         _attemptedPeers = new HashSet(16);
-        if (toSkip != null)
+        if (toSkip != null) {
             _attemptedPeers.addAll(toSkip);
+            _completeCount = toSkip.size();
+        }
         _failedPeers = new HashSet(16);
         _successfulPeers = new HashSet(16);
         _successfulExploratoryPeers = new HashSet(16);
@@ -75,6 +78,7 @@ class StoreState {
         if (completed)
             _completed = _context.clock().now();
     }
+    public int getCompleteCount() { return _completeCount; }
 
     public long getWhenStarted() { return _started; }
     public long getWhenCompleted() { return _completed; }
@@ -110,6 +114,7 @@ class StoreState {
         synchronized (_successfulPeers) {
             _successfulPeers.add(peer);
         }
+        _completeCount++;
         return rv;
     }
 
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index 8db02b63b936823327a1afa0d94deeecf8fed1b6..551c9b9f354d74bf9417e0d6637d304798919d67 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -34,6 +34,7 @@ public class TransportManager implements TransportEventListener {
 
     private final static String PROP_DISABLE_TCP = "i2np.tcp.disable";
     private final static String PROP_ENABLE_UDP = "i2np.udp.enable";
+    private static final String DEFAULT_ENABLE_UDP = "true";
     
     public TransportManager(RouterContext context) {
         _context = context;
@@ -63,7 +64,9 @@ public class TransportManager implements TransportEventListener {
             _transports.add(t);
         }
         String enableUDP = _context.router().getConfigSetting(PROP_ENABLE_UDP);
-        if ( (enableUDP != null) && (Boolean.valueOf(enableUDP).booleanValue())) {
+        if (enableUDP == null)
+            enableUDP = DEFAULT_ENABLE_UDP;
+        if ("true".equalsIgnoreCase(enableUDP)) {
             UDPTransport udp = new UDPTransport(_context);
             udp.setListener(this);
             _transports.add(udp);
diff --git a/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java b/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java
index c0392105100c975dd5f12d1d67e95b776c203dba..62ad79c184c1757d214225dbeabf408a51a05d2b 100644
--- a/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java
+++ b/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java
@@ -529,8 +529,12 @@ public class ConnectionBuilder {
             return false;
         }
         
+        // our public == X, since we are establishing the connection
+        byte X[] = builder.getMyPublicValueBytes();
+        byte Y[] = builder.getPeerPublicValueBytes();
+        
         // send: routerInfo + currentTime 
-        //       + S(routerInfo + currentTime + nonce + nextTag, routerIdent.signingKey)
+        //       + S(routerInfo + currentTime + nonce + nextTag + X + Y, routerIdent.signingKey)
         try {
             ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
             _context.router().getRouterInfo().writeBytes(baos);
@@ -540,6 +544,8 @@ public class ConnectionBuilder {
             
             baos.write(_nonce.getData());
             baos.write(_nextConnectionTag.getData());
+            baos.write(X);
+            baos.write(Y);
             Signature sig = _context.dsa().sign(baos.toByteArray(), 
                                                 _context.keyManager().getSigningPrivateKey());
             
@@ -556,7 +562,7 @@ public class ConnectionBuilder {
         }
         
         // read: routerInfo + status + properties 
-        //       + S(routerInfo + status + properties + nonce + nextTag, routerIdent.signingKey)
+        //       + S(routerInfo + status + properties + nonce + nextTag + X + Y, routerIdent.signingKey)
         try {
             RouterInfo peer = new RouterInfo();
             peer.readBytes(_rawIn);
@@ -578,6 +584,8 @@ public class ConnectionBuilder {
             DataHelper.writeProperties(baos, props);
             baos.write(_nonce.getData());
             baos.write(_nextConnectionTag.getData());
+            baos.write(X);
+            baos.write(Y);
             ok = _context.dsa().verifySignature(sig, baos.toByteArray(), 
                                                 peer.getIdentity().getSigningPublicKey());
             
diff --git a/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java b/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java
index 249a3265f7c10d52314846b01575e53553e92339..e12f45ad54c9654594ed4de02da35f7fea47b742 100644
--- a/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java
+++ b/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java
@@ -555,8 +555,12 @@ public class ConnectionHandler {
         long clockSkew = 0;
         boolean sigOk = false;
         
+        // our public == Y, since we are receiving the connection
+        byte X[] = builder.getPeerPublicValueBytes();
+        byte Y[] = builder.getMyPublicValueBytes();
+        
         // read: routerInfo + currentTime 
-        //       + S(routerInfo + currentTime + nonce + nextTag, routerIdent.signingKey)
+        //       + S(routerInfo + currentTime + nonce + nextTag + X + Y, routerIdent.signingKey)
         try {
             RouterInfo info = new RouterInfo();
             info.readBytes(_rawIn);
@@ -569,6 +573,8 @@ public class ConnectionHandler {
             DataHelper.writeDate(baos, now);
             baos.write(_nonce.getData());
             baos.write(_nextConnectionTag.getData());
+            baos.write(X);
+            baos.write(Y);
             
             sigOk = _context.dsa().verifySignature(sig, baos.toByteArray(), 
                                                         info.getIdentity().getSigningPublicKey());
@@ -589,7 +595,7 @@ public class ConnectionHandler {
         boolean reachable = verifyReachability();
         
         // send: routerInfo + status + properties 
-        //       + S(routerInfo + status + properties + nonce + nextTag, routerIdent.signingKey)
+        //       + S(routerInfo + status + properties + nonce + nextTag + X + Y, routerIdent.signingKey)
         try {
             ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
             _context.router().getRouterInfo().writeBytes(baos);
@@ -629,6 +635,8 @@ public class ConnectionHandler {
             
             baos.write(_nonce.getData());
             baos.write(_nextConnectionTag.getData());
+            baos.write(X);
+            baos.write(Y);
             
             Signature sig = _context.dsa().sign(baos.toByteArray(), 
                                                 _context.keyManager().getSigningPrivateKey());
diff --git a/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java b/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java
index d6052d0382be65c8842584cfc385480adac385cb..d2ca97c075ff892257764ba00c75d80c80888044 100644
--- a/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java
@@ -89,7 +89,7 @@ public class TCPTransport extends TransportImpl {
     public static final int DEFAULT_ESTABLISHERS = 3;
     
     /** Ordered list of supported I2NP protocols */
-    public static final int[] SUPPORTED_PROTOCOLS = new int[] { 4 }; // drop <= 0.5.0.3
+    public static final int[] SUPPORTED_PROTOCOLS = new int[] { 5 }; // drop < 0.6
     /** blah, people shouldnt use defaults... */
     public static final int DEFAULT_LISTEN_PORT = 8887;
     
diff --git a/router/java/src/net/i2p/router/transport/udp/ACKSender.java b/router/java/src/net/i2p/router/transport/udp/ACKSender.java
index e3d424ee2935d567a6959d99ba1f4748c6850fe2..e788213f9a471ed75a4b75515a05b092c792ed6d 100644
--- a/router/java/src/net/i2p/router/transport/udp/ACKSender.java
+++ b/router/java/src/net/i2p/router/transport/udp/ACKSender.java
@@ -98,7 +98,8 @@ public class ACKSender implements Runnable {
                 
                 if ( (ackBitfields != null) && (ackBitfields.size() > 0) ) {
                     _context.statManager().addRateData("udp.sendACKCount", ackBitfields.size(), 0);
-                    _context.statManager().addRateData("udp.sendACKRemaining", remaining, 0);
+                    if (remaining > 0)
+                        _context.statManager().addRateData("udp.sendACKRemaining", remaining, 0);
                     now = _context.clock().now();
                     if (lastSend < 0)
                         lastSend = now - 1;
diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
index b464ff6d652e47275c624e12dd621a0820893e72..76cd9a488f3355cb14149e06b1e7cce3736d032c 100644
--- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
@@ -63,8 +63,7 @@ public class EstablishmentManager {
     /**
      * Grab the active establishing state
      */
-    InboundEstablishState getInboundState(InetAddress fromHost, int fromPort) {
-        RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
+    InboundEstablishState getInboundState(RemoteHostId from) {
         synchronized (_inboundStates) {
             InboundEstablishState state = (InboundEstablishState)_inboundStates.get(from);
             if ( (state == null) && (_log.shouldLog(Log.DEBUG)) )
@@ -73,8 +72,7 @@ public class EstablishmentManager {
         }
     }
     
-    OutboundEstablishState getOutboundState(InetAddress fromHost, int fromPort) {
-        RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
+    OutboundEstablishState getOutboundState(RemoteHostId from) {
         synchronized (_outboundStates) {
             OutboundEstablishState state = (OutboundEstablishState)_outboundStates.get(from);
             if ( (state == null) && (_log.shouldLog(Log.DEBUG)) )
@@ -121,12 +119,12 @@ public class EstablishmentManager {
      * Got a SessionRequest (initiates an inbound establishment)
      *
      */
-    void receiveSessionRequest(RemoteHostId from, InetAddress host, int port, UDPPacketReader reader) {
+    void receiveSessionRequest(RemoteHostId from, UDPPacketReader reader) {
         InboundEstablishState state = null;
         synchronized (_inboundStates) {
             state = (InboundEstablishState)_inboundStates.get(from);
             if (state == null) {
-                state = new InboundEstablishState(_context, host, port, _transport.getLocalPort());
+                state = new InboundEstablishState(_context, from.getIP(), from.getPort(), _transport.getLocalPort());
                 _inboundStates.put(from, state);
             }
         }
diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java
index 8f426f442ba8e558af68074b5bf7edca27ea586d..f39f67d473d3d393008e55efc04b4908bcabd867 100644
--- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java
+++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java
@@ -66,10 +66,10 @@ public class InboundEstablishState {
     /** we have completely received all of the confirmation packets */
     public static final int STATE_CONFIRMED_COMPLETELY = 4;
     
-    public InboundEstablishState(RouterContext ctx, InetAddress remoteHost, int remotePort, int localPort) {
+    public InboundEstablishState(RouterContext ctx, byte remoteIP[], int remotePort, int localPort) {
         _context = ctx;
         _log = ctx.logManager().getLog(InboundEstablishState.class);
-        _aliceIP = remoteHost.getAddress();
+        _aliceIP = remoteIP;
         _alicePort = remotePort;
         _remoteHostId = new RemoteHostId(_aliceIP, _alicePort);
         _bobPort = localPort;
@@ -141,7 +141,8 @@ public class InboundEstablishState {
      *       new relay tag + Bob's signed on time
      */
     private void signSessionCreated() {
-        byte signed[] = new byte[_aliceIP.length + 2
+        byte signed[] = new byte[256 + 256 // X + Y
+                                 + _aliceIP.length + 2
                                  + _bobIP.length + 2
                                  + 4 // sent relay tag
                                  + 4 // signed on time
@@ -149,6 +150,12 @@ public class InboundEstablishState {
         _sentSignedOnTime = _context.clock().now() / 1000;
         
         int off = 0;
+        System.arraycopy(_receivedX, 0, signed, off, _receivedX.length);
+        off += _receivedX.length;
+        if (_sentY == null)
+            _sentY = getSentY();
+        System.arraycopy(_sentY, 0, signed, off, _sentY.length);
+        off += _sentY.length;
         System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
         off += _aliceIP.length;
         DataHelper.toLong(signed, off, 2, _alicePort);
@@ -166,6 +173,8 @@ public class InboundEstablishState {
         if (_log.shouldLog(Log.DEBUG)) {
             StringBuffer buf = new StringBuffer(128);
             buf.append("Signing sessionCreated:");
+            buf.append(" ReceivedX: ").append(Base64.encode(_receivedX));
+            buf.append(" SentY: ").append(Base64.encode(_sentY));
             buf.append(" AliceIP: ").append(Base64.encode(_aliceIP));
             buf.append(" AlicePort: ").append(_alicePort);
             buf.append(" BobIP: ").append(Base64.encode(_bobIP));
@@ -266,13 +275,18 @@ public class InboundEstablishState {
         try {
             peer.readBytes(in);
             
-            byte signed[] = new byte[_aliceIP.length + 2
+            byte signed[] = new byte[256+256 // X + Y
+                                     + _aliceIP.length + 2
                                      + _bobIP.length + 2
                                      + 4 // Alice's relay key
                                      + 4 // signed on time
                                      ];
 
             off = 0;
+            System.arraycopy(_receivedX, 0, signed, off, _receivedX.length);
+            off += _receivedX.length;
+            System.arraycopy(_sentY, 0, signed, off, _sentY.length);
+            off += _sentY.length;
             System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
             off += _aliceIP.length;
             DataHelper.toLong(signed, off, 2, _alicePort);
diff --git a/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java
index 91d181b695d2d60d088689045b10838449f1f435..d5e534f37426ade3d8395988cfe51bd56c4ea86a 100644
--- a/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java
+++ b/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java
@@ -152,7 +152,8 @@ public class InboundMessageFragments /*implements UDPTransport.PartialACKSource
                         _log.info("Message received completely!  " + state);
 
                     _context.statManager().addRateData("udp.receivedCompleteTime", state.getLifetime(), state.getLifetime());
-                    _context.statManager().addRateData("udp.receivedCompleteFragments", state.getFragmentCount(), state.getLifetime());
+                    if (state.getFragmentCount() > 0)
+                        _context.statManager().addRateData("udp.receivedCompleteFragments", state.getFragmentCount(), state.getLifetime());
                 } else if (messageExpired) {
                     state.releaseResources();
                     if (_log.shouldLog(Log.WARN))
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java
index f976973933838ec4c9772cb13eed28fe66863108..b64b796174ef5100c5071493d38327b58cfd1431 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java
@@ -234,13 +234,18 @@ public class OutboundEstablishState {
      *         new relay tag + Bob's signed on time
      */
     private boolean verifySessionCreated() {
-        byte signed[] = new byte[_aliceIP.length + 2
+        byte signed[] = new byte[256+256 // X + Y
+                                 + _aliceIP.length + 2
                                  + _bobIP.length + 2
                                  + 4 // sent relay tag
                                  + 4 // signed on time
                                  ];
         
         int off = 0;
+        System.arraycopy(_sentX, 0, signed, off, _sentX.length);
+        off += _sentX.length;
+        System.arraycopy(_receivedY, 0, signed, off, _receivedY.length);
+        off += _receivedY.length;
         System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
         off += _aliceIP.length;
         DataHelper.toLong(signed, off, 2, _alicePort);
@@ -287,7 +292,8 @@ public class OutboundEstablishState {
     public synchronized void prepareSessionConfirmed() {
         if (_sentSignedOnTime > 0)
             return;
-        byte signed[] = new byte[_aliceIP.length + 2
+        byte signed[] = new byte[256+256 // X + Y
+                             + _aliceIP.length + 2
                              + _bobIP.length + 2
                              + 4 // Alice's relay key
                              + 4 // signed on time
@@ -296,6 +302,10 @@ public class OutboundEstablishState {
         _sentSignedOnTime = _context.clock().now() / 1000;
         
         int off = 0;
+        System.arraycopy(_sentX, 0, signed, off, _sentX.length);
+        off += _sentX.length;
+        System.arraycopy(_receivedY, 0, signed, off, _receivedY.length);
+        off += _receivedY.length;
         System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
         off += _aliceIP.length;
         DataHelper.toLong(signed, off, 2, _alicePort);
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
index da8f28af66c08dbb1f8e265624619583c2994ec5..b20fccd5f3ac121908e5fa48067cf1e79295d6d1 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
@@ -35,7 +35,7 @@ public class OutboundMessageFragments {
     /** if we can handle more messages explicitly, set this to true */
     private boolean _allowExcess;
     
-    private static final int MAX_ACTIVE = 16;
+    private static final int MAX_ACTIVE = 32;
     // don't send a packet more than 10 times
     static final int MAX_VOLLEYS = 10;
     
@@ -414,8 +414,10 @@ public class OutboundMessageFragments {
                 _log.info("Received ack of " + messageId + " by " + ackedBy.toBase64() 
                           + " after " + state.getLifetime() + " and " + numSends + " sends");
             _context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime());
-            _context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime());
-            _context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount());
+            if (state.getFragmentCount() > 1)
+                _context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime());
+            if (numSends > 1)
+                _context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount());
             _transport.succeeded(state.getMessage());
             int numFragments = state.getFragmentCount();
             if (state.getPeer() != null) {
@@ -494,8 +496,10 @@ public class OutboundMessageFragments {
             
             if (isComplete) {
                 _context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime());
-                _context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime());
-                _context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount());
+                if (state.getFragmentCount() > 1)
+                    _context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime());
+                if (numSends > 1)
+                    _context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount());
                 _transport.succeeded(state.getMessage());
                 
                 if (state.getPeer() != null) {
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
index 7ac9bf77d5f7a0751e311f92e4ebb29fa7a05a6e..b955904e0b8a2dff226fc1bb20547e63c6d5f68a 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
@@ -225,10 +225,15 @@ public class OutboundMessageState {
     public boolean shouldSend(int fragmentNum) { return _fragmentSends[fragmentNum] >= (short)0; }
     public int fragmentSize(int fragmentNum) {
         if (_messageBuf == null) return -1;
-        if (fragmentNum + 1 == _fragmentSends.length)
-            return _messageBuf.getValid() % _fragmentSize;
-        else
+        if (fragmentNum + 1 == _fragmentSends.length) {
+            int valid = _messageBuf.getValid();
+            if (valid <= _fragmentSize)
+                return valid;
+            else
+                return valid % _fragmentSize;
+        } else {
             return _fragmentSize;
+        }
     }
 
     /**
@@ -241,10 +246,8 @@ public class OutboundMessageState {
      */
     public int writeFragment(byte out[], int outOffset, int fragmentNum) {
         int start = _fragmentSize * fragmentNum;
-        int end = start + _fragmentSize;
+        int end = start + fragmentSize(fragmentNum);
         if (_messageBuf == null) return -1;
-        if (end > _messageBuf.getValid())
-            end = _messageBuf.getValid();
         int toSend = end - start;
         System.arraycopy(_messageBuf.getData(), start, out, outOffset, toSend);
         if (_log.shouldLog(Log.DEBUG))
diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
index 278762ee2998340f350311600ada0e0d0ee8c391..503b8d5995984a67f1577ae06eb8b5f5a69163ee 100644
--- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
+++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
@@ -100,13 +100,12 @@ public class PacketHandler {
     private void handlePacket(UDPPacketReader reader, UDPPacket packet) {
         if (packet == null) return;
         
-        InetAddress remAddr = packet.getPacket().getAddress();
-        int remPort = packet.getPacket().getPort();
-        PeerState state = _transport.getPeerState(remAddr, remPort);
+        RemoteHostId rem = packet.getRemoteHost();
+        PeerState state = _transport.getPeerState(rem);
         if (state == null) {
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("Packet received is not for a connected peer");
-            InboundEstablishState est = _establisher.getInboundState(remAddr, remPort);
+            InboundEstablishState est = _establisher.getInboundState(rem);
             if (est != null) {
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug("Packet received IS for an inbound establishment");
@@ -114,7 +113,7 @@ public class PacketHandler {
             } else {
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug("Packet received is not for an inbound establishment");
-                OutboundEstablishState oest = _establisher.getOutboundState(remAddr, remPort);
+                OutboundEstablishState oest = _establisher.getOutboundState(rem);
                 if (oest != null) {
                     if (_log.shouldLog(Log.DEBUG))
                         _log.debug("Packet received IS for an outbound establishment");
@@ -152,9 +151,7 @@ public class PacketHandler {
                         _log.info("Validation with existing con failed, but validation as reestablish/stray passed");
                     packet.decrypt(_transport.getIntroKey());
                 } else {
-                    InetAddress remAddr = packet.getPacket().getAddress();
-                    int remPort = packet.getPacket().getPort();
-                    InboundEstablishState est = _establisher.getInboundState(remAddr, remPort);
+                    InboundEstablishState est = _establisher.getInboundState(packet.getRemoteHost());
                     if (est != null) {
                         if (_log.shouldLog(Log.DEBUG))
                             _log.debug("Packet from an existing peer IS for an inbound establishment");
@@ -304,13 +301,14 @@ public class PacketHandler {
         
         _context.statManager().addRateData("udp.receivePacketSkew", skew, packet.getLifetime());
         
-        InetAddress fromHost = packet.getPacket().getAddress();
-        int fromPort = packet.getPacket().getPort();
-        RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
+        //InetAddress fromHost = packet.getPacket().getAddress();
+        //int fromPort = packet.getPacket().getPort();
+        //RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
+        RemoteHostId from = packet.getRemoteHost();
         
         switch (reader.readPayloadType()) {
             case UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST:
-                _establisher.receiveSessionRequest(from, fromHost, fromPort, reader);
+                _establisher.receiveSessionRequest(from, reader);
                 break;
             case UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED:
                 _establisher.receiveSessionConfirmed(from, reader);
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java
index 2d8c82ce30fdf4e5e03ab49090e94fdd9156e201..0b36f8af8152ec6c1d5cf8ccb5f81671e7c86135 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerState.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java
@@ -541,10 +541,11 @@ public class PeerState {
             }
         }
 
-        _context.statManager().addRateData("udp.sendACKPartial", partialIncluded, rv.size() - partialIncluded);
         _lastACKSend = _context.clock().now();
         if (rv == null)
             rv = Collections.EMPTY_LIST;
+        if (partialIncluded > 0)
+            _context.statManager().addRateData("udp.sendACKPartial", partialIncluded, rv.size() - partialIncluded);
         return rv;
     }
     
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java
index df8b334c1879dcb8c3c41f2235c7935f1df776ef..21fe37b9d3aa954990f0b8f36d04bafb92d536ff 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java
@@ -37,7 +37,7 @@ public class UDPEndpoint {
             _receiver.startup();
         } catch (SocketException se) {
             if (_log.shouldLog(Log.ERROR))
-                _log.error("Unable to bind on " + _listenPort);
+                _log.error("Unable to bind on " + _listenPort, se);
         }
     }
     
@@ -45,11 +45,10 @@ public class UDPEndpoint {
         if (_sender != null) {
             _sender.shutdown();
             _receiver.shutdown();
-            _sender = null;
-            _receiver = null;
         }
     }
     
+    public void setListenPort(int newPort) { _listenPort = newPort; }
     public void updateListenPort(int newPort) {
         if (newPort == _listenPort) return;
         try {
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java
index ac7f600108ee74c194222795bab6f5ad4cf1f199..3443c502628b82dd0bc9fee382cf87bb47183488 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java
@@ -32,6 +32,7 @@ public class UDPPacket {
     private volatile byte[] _data;
     private volatile ByteArray _dataBuf;
     private volatile int _markedType;
+    private volatile RemoteHostId _remoteHost;
     private volatile boolean _released;
     private volatile Exception _releasedBy;
     private volatile Exception _acquiredBy;
@@ -78,6 +79,7 @@ public class UDPPacket {
         _packet = new DatagramPacket(_data, MAX_PACKET_SIZE);
         _initializeTime = _context.clock().now();
         _markedType = -1;
+        _remoteHost = null;
     }
     
     public void initialize(int priority, long expiration, InetAddress host, int port) {
@@ -88,6 +90,7 @@ public class UDPPacket {
         //_packet.setLength(0);
         _packet.setAddress(host);
         _packet.setPort(port);
+        _remoteHost = null;
         _released = false;
         _releasedBy = null;
     }
@@ -113,6 +116,12 @@ public class UDPPacket {
      */
     public int getMarkedType() { verifyNotReleased(); return _markedType; }
     
+    public RemoteHostId getRemoteHost() {
+        if (_remoteHost == null)
+            _remoteHost = new RemoteHostId(_packet.getAddress().getAddress(), _packet.getPort());
+        return _remoteHost;
+    }
+    
     /**
      * Validate the packet against the MAC specified, returning true if the
      * MAC matches, false otherwise.
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
index 63c8200139e2d6f4d7ad8f85de0349d8654b6ca3..4d00eb6fd3f82e091882d143811e67c11578dbb4 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -75,7 +75,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     /** shared slow bid for unconnected peers when we want to prefer UDP */
     private TransportBid _slowPreferredBid;
 
-    public static final String STYLE = "SSUv1";
+    public static final String STYLE = "SSU";
     public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort";
 
     /** define this to explicitly set an external IP address */
@@ -85,11 +85,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     /** 
      * If i2np.udp.alwaysPreferred is set, the UDP bids will always be under 
      * the bid from the TCP transport - even if a TCP connection already 
-     * exists.  The default is to prefer UDP unless no UDP session exists and 
-     * a TCP connection already exists.
+     * exists.  If this is true (the default), it will always prefer UDP, otherwise
+     * it will prefer UDP unless no UDP session exists and a TCP connection 
+     * already exists.
      */
     public static final String PROP_ALWAYS_PREFER_UDP = "i2np.udp.alwaysPreferred";
-    
+    private static final String DEFAULT_ALWAYS_PREFER_UDP = "true";
     
     /** how many relays offered to us will we use at a time? */
     public static final int PUBLIC_RELAY_COUNT = 3;
@@ -154,29 +155,35 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         
         rebuildExternalAddress();
         
-        if (_endpoint == null) {
-            int port = -1;
-            if (_externalListenPort <= 0) {
-                // no explicit external port, so lets try an internal one
-                String portStr = _context.getProperty(PROP_INTERNAL_PORT);
-                if (portStr != null) {
-                    try {
-                        port = Integer.parseInt(portStr);
-                    } catch (NumberFormatException nfe) {
-                        if (_log.shouldLog(Log.ERROR))
-                            _log.error("Invalid port specified [" + portStr + "]");
-                    }
-                }
-                if (port <= 0) {
-                    port = 1024 + _context.random().nextInt(31*1024);
-                    if (_log.shouldLog(Log.INFO))
-                        _log.info("Selecting a random port to bind to: " + port);
+        int port = -1;
+        if (_externalListenPort <= 0) {
+            // no explicit external port, so lets try an internal one
+            String portStr = _context.getProperty(PROP_INTERNAL_PORT);
+            if (portStr != null) {
+                try {
+                    port = Integer.parseInt(portStr);
+                } catch (NumberFormatException nfe) {
+                    if (_log.shouldLog(Log.ERROR))
+                        _log.error("Invalid port specified [" + portStr + "]");
                 }
-            } else {
-                port = _externalListenPort;
+            }
+            if (port <= 0) {
+                port = 8887;
+                //port = 1024 + _context.random().nextInt(31*1024);
                 if (_log.shouldLog(Log.INFO))
-                    _log.info("Binding to the explicitly specified external port: " + port);
+                    _log.info("Selecting an arbitrary port to bind to: " + port);
+                _context.router().setConfigSetting(PROP_INTERNAL_PORT, port+"");
+                // attempt to use it as our external port - this will be overridden by
+                // externalAddressReceived(...)
+                _context.router().setConfigSetting(PROP_EXTERNAL_PORT, port+"");
+                _context.router().saveConfig();
             }
+        } else {
+            port = _externalListenPort;
+            if (_log.shouldLog(Log.INFO))
+                _log.info("Binding to the explicitly specified external port: " + port);
+        }
+        if (_endpoint == null) {
             try {
                 _endpoint = new UDPEndpoint(_context, port);
             } catch (SocketException se) {
@@ -184,6 +191,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                     _log.log(Log.CRIT, "Unable to listen on the UDP port (" + port + ")", se);
                 return;
             }
+        } else {
+            _endpoint.setListenPort(port);
         }
         
         if (_establisher == null)
@@ -211,14 +220,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     }
     
     public void shutdown() {
+        if (_endpoint != null)
+            _endpoint.shutdown();
         if (_flooder != null)
             _flooder.shutdown();
         if (_refiller != null)
             _refiller.shutdown();
         if (_handler != null)
             _handler.shutdown();
-        if (_endpoint != null)
-            _endpoint.shutdown();
         if (_fragments != null)
             _fragments.shutdown();
         if (_pusher != null)
@@ -268,6 +277,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             }
         }
         
+        _context.router().setConfigSetting(PROP_EXTERNAL_PORT, ourPort+"");
+        _context.router().saveConfig();
+        
         if (updated) 
             _context.router().rebuildRouterInfo();
     }
@@ -280,8 +292,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
      * get the state for the peer at the given remote host/port, or null 
      * if no state exists
      */
-    public PeerState getPeerState(InetAddress remoteHost, int remotePort) {
-        RemoteHostId hostInfo = new RemoteHostId(remoteHost.getAddress(), remotePort);
+    public PeerState getPeerState(RemoteHostId hostInfo) {
         synchronized (_peersByRemoteHost) {
             return (PeerState)_peersByRemoteHost.get(hostInfo);
         }
@@ -424,7 +435,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     }
 
     private boolean alwaysPreferUDP() {
-        String pref = _context.getProperty(PROP_ALWAYS_PREFER_UDP);
+        String pref = _context.getProperty(PROP_ALWAYS_PREFER_UDP, DEFAULT_ALWAYS_PREFER_UDP);
         return (pref != null) && "true".equals(pref);
     }
     
diff --git a/router/java/src/net/i2p/router/tunnel/HopProcessor.java b/router/java/src/net/i2p/router/tunnel/HopProcessor.java
index 5947fcc644251d38ad1872a9da357cb02daa27bd..6a3201e0ce57ef15a7d34829cf80697dcf921dcf 100644
--- a/router/java/src/net/i2p/router/tunnel/HopProcessor.java
+++ b/router/java/src/net/i2p/router/tunnel/HopProcessor.java
@@ -29,7 +29,7 @@ public class HopProcessor {
      * and after using it at each hop so as to prevent a certain type of replay/confirmation 
      * attack.
      */
-    static final boolean USE_DOUBLE_IV_ENCRYPTION = false;
+    static final boolean USE_DOUBLE_IV_ENCRYPTION = true;
     static final int IV_LENGTH = 16;
     private static final ByteCache _cache = ByteCache.getInstance(128, IV_LENGTH);