Author: nextgens
Date: 2006-12-13 19:38:15 +0000 (Wed, 13 Dec 2006)
New Revision: 11378

Added:
   trunk/freenet/test/
   trunk/freenet/test/DatastoreTest.java
   trunk/freenet/test/PaddingSpeedTest.java
   trunk/freenet/test/PingTest.java
   trunk/freenet/test/PreNodeTest.java
   trunk/freenet/test/PreQuasiNodeTest.java
   trunk/freenet/test/QuasiNodeTest.java
   trunk/freenet/test/TransferBlockTest.java
   trunk/freenet/test/TransferSendTest.java
   trunk/freenet/test/freenet/
   trunk/freenet/test/freenet/io/
   trunk/freenet/test/freenet/io/AddressIdentifierTest.java
   trunk/freenet/test/freenet/io/Inet4AddressMatcherTest.java
   trunk/freenet/test/freenet/io/Inet6AddressMatcherTest.java
Removed:
   trunk/freenet/src/test/
   trunk/freenet/test/AddressIdentifierTest.java
   trunk/freenet/test/DatastoreTest.java
   trunk/freenet/test/Inet4AddressMatcherTest.java
   trunk/freenet/test/Inet6AddressMatcherTest.java
   trunk/freenet/test/PaddingSpeedTest.java
   trunk/freenet/test/PingTest.java
   trunk/freenet/test/PreNodeTest.java
   trunk/freenet/test/PreQuasiNodeTest.java
   trunk/freenet/test/QuasiNodeTest.java
   trunk/freenet/test/TransferBlockTest.java
   trunk/freenet/test/TransferSendTest.java
Modified:
   trunk/freenet/build.xml
Log:
Set up basic unit testing on a few classes : most of the tests have been 
written by Bombe

Modified: trunk/freenet/build.xml
===================================================================
--- trunk/freenet/build.xml     2006-12-13 19:33:17 UTC (rev 11377)
+++ trunk/freenet/build.xml     2006-12-13 19:38:15 UTC (rev 11378)
@@ -9,7 +9,10 @@

        <!-- set global properties for this build -->
        <property name="src" location="src"/>
+       <property name="test" location="test"/>
        <property name="build" location="build"/>
+       <property name="build-test" location="build-test"/>
+       <property name="test-results" location="test-results"/>
        <property name="lib"    location="lib"/>
        <property name="freenet-ext.location" 
location="${lib}/freenet-ext.jar"/>
        <property name="javadoc" location="javadoc"/>
@@ -20,6 +23,8 @@

        <target name="mkdir">
                <mkdir dir="${build}"/>
+               <mkdir dir="${build-test}"/>
+               <mkdir dir="${test-results}"/>
                <mkdir dir="${lib}"/>
        </target>

@@ -48,6 +53,7 @@
        </target>

        <!-- ================================================== -->
+
        <target name="compile" depends="get-extjar, 
generate-CSSTokenizerFilter">
                <!-- Create the time stamp -->
                <tstamp/>
@@ -83,7 +89,8 @@


        <!-- ================================================== -->
-       <target name="dist" depends="compile"
+
+       <target name="dist" depends="compile,unit"
                description="generate the distribution" >
                <!-- Create the distribution directory -->
                <!--<mkdir dir="."/>-->
@@ -105,12 +112,44 @@
        </target>

        <!-- ================================================== -->
+
+       <target name="unit-build" depends="compile">
+               <javac srcdir="${test}" destdir="${build-test}" debug="off" 
optimize="on" source="1.4">
+                       <classpath>
+                               <pathelement path="${build}"/>
+                               <pathelement 
location="${freenet-ext.location}"/>
+                       </classpath>
+                       <include name="**/*.java"/>
+                       <exclude name="*.java"/>
+               </javac>
+       </target>
+
+       <target name="unit" depends="unit-build">
+               <junit printsummary="yes" fork="yes" haltonfailure="yes">
+                       <classpath>
+                               <pathelement path="${build}"/>
+                               <pathelement path="${build-test}"/>
+                       </classpath>
+
+                       <formatter type="plain"/>
+
+                       <batchtest fork="yes" todir="${test-results}">
+                               <fileset dir="${build-test}">
+                                       <include name="**/*.java"/>
+                               </fileset>
+                       </batchtest>
+               </junit>
+       </target>
+
+       <!-- ================================================== -->
+
        <target name="clean" description="Delete class files and docs dir.">
                <delete dir="${build}"/>
        </target>
        <target name="distclean" description="Delete class files, lib dir and 
docs dir.">
                <delete file="${CSSTokenizerFilter.java}"/>
                <delete dir="${build}"/>
+               <delete dir="${build-test}"/>
                <delete dir="${lib}"/>
                <delete dir="${javadoc}"/>
        </target>

Copied: trunk/freenet/test (from rev 11374, trunk/freenet/src/test)

Deleted: trunk/freenet/test/AddressIdentifierTest.java
===================================================================
--- trunk/freenet/src/test/AddressIdentifierTest.java   2006-12-13 18:27:21 UTC 
(rev 11374)
+++ trunk/freenet/test/AddressIdentifierTest.java       2006-12-13 19:38:15 UTC 
(rev 11378)
@@ -1,54 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package test;
-
-import junit.framework.TestCase;
-import freenet.io.AddressIdentifier;
-import freenet.io.AddressIdentifier.AddressType;
-
-/**
- * Test case for the {@link freenet.io.AddressIdentifier} class.
- * 
- * @author David Roden &lt;droden at gmail.com&gt;
- * @version $Id$
- */
-public class AddressIdentifierTest extends TestCase {
-
-       public void test() {
-               /* test real IPv4 addresses */
-               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("0.0.0.0"));
-               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("127.0.0.1"));
-               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("255.255.255.255"));
-               /* in case you didn't know: 183.24.17 = 183.24.0.17 */
-               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("183.24.17"));
-               /* and 127.1 = 127.0.0.1 */
-               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("127.1"));
-
-               /* test fake IPv4 addresses */
-               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("192.168.370.12"));
-               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("127.0.0.0.1"));
-
-               /* test real unabridged IPv6 addresses */
-               assertEquals(AddressType.IPv6, 
AddressIdentifier.getAddressType("0:0:0:0:0:0:0:1"));
-               assertEquals(AddressType.IPv6, 
AddressIdentifier.getAddressType("fe80:0:0:0:203:dff:fe22:420f"));
-
-               /* test fake IPv6 addresses */
-               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("1:2:3:4:5:6:7:8:9"));
-               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("12345:6:7:8:9"));
-       }
-
-}

Deleted: trunk/freenet/test/DatastoreTest.java
===================================================================
--- trunk/freenet/src/test/DatastoreTest.java   2006-12-13 18:27:21 UTC (rev 
11374)
+++ trunk/freenet/test/DatastoreTest.java       2006-12-13 19:38:15 UTC (rev 
11378)
@@ -1,121 +0,0 @@
-package test;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-import freenet.keys.CHKDecodeException;
-import freenet.keys.CHKEncodeException;
-import freenet.keys.CHKVerifyException;
-import freenet.keys.ClientCHK;
-import freenet.keys.CHKBlock;
-import freenet.keys.ClientCHKBlock;
-import freenet.keys.FreenetURI;
-import freenet.store.FreenetStore;
-import freenet.support.Logger;
-
-/**
- * Create, or load, a datastore.
- * Command line interface, to do either:
- * a) Enter data, is encoded, store in datastore, return key.
- * b) Retrieve data by key.
- */
-public class DatastoreTest {
-
-    public static void main(String[] args) throws Exception {
-        // Setup datastore
-        FreenetStore fs = new FreenetStore("datastore", "headerstore", 1024);
-        // Setup logging
-        Logger.setupStdoutLogging(Logger.DEBUG, "");
-        printHeader();
-        // Read command, and data
-        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
-        while(true) {
-            String line = reader.readLine();
-            if(line.toUpperCase().startsWith("GET:")) {
-                // Should have a key next
-                String key = line.substring("GET:".length());
-                while(key.length() > 0 && key.charAt(0) == ' ')
-                    key = key.substring(1);
-                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
-                    key = key.substring(0, key.length()-2);
-                Logger.normal(DatastoreTest.class, "Key: "+key);
-                FreenetURI uri = new FreenetURI(key);
-                ClientCHK chk = new ClientCHK(uri);
-                CHKBlock block;
-                try {
-                    block = fs.fetch(chk.getNodeCHK());
-                } catch (CHKVerifyException e1) {
-                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
-                    continue;
-                }
-                if(block == null) {
-                    System.out.println("Not found in store: "+chk.getURI());
-                } else {
-                    // Decode it
-                    byte[] decoded;
-                    try {
-                        decoded = block.decode(chk);
-                    } catch (CHKDecodeException e) {
-                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
-                        continue;
-                    }
-                    System.out.println("Decoded data:\n");
-                    System.out.println(new String(decoded));
-                }
-            } else if(line.toUpperCase().startsWith("QUIT")) {
-                System.out.println("Goodbye.");
-                System.exit(0);
-            } else if(line.toUpperCase().startsWith("PUT:")) {
-                line = line.substring("PUT:".length());
-                while(line.length() > 0 && line.charAt(0) == ' ')
-                    line = line.substring(1);
-                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
-                    line = line.substring(0, line.length()-2);
-                String content;
-                if(line.length() > 0) {
-                    // Single line insert
-                    content = line;
-                } else {
-                    // Multiple line insert
-                    StringBuffer sb = new StringBuffer(1000);
-                    while(true) {
-                        line = reader.readLine();
-                        if(line.equals(".")) break;
-                        sb.append(line).append('\n');
-                    }
-                    content = sb.toString();
-                }
-                // Insert
-                byte[] data = content.getBytes();
-                ClientCHKBlock block;
-                try {
-                    block = ClientCHKBlock.encode(data);
-                } catch (CHKEncodeException e) {
-                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
-                    continue;
-                }
-                ClientCHK chk = block.getClientKey();
-                FreenetURI uri = 
-                    chk.getURI();
-                fs.put(block);
-                // Definitely interface
-                System.out.println("URI: "+uri);
-            } else {
-                
-            }
-        }
-    }
-
-    private static void printHeader() {
-        // Write header
-        System.out.println("Datastore tester");
-        System.out.println("----------------");
-        System.out.println();
-        System.out.println("Enter one of the following commands:");
-        System.out.println("FETCH:<Freenet key> - fetch a key from the store");
-        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
-        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
-        System.out.println("QUIT - exit the program");
-    }
-}

Copied: trunk/freenet/test/DatastoreTest.java (from rev 11377, 
trunk/freenet/src/test/DatastoreTest.java)
===================================================================
--- trunk/freenet/test/DatastoreTest.java                               (rev 0)
+++ trunk/freenet/test/DatastoreTest.java       2006-12-13 19:38:15 UTC (rev 
11378)
@@ -0,0 +1,121 @@
+package test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import freenet.keys.CHKDecodeException;
+import freenet.keys.CHKEncodeException;
+import freenet.keys.CHKVerifyException;
+import freenet.keys.ClientCHK;
+import freenet.keys.CHKBlock;
+import freenet.keys.ClientCHKBlock;
+import freenet.keys.FreenetURI;
+import freenet.store.FreenetStore;
+import freenet.support.Logger;
+
+/**
+ * Create, or load, a datastore.
+ * Command line interface, to do either:
+ * a) Enter data, is encoded, store in datastore, return key.
+ * b) Retrieve data by key.
+ */
+public class DatastoreTest {
+
+    public static void main(String[] args) throws Exception {
+        // Setup datastore
+        FreenetStore fs = new FreenetStore("datastore", "headerstore", 1024);
+        // Setup logging
+        Logger.setupStdoutLogging(Logger.DEBUG, "");
+        printHeader();
+        // Read command, and data
+        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
+        while(true) {
+            String line = reader.readLine();
+            if(line.toUpperCase().startsWith("GET:")) {
+                // Should have a key next
+                String key = line.substring("GET:".length());
+                while(key.length() > 0 && key.charAt(0) == ' ')
+                    key = key.substring(1);
+                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
+                    key = key.substring(0, key.length()-2);
+                Logger.normal(DatastoreTest.class, "Key: "+key);
+                FreenetURI uri = new FreenetURI(key);
+                ClientCHK chk = new ClientCHK(uri);
+                CHKBlock block;
+                try {
+                    block = fs.fetch(chk.getNodeCHK());
+                } catch (CHKVerifyException e1) {
+                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
+                    continue;
+                }
+                if(block == null) {
+                    System.out.println("Not found in store: "+chk.getURI());
+                } else {
+                    // Decode it
+                    byte[] decoded;
+                    try {
+                        decoded = block.decode(chk);
+                    } catch (CHKDecodeException e) {
+                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
+                        continue;
+                    }
+                    System.out.println("Decoded data:\n");
+                    System.out.println(new String(decoded));
+                }
+            } else if(line.toUpperCase().startsWith("QUIT")) {
+                System.out.println("Goodbye.");
+                System.exit(0);
+            } else if(line.toUpperCase().startsWith("PUT:")) {
+                line = line.substring("PUT:".length());
+                while(line.length() > 0 && line.charAt(0) == ' ')
+                    line = line.substring(1);
+                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
+                    line = line.substring(0, line.length()-2);
+                String content;
+                if(line.length() > 0) {
+                    // Single line insert
+                    content = line;
+                } else {
+                    // Multiple line insert
+                    StringBuffer sb = new StringBuffer(1000);
+                    while(true) {
+                        line = reader.readLine();
+                        if(line.equals(".")) break;
+                        sb.append(line).append('\n');
+                    }
+                    content = sb.toString();
+                }
+                // Insert
+                byte[] data = content.getBytes();
+                ClientCHKBlock block;
+                try {
+                    block = ClientCHKBlock.encode(data);
+                } catch (CHKEncodeException e) {
+                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
+                    continue;
+                }
+                ClientCHK chk = block.getClientKey();
+                FreenetURI uri = 
+                    chk.getURI();
+                fs.put(block);
+                // Definitely interface
+                System.out.println("URI: "+uri);
+            } else {
+                
+            }
+        }
+    }
+
+    private static void printHeader() {
+        // Write header
+        System.out.println("Datastore tester");
+        System.out.println("----------------");
+        System.out.println();
+        System.out.println("Enter one of the following commands:");
+        System.out.println("FETCH:<Freenet key> - fetch a key from the store");
+        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
+        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
+        System.out.println("QUIT - exit the program");
+    }
+}

Deleted: trunk/freenet/test/Inet4AddressMatcherTest.java
===================================================================
--- trunk/freenet/src/test/Inet4AddressMatcherTest.java 2006-12-13 18:27:21 UTC 
(rev 11374)
+++ trunk/freenet/test/Inet4AddressMatcherTest.java     2006-12-13 19:38:15 UTC 
(rev 11378)
@@ -1,74 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package freenet.io;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-
-import freenet.io.Inet4AddressMatcher;
-
-import junit.framework.TestCase;
-
-/**
- * @author David Roden &lt;droden at gmail.com&gt;
- * @version $Id$
- */
-public class Inet4AddressMatcherTest extends TestCase {
-
-       public void test() throws Exception {
-               Inet4AddressMatcher matcher = new 
Inet4AddressMatcher("192.168.1.2");
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.2")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("0.0.0.0")));
-               
-               matcher = new Inet4AddressMatcher("192.168.1.2/8");
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.2")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.81.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.255.255.255")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("172.16.1.1")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("0.0.0.0")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.0.0.0")));
-
-               /* some fancy matching */
-               matcher = new Inet4AddressMatcher("192.168.1.1/255.0.255.0");
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.1.1")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.2.1")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
-               
-               matcher = new Inet4AddressMatcher("127.0.0.1/8");
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.23.42.64")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.0")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.255.255.255")));
-               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("28.0.0.1")));
-
-               matcher = new Inet4AddressMatcher("0.0.0.0/0");
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("172.16.42.23")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("10.0.0.1")));
-               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("224.0.0.1")));
-       }
-
-}

Deleted: trunk/freenet/test/Inet6AddressMatcherTest.java
===================================================================
--- trunk/freenet/src/test/Inet6AddressMatcherTest.java 2006-12-13 18:27:21 UTC 
(rev 11374)
+++ trunk/freenet/test/Inet6AddressMatcherTest.java     2006-12-13 19:38:15 UTC 
(rev 11378)
@@ -1,65 +0,0 @@
-/*
- * freenet0.7 - 
- * Copyright (C) 2006 David Roden
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package test;
-
-import java.net.InetAddress;
-
-import junit.framework.TestCase;
-import freenet.io.Inet6AddressMatcher;
-
-/**
- * Test case for the {@link freenet.io.Inet6AddressMatcher} class. Contains 
some
- * very basic tests. Feel free to add more complicated tests!
- * 
- * @author David Roden &lt;droden at gmail.com&gt;
- * @version $Id$
- */
-public class Inet6AddressMatcherTest extends TestCase {
-
-       public void test() throws Exception {
-               Inet6AddressMatcher matcher = new 
Inet6AddressMatcher("0:0:0:0:0:0:0:0/0");
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
-
-               matcher = new 
Inet6AddressMatcher("fe80:0:0:0:203:dff:fe22:420f/64");
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0203:0dff:fe22:420f")));
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0204:0dff:fe22:420f")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe81:0:0:0:0203:0dff:fe22:420f")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("0:0:0:0:0:0:0:1")));
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0:0:0:1")));
-
-               matcher = new 
Inet6AddressMatcher("fe80:0:0:0:203:dff:fe22:420f/ffff:ffff:ffff:ffff:0:0:0:0");
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0203:0dff:fe22:420f")));
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0204:0dff:fe22:420f")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe81:0:0:0:0203:0dff:fe22:420f")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("0:0:0:0:0:0:0:1")));
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0:0:0:1")));
-
-               matcher = new 
Inet6AddressMatcher("fe80:0:0:0:203:dff:fe22:420f/128");
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
-               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0203:0dff:fe22:420f")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0204:0dff:fe22:420f")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe81:0:0:0:0203:0dff:fe22:420f")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("0:0:0:0:0:0:0:1")));
-               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0:0:0:1")));
-       }
-
-}

Deleted: trunk/freenet/test/PaddingSpeedTest.java
===================================================================
--- trunk/freenet/src/test/PaddingSpeedTest.java        2006-12-13 18:27:21 UTC 
(rev 11374)
+++ trunk/freenet/test/PaddingSpeedTest.java    2006-12-13 19:38:15 UTC (rev 
11378)
@@ -1,94 +0,0 @@
-package test;
-
-import java.security.DigestException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Random;
-
-import org.spaceroots.mantissa.random.MersenneTwister;
-
-import freenet.support.SizeUtil;
-
-/**
- * Test the speed of RNGs and hashes.
- */
-public class PaddingSpeedTest {
-
-    public static void main(String[] args) throws NoSuchAlgorithmException, 
DigestException {
-        MessageDigest md160 = MessageDigest.getInstance("SHA-1");
-        MessageDigest md256 = MessageDigest.getInstance("SHA-256");
-        MessageDigest md384 = MessageDigest.getInstance("SHA-384");
-        MessageDigest md512 = MessageDigest.getInstance("SHA-512");
-        MessageDigest[] mds = new MessageDigest[] { md160, md256, md384, md512 
};
-        int[] sizes = new int[] { 160, 256, 384, 512 };
-        for(int i=0;i<4;i++) {
-            long timeStart = System.currentTimeMillis();
-            int bits = sizes[i];
-            MessageDigest md = mds[i];
-            System.out.println("Algorithm "+i+": "+bits+" bits");
-            int bytes = bits/8;
-            byte[] buf = new byte[bytes];
-            for(int x=0;x<buf.length;x++) buf[x] = 0;
-            for(int j=0;j<512;j++) {
-                for(int k=0;k<1024;k++) {
-                    md.update(buf);
-                    md.digest(buf, 0, buf.length);
-                }
-            }
-            long timeEnd = System.currentTimeMillis();
-            long interval = timeEnd - timeStart;
-            System.out.println("Total time: "+interval);
-            int bytesTotal = 512 * 1024 * bytes;
-            printStats("SHA-"+bits, bytesTotal, interval);
-        }
-        // And a plain RNG
-        Random r = new Random();
-        long l = 0;
-        long timeStart = System.currentTimeMillis();
-        for(int q=0;q<50;q++) {
-        for(int i=0;i<1024;i++) {
-            for(int j=0;j<1024;j++) {
-                l = l ^ r.nextLong();
-            }
-        }
-        }
-        long timeEnd = System.currentTimeMillis();
-        long interval = timeEnd - timeStart;
-        int bytesTotal = 50 * 1024 * 1024 * 8;
-        printStats("java.util.Random", bytesTotal, interval);
-        // Now a more interesting RNG
-        byte[] buf = new byte[32]; // init from SHA-256
-        r.nextBytes(buf);
-        int[] seed = new int[8];
-        for(int i=0;i<8;i++) {
-            int x = buf[i*4] & 0xff;
-            x = x << 8 + (buf[i*4+1] & 0xff);
-            x = x << 8 + (buf[i*4+2] & 0xff);
-            x = x << 8 + (buf[i*4+3] & 0xff);
-            seed[i] = x;
-        }
-        MersenneTwister mt;
-        mt = new MersenneTwister(seed);
-        timeStart = System.currentTimeMillis();
-        for(int q=0;q<50;q++) {
-        for(int i=0;i<1024;i++) {
-            for(int j=0;j<1024;j++) {
-                l = l ^ mt.nextLong();
-            }
-        }
-        }
-        timeEnd = System.currentTimeMillis();
-        interval = timeEnd - timeStart;
-        bytesTotal = 50 * 1024 * 1024 * 8;
-        printStats("Mersenne Twister", bytesTotal, interval);
-    }
-
-    /**
-     * @param bytesTotal
-     * @param interval
-     */
-    private static void printStats(String name, int bytesTotal, long interval) 
{
-        double rate = bytesTotal / ((double)interval/1000);
-        System.out.println(name+": "+bytesTotal+" in "+interval+"ms = 
"+SizeUtil.formatSize((long)rate,false)+"/s");
-    }
-}

Copied: trunk/freenet/test/PaddingSpeedTest.java (from rev 11377, 
trunk/freenet/src/test/PaddingSpeedTest.java)
===================================================================
--- trunk/freenet/test/PaddingSpeedTest.java                            (rev 0)
+++ trunk/freenet/test/PaddingSpeedTest.java    2006-12-13 19:38:15 UTC (rev 
11378)
@@ -0,0 +1,94 @@
+package test;
+
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+
+import org.spaceroots.mantissa.random.MersenneTwister;
+
+import freenet.support.SizeUtil;
+
+/**
+ * Test the speed of RNGs and hashes.
+ */
+public class PaddingSpeedTest {
+
+    public static void main(String[] args) throws NoSuchAlgorithmException, 
DigestException {
+        MessageDigest md160 = MessageDigest.getInstance("SHA-1");
+        MessageDigest md256 = MessageDigest.getInstance("SHA-256");
+        MessageDigest md384 = MessageDigest.getInstance("SHA-384");
+        MessageDigest md512 = MessageDigest.getInstance("SHA-512");
+        MessageDigest[] mds = new MessageDigest[] { md160, md256, md384, md512 
};
+        int[] sizes = new int[] { 160, 256, 384, 512 };
+        for(int i=0;i<4;i++) {
+            long timeStart = System.currentTimeMillis();
+            int bits = sizes[i];
+            MessageDigest md = mds[i];
+            System.out.println("Algorithm "+i+": "+bits+" bits");
+            int bytes = bits/8;
+            byte[] buf = new byte[bytes];
+            for(int x=0;x<buf.length;x++) buf[x] = 0;
+            for(int j=0;j<512;j++) {
+                for(int k=0;k<1024;k++) {
+                    md.update(buf);
+                    md.digest(buf, 0, buf.length);
+                }
+            }
+            long timeEnd = System.currentTimeMillis();
+            long interval = timeEnd - timeStart;
+            System.out.println("Total time: "+interval);
+            int bytesTotal = 512 * 1024 * bytes;
+            printStats("SHA-"+bits, bytesTotal, interval);
+        }
+        // And a plain RNG
+        Random r = new Random();
+        long l = 0;
+        long timeStart = System.currentTimeMillis();
+        for(int q=0;q<50;q++) {
+        for(int i=0;i<1024;i++) {
+            for(int j=0;j<1024;j++) {
+                l = l ^ r.nextLong();
+            }
+        }
+        }
+        long timeEnd = System.currentTimeMillis();
+        long interval = timeEnd - timeStart;
+        int bytesTotal = 50 * 1024 * 1024 * 8;
+        printStats("java.util.Random", bytesTotal, interval);
+        // Now a more interesting RNG
+        byte[] buf = new byte[32]; // init from SHA-256
+        r.nextBytes(buf);
+        int[] seed = new int[8];
+        for(int i=0;i<8;i++) {
+            int x = buf[i*4] & 0xff;
+            x = x << 8 + (buf[i*4+1] & 0xff);
+            x = x << 8 + (buf[i*4+2] & 0xff);
+            x = x << 8 + (buf[i*4+3] & 0xff);
+            seed[i] = x;
+        }
+        MersenneTwister mt;
+        mt = new MersenneTwister(seed);
+        timeStart = System.currentTimeMillis();
+        for(int q=0;q<50;q++) {
+        for(int i=0;i<1024;i++) {
+            for(int j=0;j<1024;j++) {
+                l = l ^ mt.nextLong();
+            }
+        }
+        }
+        timeEnd = System.currentTimeMillis();
+        interval = timeEnd - timeStart;
+        bytesTotal = 50 * 1024 * 1024 * 8;
+        printStats("Mersenne Twister", bytesTotal, interval);
+    }
+
+    /**
+     * @param bytesTotal
+     * @param interval
+     */
+    private static void printStats(String name, int bytesTotal, long interval) 
{
+        double rate = bytesTotal / ((double)interval/1000);
+        System.out.println(name+": "+bytesTotal+" in "+interval+"ms = 
"+SizeUtil.formatSize((long)rate,false)+"/s");
+    }
+}

Deleted: trunk/freenet/test/PingTest.java
===================================================================
--- trunk/freenet/src/test/PingTest.java        2006-12-13 18:27:21 UTC (rev 
11374)
+++ trunk/freenet/test/PingTest.java    2006-12-13 19:38:15 UTC (rev 11378)
@@ -1,75 +0,0 @@
-package test;
-
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-
-import freenet.io.comm.Dispatcher;
-import freenet.io.comm.DumpDispatcher;
-import freenet.io.comm.Message;
-import freenet.io.comm.Peer;
-import freenet.io.comm.UdpSocketManager;
-import freenet.io.comm.DMT;
-import freenet.io.comm.MessageFilter;
-
-/**
- * Ping test.
- * Just me getting used to the Dijjer-derived messaging system really.
- * Takes two parameters: ourPort and hisPort.
- * Sends a ping message every second.
- * Prints out whenever we receive a ping message.
- * @author amphibian
- */
-public class PingTest {
-
-
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class PingingDispatcher implements Dispatcher {
-        public boolean handleMessage(Message m) {
-            if(m.getSpec() == DMT.ping) {
-                usm.send(m.getSource(), DMT.createPong(m));
-                return true;
-            }
-            return false;
-        }
-    }
-    
-    static UdpSocketManager usm;
-    
-    public PingTest() {
-        // not much to initialize
-        super();
-    }
-
-    public static void main(String[] args) throws SocketException, 
UnknownHostException {
-        if(args.length < 2) {
-            System.err.println("Syntax: PingTest <myPort> <hisPort>");
-            System.exit(1);
-        }
-        int myPort = Integer.parseInt(args[0]);
-        int hisPort = Integer.parseInt(args[1]);
-        System.out.println("My port: "+myPort+", his port: "+hisPort);
-        // Set up a UdpSocketManager
-        usm = new UdpSocketManager(myPort);
-        usm.setDispatcher(new PingingDispatcher());
-        Peer otherSide;
-        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
-        while(true) {
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-            }
-            System.err.println("Sending ping");
-            usm.send(otherSide, DMT.createPing());
-            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
-            if(m != null) {
-                System.err.println("Got pong: "+m);
-            }
-        }
-    }
-}

Copied: trunk/freenet/test/PingTest.java (from rev 11377, 
trunk/freenet/src/test/PingTest.java)
===================================================================
--- trunk/freenet/test/PingTest.java                            (rev 0)
+++ trunk/freenet/test/PingTest.java    2006-12-13 19:38:15 UTC (rev 11378)
@@ -0,0 +1,75 @@
+package test;
+
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+import freenet.io.comm.Dispatcher;
+import freenet.io.comm.DumpDispatcher;
+import freenet.io.comm.Message;
+import freenet.io.comm.Peer;
+import freenet.io.comm.UdpSocketManager;
+import freenet.io.comm.DMT;
+import freenet.io.comm.MessageFilter;
+
+/**
+ * Ping test.
+ * Just me getting used to the Dijjer-derived messaging system really.
+ * Takes two parameters: ourPort and hisPort.
+ * Sends a ping message every second.
+ * Prints out whenever we receive a ping message.
+ * @author amphibian
+ */
+public class PingTest {
+
+
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class PingingDispatcher implements Dispatcher {
+        public boolean handleMessage(Message m) {
+            if(m.getSpec() == DMT.ping) {
+                usm.send(m.getSource(), DMT.createPong(m));
+                return true;
+            }
+            return false;
+        }
+    }
+    
+    static UdpSocketManager usm;
+    
+    public PingTest() {
+        // not much to initialize
+        super();
+    }
+
+    public static void main(String[] args) throws SocketException, 
UnknownHostException {
+        if(args.length < 2) {
+            System.err.println("Syntax: PingTest <myPort> <hisPort>");
+            System.exit(1);
+        }
+        int myPort = Integer.parseInt(args[0]);
+        int hisPort = Integer.parseInt(args[1]);
+        System.out.println("My port: "+myPort+", his port: "+hisPort);
+        // Set up a UdpSocketManager
+        usm = new UdpSocketManager(myPort);
+        usm.setDispatcher(new PingingDispatcher());
+        Peer otherSide;
+        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
+        while(true) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+            System.err.println("Sending ping");
+            usm.send(otherSide, DMT.createPing());
+            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
+            if(m != null) {
+                System.err.println("Got pong: "+m);
+            }
+        }
+    }
+}

Deleted: trunk/freenet/test/PreNodeTest.java
===================================================================
--- trunk/freenet/src/test/PreNodeTest.java     2006-12-13 18:27:21 UTC (rev 
11374)
+++ trunk/freenet/test/PreNodeTest.java 2006-12-13 19:38:15 UTC (rev 11378)
@@ -1,845 +0,0 @@
-package test;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Random;
-
-import freenet.io.comm.DMT;
-import freenet.io.comm.Dispatcher;
-import freenet.io.comm.Message;
-import freenet.io.comm.MessageFilter;
-import freenet.io.comm.Peer;
-import freenet.io.comm.RetrievalException;
-import freenet.io.comm.UdpSocketManager;
-import freenet.io.xfer.BlockReceiver;
-import freenet.io.xfer.BlockTransmitter;
-import freenet.io.xfer.PartiallyReceivedBlock;
-import freenet.keys.CHKBlock;
-import freenet.keys.CHKDecodeException;
-import freenet.keys.CHKEncodeException;
-import freenet.keys.CHKVerifyException;
-import freenet.keys.ClientCHK;
-import freenet.keys.ClientCHKBlock;
-import freenet.keys.FreenetURI;
-import freenet.keys.NodeCHK;
-import freenet.store.FreenetStore;
-import freenet.support.Buffer;
-import freenet.support.Logger;
-
-/**
- * Invoker provides list of nodes to connect to (port #s).
- * Do handshake with each.. 5 consecutive pings.
- * 
- * Then:
- * Take requests and inserts from stdin, like DatastoreTest.
- * Inserts:
- * - Just put to local store.
- * Requests:
- * - Choose a (random) peer to request from.
- *
- * Requests can now propagate. 
- */
-public class PreNodeTest {
-
-    /** SendJob: Send the DataReply, wait for the ack, send the
-      * data, then report back. */
-    public static class SendJob implements Runnable {
-
-        final PartiallyReceivedBlock prb;
-        final long id;
-        final Peer peer;
-        final byte[] header;
-        final boolean silent;
-        BlockTransmitter bt = null;
-        boolean cancelled = false;
-        
-        public SendJob(PartiallyReceivedBlock prb, Peer peer, long id, byte[] 
header, boolean silent) {
-            this.prb = prb;
-            this.id = id;
-            this.peer = peer;
-            this.header = header;
-            this.silent = silent;
-        }
-
-        public void run() {
-            // First send the DataReply
-            Message dataReply = DMT.createTestDataReply(id, header);
-            // Yet another arbitrary timeout :(
-            MessageFilter waitFor = 
MessageFilter.create().setSource(peer).setType(DMT.testDataReplyAck).setTimeout(1000);
-            Message ack = null;
-            for(int i=0;i<5;i++) {
-                Logger.minor(this, "Waiting for DataReplyAck");
-                usm.send(peer, dataReply);
-                // Now wait for the ack
-                ack = usm.waitFor(waitFor);
-                if(ack != null)
-                    break;
-            }
-            Message completionNotification = null;
-            if(silent) completionNotification = null;
-            if(ack == null) {
-                if(!silent)
-                    completionNotification =
-                        DMT.createTestSendCompleted(id, false, "No 
DataReplyAck");
-            } else {
-                // Got an acknowledgement
-                bt = new BlockTransmitter(usm, peer, id, prb);
-                bt.send();
-                if(!silent)
-                    completionNotification = 
-                        DMT.createTestSendCompleted(id, true, "");
-            }
-            if(!silent) usm.checkFilters(completionNotification);
-        }
-    }
-    
-    // ReceiveJob: Receive the entire file, then report back.
-    public static class ReceiveJob implements Runnable {
-
-        final PartiallyReceivedBlock prb;
-        final Peer peer;
-        final long id;
-        
-        public ReceiveJob(PartiallyReceivedBlock prb, Peer peer, long id) {
-            this.prb = prb;
-            this.peer = peer;
-            this.id = id;
-        }
-
-        public void run() {
-            BlockReceiver br = new BlockReceiver(usm, peer, id, prb);
-            Message m = null;
-            try {
-                br.receive();
-            } catch (RetrievalException e) {
-                Logger.normal(this, "Receive failed: "+e);
-                m = DMT.createTestReceiveCompleted(id, false, e.toString());
-            }
-            if(m == null)
-                m = DMT.createTestReceiveCompleted(id, true, "");
-            // Send notification
-            usm.checkFilters(m);
-        }
-
-    }
-    static Peer myPeer = null;
-
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class IDSet {
-
-        HashMap items = new HashMap();
-        
-        public synchronized void register(long id, Peer source) {
-            items.put(new Long(id), source);
-        }
-
-        public void unregister(long id) {
-            items.remove(new Long(id));
-        }
-
-        public Peer getSource(long id) {
-            return (Peer) items.get(new Long(id));
-        }
-    }
-    
-    static final IDSet idsRunning = new IDSet();
-    
-    static final HashSet previousIDs = new HashSet();
-    
-    /**
-     * @author amphibian
-     * 
-     * Keeps track of who we are connected to.
-     * Also provides functionality for routing.
-     * In a full implementation, we would keep estimators for
-     * each node. In this version, we merely choose a peer 
-     * randomly.
-     */
-    public static class RoutingTable {
-
-        PeerNode[] peerNodes = null;
-
-        HashSet connectedNodes = new HashSet();
-        PeerNode[] connectedNodesArray;
-
-        public int connectedNodes() {
-            return connectedNodes.size();
-        }
-
-        public PeerNode route(HashSet peerNodesExcluded) {
-            PeerNode[] nodes = getConnectedNodes();
-            int length = nodes.length;
-            if(peerNodesExcluded.size() > 0) {
-                PeerNode[] nodesNotExcluded = new PeerNode[length];
-                int j=0;
-                for(int i=0;i<length;i++) {
-                    PeerNode pn = nodes[i];
-                    if(peerNodesExcluded.contains(pn)) {
-                        Logger.minor(this, "Excluding: "+pn+" = "+pn.peer);
-                        continue;
-                    }
-                    nodesNotExcluded[j] = pn;
-                    j++;
-                }
-                nodes = nodesNotExcluded;
-                length = j;
-            }
-            Logger.debug(this, "Route choices length: "+length);
-            if(length == 0) return null;
-            else return nodes[r.nextInt(length)];
-        }
-        
-        public synchronized PeerNode[] getConnectedNodes() {
-            if(connectedNodesArray == null) {
-                connectedNodesArray = new PeerNode[connectedNodes.size()];
-                connectedNodes.toArray(connectedNodesArray);
-            }
-            return connectedNodesArray;
-        }
-
-        /**
-         * Try to connect to all nodes.
-         */
-        public synchronized void doInitialConnectAll() {
-            // Connect to all peers
-            if(peerNodes == null || peerNodes.length == 0) {
-                Logger.error(this, "No peer nodes");
-                return;
-            }
-            while(true) {
-                boolean failedConnect = false;
-                for(int i=0;i<peerNodes.length;i++) {
-                    PeerNode pn = peerNodes[i];
-                    Logger.debug(this, "["+i+"]: "+pn);
-                    if(!pn.isConnected()) {
-                        Logger.minor(this, "Trying to connect to "+pn);
-                        if(!pn.tryConnectOnce())
-                            failedConnect = true;
-                    }
-                }
-                if(!failedConnect) break;
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    // Ignore
-                }
-            }
-        }
-
-        public synchronized void addPeerNode(PeerNode p) {
-            Logger.debug(this,"Adding "+p);
-            if(peerNodes == null)
-                Logger.debug(this, "peerNodes = null");
-            else
-                Logger.debug(this, "peerNodes size = "+peerNodes.length);
-            int length;
-            if(p == null) throw new NullPointerException();
-            if(peerNodes == null) length = 0;
-            else length = peerNodes.length;
-            PeerNode[] newPeers = new PeerNode[length+1];
-            if(length > 0)
-                System.arraycopy(peerNodes, 0, newPeers, 0, peerNodes.length);
-            newPeers[newPeers.length-1] = p;
-            peerNodes = newPeers;
-            for(int i=0;i<peerNodes.length;i++)
-                Logger.debug(this, "peerNodes["+i+"] = "+peerNodes[i]);
-        }
-
-        public synchronized void onConnected(PeerNode p) {
-            connectedNodes.add(p);
-            connectedNodesArray = null;
-        }
-        
-        public synchronized void onDisconnected(PeerNode p) {
-            connectedNodesArray = null;
-            // FIXME
-        }
-
-        /**
-         * @return The total number of nodes known.
-         */
-        public int totalPeers() {
-            return peerNodes.length;
-        }
-
-        /**
-         * @param otherSide
-         * @return
-         */
-        public PeerNode getPeerNode(Peer otherSide) {
-            for(int i=0;i<peerNodes.length;i++) {
-                PeerNode pn = peerNodes[i];
-                if(pn.peer.equals(otherSide)) return pn;
-            }
-            return null;
-        }
-    }
-    
-    /**
-     * A peer node. Would contain estimators as well as contact
-     * details.
-     * @author amphibian
-     */
-    public static class PeerNode {
-        int portNumber;
-        Peer peer;
-        
-        PeerNode(int portNum) {
-            this.portNumber = portNum;
-            try {
-                peer = new Peer(InetAddress.getByName("127.0.0.1"), portNum);
-            } catch (UnknownHostException e) {
-                // WTF?
-                throw new Error(e);
-            }
-        }
-
-        public int hashCode() {
-            return portNumber;
-        }
-        
-        public String toString() {
-            return super.toString()+":port="+portNumber;
-        }
-
-        public boolean equals(Object o) {
-            // FIXME: do we need to actually compare content?
-            // Probably not... there should only be one PeerNode for each peer.
-            return (o == this);
-        }
-        
-        /**
-         * @return
-         */
-        public boolean isConnected() {
-            return connected;
-        }
-
-        int consecutivePings = 0;
-        boolean connected = false;
-        
-        /**
-         * Attempt to connect to this node.
-         * @return true if we have succeeded
-         */
-        public boolean tryConnectOnce() {
-            if(!connected) {
-                Logger.normal(TransferBlockTest.class, "Sending ping");
-                usm.send(peer, DMT.createPing());
-                Message m = usm.waitFor(MessageFilter.create().
-                        setTimeout(1000).setType(DMT.pong).setSource(peer));
-                if(m != null) {
-                    consecutivePings++;
-                    Logger.normal(TransferBlockTest.class, "Got pong: "+m);
-                } else {
-                    consecutivePings = 0;
-                    connected = false;
-                }
-            }
-            if(consecutivePings >= 3) {
-                connected = true;
-                rt.onConnected(this);
-                return true;
-            }
-            Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings to "+this);
-            return false;
-        }
-    }
-    
-    static FreenetStore fs;
-    static UdpSocketManager usm;
-    final static Random r = new Random();
-    static RoutingTable rt;
-    static int myPort;
-    
-    public static void main(String[] args) throws Exception {
-        Logger.setupStdoutLogging(Logger.DEBUG, "");
-        rt = new RoutingTable();
-        // Parse parameters.
-        parseParameters(args);
-        // Set up a UdpSocketManager
-        usm = new UdpSocketManager(myPort);
-        usm.setDispatcher(new MyDispatcher());
-        //usm.setDropProbability(10);
-        rt.doInitialConnectAll();
-        // Setup datastore
-        fs = new FreenetStore("datastore-"+myPort, "headerstore-"+myPort, 
1024);
-        printHeader();
-        interfaceLoop();
-    }
-
-    private static void interfaceLoop() throws IOException {
-        // Read command, and data
-        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
-        while(true) {
-            String line = reader.readLine();
-            if(line.startsWith("GET:")) {
-                // Should have a key next
-                String key = line.substring("GET:".length());
-                while(key.length() > 0 && key.charAt(0) == ' ')
-                    key = key.substring(1);
-                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
-                    key = key.substring(0, key.length()-2);
-                Logger.normal(DatastoreTest.class, "Key: "+key);
-                FreenetURI uri = new FreenetURI(key);
-                ClientCHK chk = new ClientCHK(uri);
-                CHKBlock block;
-                try {
-                    // Fetch, possibly from other node.
-                    block = runRequest(chk.getNodeCHK(), 3, r.nextLong(), 
null, null);
-                } catch (CHKVerifyException e1) {
-                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
-                    continue;
-                }
-                if(block == null) {
-                    System.out.println("Not found in store: "+chk.getURI());
-                } else {
-                    // Decode it
-                    byte[] decoded;
-                    try {
-                        decoded = block.decode(chk);
-                    } catch (CHKDecodeException e) {
-                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
-                        continue;
-                    }
-                    System.out.println("Decoded data:\n");
-                    System.out.println(new String(decoded));
-                }
-            } else if(line.startsWith("QUIT")) {
-                System.out.println("Goodbye.");
-                System.exit(0);
-            } else if(line.startsWith("PUT:")) {
-                // Just insert to local store
-                line = line.substring("PUT:".length());
-                while(line.length() > 0 && line.charAt(0) == ' ')
-                    line = line.substring(1);
-                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
-                    line = line.substring(0, line.length()-2);
-                String content;
-                if(line.length() > 0) {
-                    // Single line insert
-                    content = line;
-                } else {
-                    // Multiple line insert
-                    StringBuffer sb = new StringBuffer(1000);
-                    while(true) {
-                        line = reader.readLine();
-                        if(line.equals(".")) break;
-                        sb.append(line).append('\n');
-                    }
-                    content = sb.toString();
-                }
-                // Insert
-                byte[] data = content.getBytes();
-                ClientCHKBlock block;
-                try {
-                    block = ClientCHKBlock.encode(data);
-                } catch (CHKEncodeException e) {
-                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
-                    continue;
-                }
-                ClientCHK chk = block.getClientKey();
-                FreenetURI uri = 
-                    chk.getURI();
-                fs.put(block);
-                // Definitely interface
-                System.out.println("URI: "+uri);
-            } else {
-                
-            }
-        }
-    }
-
-    /**
-     * Parse parameters.
-     * The first one is my port number.
-     * The second, third, fourth... are the port numbers of
-     * nodes to add to the routing table.
-     */
-    private static void parseParameters(String[] args) throws 
UnknownHostException {
-        if(args.length < 2) {
-            System.err.println("Syntax: QuasiNodeTest <myPort> <node1's port> 
<node2's port> <node3's port>... ");
-            System.exit(1);
-        }
-        myPort = Integer.parseInt(args[0]);
-        myPeer = new Peer(InetAddress.getByName("127.0.0.1"), myPort);
-        for(int i=1;i<args.length;i++) {
-            int port = Integer.parseInt(args[i]);
-            Logger.minor(PreNodeTest.class, "Adding node on port "+port);
-            PeerNode p = new PeerNode(port);
-            rt.addPeerNode(p);
-        }
-        Logger.normal(PreNodeTest.class, "Added "+rt.totalPeers()+" peers");
-    }
-
-    /**
-     * Either fetch the key from the datastore, or request it from the other
-     * node.
-     * 
-     * @param nodeCHK
-     *            The key to fetch.
-     * @param htl
-     *            The hops to live.
-     * @return null if we can't find the data.
-     */
-    private static CHKBlock runRequest(NodeCHK nodeCHK, int htl, long id,
-            Peer source, PeerNode sourceNode) throws IOException,
-            CHKVerifyException {
-        Logger.debug(PreNodeTest.class, "runRequest for "+nodeCHK+"@ 
HTL="+htl+" for "+source+" : "+sourceNode);
-        previousIDs.add(new Long(id));
-        idsRunning.register(id, source == null ? myPeer : source);
-        // Send the ACK
-        if (source != null) usm.send(source, DMT.createAcknowledgeRequest(id));
-        try {
-            HashSet peersSentTo = new HashSet();
-            if (sourceNode != null) peersSentTo.add(sourceNode);
-            // No source - catch any requests to this ID, check source later
-            MessageFilter requestFilter = 
MessageFilter.create().setType(DMT.testRequest).setField(DMT.UID, id);
-            while (true) {
-                // First try the store
-                CHKBlock block = fs.fetch(nodeCHK);
-                if (block != null) {
-                    if(source != null) {
-                        // End node
-                        PartiallyReceivedBlock prb = new 
PartiallyReceivedBlock(32, 1024, block.getData());
-                        byte[] header = block.getHeader();
-                        SendJob sj = new SendJob(prb, source, id, header, 
true);
-                        Thread t = new Thread(sj);
-                        t.start();
-                    }
-                    return block;
-                }
-                if (htl <= 0) return block;
-                // Otherwise...
-                PeerNode pn = rt.route(peersSentTo);
-                if (pn == null) {
-                    Logger.minor(PreNodeTest.class, "Ran out of peers");
-                    // FIXME: should this be a separate message? 
LateQueryRejected, perhaps?
-                    if(source != null) {
-                        Message dnf = DMT.createTestDataNotFound(id);
-                        usm.send(source, dnf);
-                    }
-                    return null;
-                }
-                Logger.minor(PreNodeTest.class, "Routing to " + pn);
-                Peer peer = pn.peer;
-                MessageFilter justReply = MessageFilter.create().setType(
-                        DMT.testDataReply).setField(DMT.UID, id)
-                        .setSource(peer);
-                MessageFilter replyFilter = justReply.or(MessageFilter.create()
-                        .setField(DMT.UID, id).setType(DMT.testDataNotFound)
-                        .setSource(peer));
-                Message request = DMT.createTestRequest(nodeCHK, id, htl);
-                Message accepted = null;
-                MessageFilter ackFilter = MessageFilter.create().setType(
-                        DMT.acknowledgeRequest).setSource(peer).setField(
-                        DMT.UID, id);
-                MessageFilter qrFilter = MessageFilter.create().setType(
-                        DMT.rejectDueToLoop).setSource(peer).setField(DMT.UID,
-                        id);
-                peersSentTo.add(pn);
-                MessageFilter wait = 
qrFilter.or(ackFilter.or(replyFilter.or(requestFilter)));
-                wait.setTimeout(1000);
-                for (int i = 0; i < 5; i++) {
-                    usm.send(peer, request);
-                    // Wait for Accepted
-                    accepted = usm.waitFor(wait);
-                    if (accepted == null) continue;
-                    if (accepted.getSpec() == DMT.testRequest) {
-                        // Is a request
-                        if(accepted.getSource() == source) {
-                            // Is a rerequest.
-                            // Resend the Accepted.
-                            usm.send(source, DMT.createAcknowledgeRequest(id));
-                        } else {
-                            // Is a loop
-                            usm.send(accepted.getSource(), 
DMT.createRejectDueToLoop(id));
-                        }
-                        accepted = null;
-                        continue;
-                    }
-                    break;
-                    // Didn't get Accepted - probably didn't receive our 
request
-                }
-                Logger.debug(PreNodeTest.class, "Waiting for Accepted got 
"+accepted);
-                if (accepted == null) {
-                    Logger.normal(PreNodeTest.class, "Did not get Accepted");
-                    // Try another node
-                    continue;
-                }
-                if (accepted.getSpec() == DMT.rejectDueToLoop) {
-                    Logger.minor(PreNodeTest.class, "Rejected: Loop");
-                    // Try another node
-                    continue;
-                }
-                Message reply;
-                // If it's not Accepted, it's something else...
-                if (accepted.getSpec() != DMT.acknowledgeRequest)
-                    reply = accepted;
-                else {
-                    while (true) {
-                        Logger.debug(PreNodeTest.class, "Waiting for reply");
-                        reply = usm.waitFor(replyFilter.or(requestFilter)
-                                .setTimeout(5000));
-                        if (reply == null) break;
-                        if (reply.getSpec() == DMT.testRequest) {
-                            if(reply.getSource() == source) {
-                                // Rerequest from requestor; resend
-                                usm.send(source, 
DMT.createAcknowledgeRequest(id));
-                            } else {
-                                // Loop
-                                usm.send(reply.getSource(), 
DMT.createRejectDueToLoop(id));                                
-                            }
-                            continue;
-                        }
-                        break;
-                    }
-                }
-                Logger.debug(PreNodeTest.class, "Got reply: "+reply);
-                // Process reply
-                if (reply == null) {
-                    Logger.normal(PreNodeTest.class,
-                            "Partner node did not reply");
-                    // Same as if can't find enough nodes
-                    continue;
-                    //return null;
-                } else if (reply.getSpec() == DMT.testDataNotFound) {
-                    // DNF
-                    Logger.normal(PreNodeTest.class, "Data Not Found");
-                    Message m = DMT.createTestDataNotFoundAck(id);
-                    usm.send(peer, m);
-                    
-                    if(source != null) {
-                        Message dnf = DMT.createTestDataNotFound(id);
-                        usm.send(source, dnf);
-                    }
-                    // If this gets lost, they'll send it again a few times...
-                    return null;
-                } else if (reply.getSpec() == DMT.testDataReply) {
-                    Logger.debug(PreNodeTest.class, "Got DataReply");
-                    byte[] header = ((Buffer) reply
-                            .getObject(DMT.TEST_CHK_HEADERS)).getData();
-                    // Send the ack
-                    Message m = DMT.createTestDataReplyAck(id);
-                    usm.send(peer, m);
-                    // Now wait for the transfer; he will send me the data
-                    // Receive the data
-                    PartiallyReceivedBlock prb;
-                    prb = new PartiallyReceivedBlock(32, 1024);
-                    BlockReceiver br;
-
-                    // Receive
-                    // ReceiveJob: Receive the entire file, then report back.
-                    ReceiveJob rj = new ReceiveJob(prb, peer, id);
-                    Thread rjt = new Thread(rj);
-                    rjt.start();
-
-                    if(source != null) {
-                        // Send
-                        // SendJob: Send the DataReply, wait for the ack, send 
the
-                        // data, then report back.
-                        SendJob sj = new SendJob(prb, source, id, header, 
false);
-                        Thread sjt = new Thread(sj);
-                        sjt.start();
-                    }
-
-                    /**
-                     * We can now receive: - Resent DataRequest from request
-                     * source => resend - Resent DataReply from peer (data
-                     * source) - Completion notification from SendJob -
-                     * Completion notification from ReceiveJob SendJob handles
-                     * DataReplyAck
-                     */
-
-                    MessageFilter sentCompleteWait = MessageFilter.create()
-                            .setType(DMT.testSendCompleted).setField(DMT.UID,
-                                    id);
-                    MessageFilter receiveCompleteWait = MessageFilter.create()
-                            .setType(DMT.testReceiveCompleted).setField(
-                                    DMT.UID, id);
-
-                    // FIXME: totally arbitrary timeout :)
-                    MessageFilter waitingFor = 
-                        
justReply.or(sentCompleteWait.or(receiveCompleteWait.or(requestFilter)));
-                    waitingFor = waitingFor.setTimeout(30 * 1000);
-
-                    boolean sendCompleted = false;
-                    boolean recvCompleted = false;
-
-                    while (true) {
-                        m = null;
-                        m = usm.waitFor(waitingFor);
-
-                        if (m == null) {
-                            // Timeout
-                            Logger.error(PreNodeTest.class, "Timeout in final 
wait");
-                            if(!recvCompleted) {
-                                // Other side will see broken send
-                                return null;
-                            } else {
-                                // We got it, they didn't
-                                break;
-                            }
-                        } else if (m.getSpec() == DMT.testSendCompleted) {
-                            Logger.minor(PreNodeTest.class, "Send completed");
-                            // Finished send
-                            sendCompleted = true;
-                            if (recvCompleted) break;
-                        } else if (m.getSpec() == DMT.testReceiveCompleted) {
-                            Logger.minor(PreNodeTest.class, "Receive 
completed");
-                            if(!m.getBoolean(DMT.SUCCESS)) {
-                                prb.abort(RetrievalException.SENDER_DIED, 
"Sender died");
-                                return null;
-                            }
-                            recvCompleted = true;
-                            if (sendCompleted || source == null) break;
-                        } else if (m.getSpec() == DMT.testDataReply) {
-                            Logger.minor(PreNodeTest.class, "Got DataReply");
-                            // Data source didn't get the acknowledgement
-                            // Resend the acknowledgement
-                            Message ack = DMT.createTestDataReplyAck(id);
-                            usm.send(peer, ack);
-                        } else if (m.getSpec() == DMT.testRequest) {
-                            Logger.minor(PreNodeTest.class, "Got DataRequest");
-                            if(m.getSource() == source) {
-                                Logger.minor(PreNodeTest.class, "DataRequest 
from source");
-                                // Resend request
-                                // Source got neither the accepted nor the 
DataReply
-                                // Resend the accepted, and let SendJob resend 
the DataReply
-                                // Difficult to get it to resend it 
immediately because it might just have sent it so just let it time out.
-                                usm.send(source, 
DMT.createAcknowledgeRequest(id));
-                            } else {
-                                // Loop - shouldn't happen at this stage
-                                Logger.normal(PreNodeTest.class, "Loop after 
have started sending");
-                                usm.send(m.getSource(), 
DMT.createRejectDueToLoop(id));                                
-                            }
-                            
-                        }
-                    }
-
-                    // Got data
-
-                    byte[] data = prb.getBlock();
-
-                    if (data == null)
-                            Logger.error(PreQuasiNodeTest.class,
-                                    "Could not receive data");
-                    System.err.println("Received " + data.length + " bytes");
-                    // Now decode it
-                    try {
-                        block = new CHKBlock(data, header, nodeCHK);
-                    } catch (CHKVerifyException e) {
-                        Logger.error(PreNodeTest.class, "Couldn't verify", e);
-                        return null;
-                    }
-                    return block;
-                } else {
-                    Logger.error(PreNodeTest.class, "Message " + reply
-                            + " - WTF?");
-                    return null;
-                }
-            }
-        } finally {
-            idsRunning.unregister(id);
-        }
-    }
-
-    private static void printHeader() {
-        // Write header
-        System.out.println("PreNode tester");
-        System.out.println("--------------");
-        System.out.println();
-        System.out.println("Enter one of the following commands:");
-        System.out.println("GET:<Freenet key> - fetch a key");
-        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
-        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
-        System.out.println("QUIT - exit the program");
-    }
-
-    public static class MyDispatcher implements Dispatcher {
-        public boolean handleMessage(Message m) {
-            if(m.getSpec() == DMT.ping) {
-                usm.send(m.getSource(), DMT.createPong(m));
-                return true;
-            }
-            if(m.getSpec() == DMT.testRequest) {
-                Peer origSource = idsRunning.getSource(m.getLong(DMT.UID));
-                Peer reqSource = m.getSource();
-                if(reqSource == origSource)
-                    // Resent by request source; ignore
-                    return true;
-                // Otherwise a genuine request, or a loop; either way needs 
further handling
-                try {
-                    new Thread(new RequestHandler(m)).start();
-                } catch (IllegalStateException e) {
-                    return true;
-                }
-                return true;
-            }
-            return false;
-        }
-    }
-    
-    /**
-     * Handle a request.
-     * Check the store, if we have anything, then send it back.
-     * Otherwise send back DNF.
-     */
-    public static class RequestHandler implements Runnable {
-
-        final long id;
-        final NodeCHK key;
-        final Peer otherSide;
-        int htl;
-        
-        /**
-         * Constructor
-         * @param m
-         */
-        public RequestHandler(Message m) {
-            if(m.getSpec() != DMT.testRequest)
-                throw new IllegalArgumentException("Not a testRequest: 
"+m.getSpec().getName());
-            id = m.getLong(DMT.UID);
-            Object o = m.getObject(DMT.FREENET_ROUTING_KEY);
-            if(o instanceof NodeCHK)
-                key = (NodeCHK) o;
-            else {
-                // Ignore it
-                Logger.error(RequestHandler.class, "Node sent testRequest but 
key not a key! Ignoring request.");
-                throw new IllegalStateException("Node sent testRequest but key 
not a key! Ignoring request.");
-            }
-            otherSide = m.getSource();
-            htl = m.getInt(DMT.HTL);
-            htl--;
-        }
-
-        public void run() {
-            // Check ID
-            // FIXME: use an LRU
-            Long lid = new Long(id);
-            if(previousIDs.contains(lid)) {
-                // Reject
-                usm.send(otherSide, DMT.createRejectDueToLoop(id));
-                return;
-            }
-            try {
-                runRequest(key, htl, id, otherSide, rt.getPeerNode(otherSide));
-            } catch (IOException e) {
-                Logger.error(this, "IO error fetching: "+e,e);
-            } catch (CHKVerifyException e) {
-                Logger.error(this, "Couldn't verify data in store for "+key+": 
"+e,e);
-            }
-        }
-        
-    }
-}

Copied: trunk/freenet/test/PreNodeTest.java (from rev 11377, 
trunk/freenet/src/test/PreNodeTest.java)
===================================================================
--- trunk/freenet/test/PreNodeTest.java                         (rev 0)
+++ trunk/freenet/test/PreNodeTest.java 2006-12-13 19:38:15 UTC (rev 11378)
@@ -0,0 +1,845 @@
+package test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Random;
+
+import freenet.io.comm.DMT;
+import freenet.io.comm.Dispatcher;
+import freenet.io.comm.Message;
+import freenet.io.comm.MessageFilter;
+import freenet.io.comm.Peer;
+import freenet.io.comm.RetrievalException;
+import freenet.io.comm.UdpSocketManager;
+import freenet.io.xfer.BlockReceiver;
+import freenet.io.xfer.BlockTransmitter;
+import freenet.io.xfer.PartiallyReceivedBlock;
+import freenet.keys.CHKBlock;
+import freenet.keys.CHKDecodeException;
+import freenet.keys.CHKEncodeException;
+import freenet.keys.CHKVerifyException;
+import freenet.keys.ClientCHK;
+import freenet.keys.ClientCHKBlock;
+import freenet.keys.FreenetURI;
+import freenet.keys.NodeCHK;
+import freenet.store.FreenetStore;
+import freenet.support.Buffer;
+import freenet.support.Logger;
+
+/**
+ * Invoker provides list of nodes to connect to (port #s).
+ * Do handshake with each.. 5 consecutive pings.
+ * 
+ * Then:
+ * Take requests and inserts from stdin, like DatastoreTest.
+ * Inserts:
+ * - Just put to local store.
+ * Requests:
+ * - Choose a (random) peer to request from.
+ *
+ * Requests can now propagate. 
+ */
+public class PreNodeTest {
+
+    /** SendJob: Send the DataReply, wait for the ack, send the
+      * data, then report back. */
+    public static class SendJob implements Runnable {
+
+        final PartiallyReceivedBlock prb;
+        final long id;
+        final Peer peer;
+        final byte[] header;
+        final boolean silent;
+        BlockTransmitter bt = null;
+        boolean cancelled = false;
+        
+        public SendJob(PartiallyReceivedBlock prb, Peer peer, long id, byte[] 
header, boolean silent) {
+            this.prb = prb;
+            this.id = id;
+            this.peer = peer;
+            this.header = header;
+            this.silent = silent;
+        }
+
+        public void run() {
+            // First send the DataReply
+            Message dataReply = DMT.createTestDataReply(id, header);
+            // Yet another arbitrary timeout :(
+            MessageFilter waitFor = 
MessageFilter.create().setSource(peer).setType(DMT.testDataReplyAck).setTimeout(1000);
+            Message ack = null;
+            for(int i=0;i<5;i++) {
+                Logger.minor(this, "Waiting for DataReplyAck");
+                usm.send(peer, dataReply);
+                // Now wait for the ack
+                ack = usm.waitFor(waitFor);
+                if(ack != null)
+                    break;
+            }
+            Message completionNotification = null;
+            if(silent) completionNotification = null;
+            if(ack == null) {
+                if(!silent)
+                    completionNotification =
+                        DMT.createTestSendCompleted(id, false, "No 
DataReplyAck");
+            } else {
+                // Got an acknowledgement
+                bt = new BlockTransmitter(usm, peer, id, prb);
+                bt.send();
+                if(!silent)
+                    completionNotification = 
+                        DMT.createTestSendCompleted(id, true, "");
+            }
+            if(!silent) usm.checkFilters(completionNotification);
+        }
+    }
+    
+    // ReceiveJob: Receive the entire file, then report back.
+    public static class ReceiveJob implements Runnable {
+
+        final PartiallyReceivedBlock prb;
+        final Peer peer;
+        final long id;
+        
+        public ReceiveJob(PartiallyReceivedBlock prb, Peer peer, long id) {
+            this.prb = prb;
+            this.peer = peer;
+            this.id = id;
+        }
+
+        public void run() {
+            BlockReceiver br = new BlockReceiver(usm, peer, id, prb);
+            Message m = null;
+            try {
+                br.receive();
+            } catch (RetrievalException e) {
+                Logger.normal(this, "Receive failed: "+e);
+                m = DMT.createTestReceiveCompleted(id, false, e.toString());
+            }
+            if(m == null)
+                m = DMT.createTestReceiveCompleted(id, true, "");
+            // Send notification
+            usm.checkFilters(m);
+        }
+
+    }
+    static Peer myPeer = null;
+
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class IDSet {
+
+        HashMap items = new HashMap();
+        
+        public synchronized void register(long id, Peer source) {
+            items.put(new Long(id), source);
+        }
+
+        public void unregister(long id) {
+            items.remove(new Long(id));
+        }
+
+        public Peer getSource(long id) {
+            return (Peer) items.get(new Long(id));
+        }
+    }
+    
+    static final IDSet idsRunning = new IDSet();
+    
+    static final HashSet previousIDs = new HashSet();
+    
+    /**
+     * @author amphibian
+     * 
+     * Keeps track of who we are connected to.
+     * Also provides functionality for routing.
+     * In a full implementation, we would keep estimators for
+     * each node. In this version, we merely choose a peer 
+     * randomly.
+     */
+    public static class RoutingTable {
+
+        PeerNode[] peerNodes = null;
+
+        HashSet connectedNodes = new HashSet();
+        PeerNode[] connectedNodesArray;
+
+        public int connectedNodes() {
+            return connectedNodes.size();
+        }
+
+        public PeerNode route(HashSet peerNodesExcluded) {
+            PeerNode[] nodes = getConnectedNodes();
+            int length = nodes.length;
+            if(peerNodesExcluded.size() > 0) {
+                PeerNode[] nodesNotExcluded = new PeerNode[length];
+                int j=0;
+                for(int i=0;i<length;i++) {
+                    PeerNode pn = nodes[i];
+                    if(peerNodesExcluded.contains(pn)) {
+                        Logger.minor(this, "Excluding: "+pn+" = "+pn.peer);
+                        continue;
+                    }
+                    nodesNotExcluded[j] = pn;
+                    j++;
+                }
+                nodes = nodesNotExcluded;
+                length = j;
+            }
+            Logger.debug(this, "Route choices length: "+length);
+            if(length == 0) return null;
+            else return nodes[r.nextInt(length)];
+        }
+        
+        public synchronized PeerNode[] getConnectedNodes() {
+            if(connectedNodesArray == null) {
+                connectedNodesArray = new PeerNode[connectedNodes.size()];
+                connectedNodes.toArray(connectedNodesArray);
+            }
+            return connectedNodesArray;
+        }
+
+        /**
+         * Try to connect to all nodes.
+         */
+        public synchronized void doInitialConnectAll() {
+            // Connect to all peers
+            if(peerNodes == null || peerNodes.length == 0) {
+                Logger.error(this, "No peer nodes");
+                return;
+            }
+            while(true) {
+                boolean failedConnect = false;
+                for(int i=0;i<peerNodes.length;i++) {
+                    PeerNode pn = peerNodes[i];
+                    Logger.debug(this, "["+i+"]: "+pn);
+                    if(!pn.isConnected()) {
+                        Logger.minor(this, "Trying to connect to "+pn);
+                        if(!pn.tryConnectOnce())
+                            failedConnect = true;
+                    }
+                }
+                if(!failedConnect) break;
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+        }
+
+        public synchronized void addPeerNode(PeerNode p) {
+            Logger.debug(this,"Adding "+p);
+            if(peerNodes == null)
+                Logger.debug(this, "peerNodes = null");
+            else
+                Logger.debug(this, "peerNodes size = "+peerNodes.length);
+            int length;
+            if(p == null) throw new NullPointerException();
+            if(peerNodes == null) length = 0;
+            else length = peerNodes.length;
+            PeerNode[] newPeers = new PeerNode[length+1];
+            if(length > 0)
+                System.arraycopy(peerNodes, 0, newPeers, 0, peerNodes.length);
+            newPeers[newPeers.length-1] = p;
+            peerNodes = newPeers;
+            for(int i=0;i<peerNodes.length;i++)
+                Logger.debug(this, "peerNodes["+i+"] = "+peerNodes[i]);
+        }
+
+        public synchronized void onConnected(PeerNode p) {
+            connectedNodes.add(p);
+            connectedNodesArray = null;
+        }
+        
+        public synchronized void onDisconnected(PeerNode p) {
+            connectedNodesArray = null;
+            // FIXME
+        }
+
+        /**
+         * @return The total number of nodes known.
+         */
+        public int totalPeers() {
+            return peerNodes.length;
+        }
+
+        /**
+         * @param otherSide
+         * @return
+         */
+        public PeerNode getPeerNode(Peer otherSide) {
+            for(int i=0;i<peerNodes.length;i++) {
+                PeerNode pn = peerNodes[i];
+                if(pn.peer.equals(otherSide)) return pn;
+            }
+            return null;
+        }
+    }
+    
+    /**
+     * A peer node. Would contain estimators as well as contact
+     * details.
+     * @author amphibian
+     */
+    public static class PeerNode {
+        int portNumber;
+        Peer peer;
+        
+        PeerNode(int portNum) {
+            this.portNumber = portNum;
+            try {
+                peer = new Peer(InetAddress.getByName("127.0.0.1"), portNum);
+            } catch (UnknownHostException e) {
+                // WTF?
+                throw new Error(e);
+            }
+        }
+
+        public int hashCode() {
+            return portNumber;
+        }
+        
+        public String toString() {
+            return super.toString()+":port="+portNumber;
+        }
+
+        public boolean equals(Object o) {
+            // FIXME: do we need to actually compare content?
+            // Probably not... there should only be one PeerNode for each peer.
+            return (o == this);
+        }
+        
+        /**
+         * @return
+         */
+        public boolean isConnected() {
+            return connected;
+        }
+
+        int consecutivePings = 0;
+        boolean connected = false;
+        
+        /**
+         * Attempt to connect to this node.
+         * @return true if we have succeeded
+         */
+        public boolean tryConnectOnce() {
+            if(!connected) {
+                Logger.normal(TransferBlockTest.class, "Sending ping");
+                usm.send(peer, DMT.createPing());
+                Message m = usm.waitFor(MessageFilter.create().
+                        setTimeout(1000).setType(DMT.pong).setSource(peer));
+                if(m != null) {
+                    consecutivePings++;
+                    Logger.normal(TransferBlockTest.class, "Got pong: "+m);
+                } else {
+                    consecutivePings = 0;
+                    connected = false;
+                }
+            }
+            if(consecutivePings >= 3) {
+                connected = true;
+                rt.onConnected(this);
+                return true;
+            }
+            Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings to "+this);
+            return false;
+        }
+    }
+    
+    static FreenetStore fs;
+    static UdpSocketManager usm;
+    final static Random r = new Random();
+    static RoutingTable rt;
+    static int myPort;
+    
+    public static void main(String[] args) throws Exception {
+        Logger.setupStdoutLogging(Logger.DEBUG, "");
+        rt = new RoutingTable();
+        // Parse parameters.
+        parseParameters(args);
+        // Set up a UdpSocketManager
+        usm = new UdpSocketManager(myPort);
+        usm.setDispatcher(new MyDispatcher());
+        //usm.setDropProbability(10);
+        rt.doInitialConnectAll();
+        // Setup datastore
+        fs = new FreenetStore("datastore-"+myPort, "headerstore-"+myPort, 
1024);
+        printHeader();
+        interfaceLoop();
+    }
+
+    private static void interfaceLoop() throws IOException {
+        // Read command, and data
+        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
+        while(true) {
+            String line = reader.readLine();
+            if(line.startsWith("GET:")) {
+                // Should have a key next
+                String key = line.substring("GET:".length());
+                while(key.length() > 0 && key.charAt(0) == ' ')
+                    key = key.substring(1);
+                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
+                    key = key.substring(0, key.length()-2);
+                Logger.normal(DatastoreTest.class, "Key: "+key);
+                FreenetURI uri = new FreenetURI(key);
+                ClientCHK chk = new ClientCHK(uri);
+                CHKBlock block;
+                try {
+                    // Fetch, possibly from other node.
+                    block = runRequest(chk.getNodeCHK(), 3, r.nextLong(), 
null, null);
+                } catch (CHKVerifyException e1) {
+                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
+                    continue;
+                }
+                if(block == null) {
+                    System.out.println("Not found in store: "+chk.getURI());
+                } else {
+                    // Decode it
+                    byte[] decoded;
+                    try {
+                        decoded = block.decode(chk);
+                    } catch (CHKDecodeException e) {
+                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
+                        continue;
+                    }
+                    System.out.println("Decoded data:\n");
+                    System.out.println(new String(decoded));
+                }
+            } else if(line.startsWith("QUIT")) {
+                System.out.println("Goodbye.");
+                System.exit(0);
+            } else if(line.startsWith("PUT:")) {
+                // Just insert to local store
+                line = line.substring("PUT:".length());
+                while(line.length() > 0 && line.charAt(0) == ' ')
+                    line = line.substring(1);
+                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
+                    line = line.substring(0, line.length()-2);
+                String content;
+                if(line.length() > 0) {
+                    // Single line insert
+                    content = line;
+                } else {
+                    // Multiple line insert
+                    StringBuffer sb = new StringBuffer(1000);
+                    while(true) {
+                        line = reader.readLine();
+                        if(line.equals(".")) break;
+                        sb.append(line).append('\n');
+                    }
+                    content = sb.toString();
+                }
+                // Insert
+                byte[] data = content.getBytes();
+                ClientCHKBlock block;
+                try {
+                    block = ClientCHKBlock.encode(data);
+                } catch (CHKEncodeException e) {
+                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
+                    continue;
+                }
+                ClientCHK chk = block.getClientKey();
+                FreenetURI uri = 
+                    chk.getURI();
+                fs.put(block);
+                // Definitely interface
+                System.out.println("URI: "+uri);
+            } else {
+                
+            }
+        }
+    }
+
+    /**
+     * Parse parameters.
+     * The first one is my port number.
+     * The second, third, fourth... are the port numbers of
+     * nodes to add to the routing table.
+     */
+    private static void parseParameters(String[] args) throws 
UnknownHostException {
+        if(args.length < 2) {
+            System.err.println("Syntax: QuasiNodeTest <myPort> <node1's port> 
<node2's port> <node3's port>... ");
+            System.exit(1);
+        }
+        myPort = Integer.parseInt(args[0]);
+        myPeer = new Peer(InetAddress.getByName("127.0.0.1"), myPort);
+        for(int i=1;i<args.length;i++) {
+            int port = Integer.parseInt(args[i]);
+            Logger.minor(PreNodeTest.class, "Adding node on port "+port);
+            PeerNode p = new PeerNode(port);
+            rt.addPeerNode(p);
+        }
+        Logger.normal(PreNodeTest.class, "Added "+rt.totalPeers()+" peers");
+    }
+
+    /**
+     * Either fetch the key from the datastore, or request it from the other
+     * node.
+     * 
+     * @param nodeCHK
+     *            The key to fetch.
+     * @param htl
+     *            The hops to live.
+     * @return null if we can't find the data.
+     */
+    private static CHKBlock runRequest(NodeCHK nodeCHK, int htl, long id,
+            Peer source, PeerNode sourceNode) throws IOException,
+            CHKVerifyException {
+        Logger.debug(PreNodeTest.class, "runRequest for "+nodeCHK+"@ 
HTL="+htl+" for "+source+" : "+sourceNode);
+        previousIDs.add(new Long(id));
+        idsRunning.register(id, source == null ? myPeer : source);
+        // Send the ACK
+        if (source != null) usm.send(source, DMT.createAcknowledgeRequest(id));
+        try {
+            HashSet peersSentTo = new HashSet();
+            if (sourceNode != null) peersSentTo.add(sourceNode);
+            // No source - catch any requests to this ID, check source later
+            MessageFilter requestFilter = 
MessageFilter.create().setType(DMT.testRequest).setField(DMT.UID, id);
+            while (true) {
+                // First try the store
+                CHKBlock block = fs.fetch(nodeCHK);
+                if (block != null) {
+                    if(source != null) {
+                        // End node
+                        PartiallyReceivedBlock prb = new 
PartiallyReceivedBlock(32, 1024, block.getData());
+                        byte[] header = block.getHeader();
+                        SendJob sj = new SendJob(prb, source, id, header, 
true);
+                        Thread t = new Thread(sj);
+                        t.start();
+                    }
+                    return block;
+                }
+                if (htl <= 0) return block;
+                // Otherwise...
+                PeerNode pn = rt.route(peersSentTo);
+                if (pn == null) {
+                    Logger.minor(PreNodeTest.class, "Ran out of peers");
+                    // FIXME: should this be a separate message? 
LateQueryRejected, perhaps?
+                    if(source != null) {
+                        Message dnf = DMT.createTestDataNotFound(id);
+                        usm.send(source, dnf);
+                    }
+                    return null;
+                }
+                Logger.minor(PreNodeTest.class, "Routing to " + pn);
+                Peer peer = pn.peer;
+                MessageFilter justReply = MessageFilter.create().setType(
+                        DMT.testDataReply).setField(DMT.UID, id)
+                        .setSource(peer);
+                MessageFilter replyFilter = justReply.or(MessageFilter.create()
+                        .setField(DMT.UID, id).setType(DMT.testDataNotFound)
+                        .setSource(peer));
+                Message request = DMT.createTestRequest(nodeCHK, id, htl);
+                Message accepted = null;
+                MessageFilter ackFilter = MessageFilter.create().setType(
+                        DMT.acknowledgeRequest).setSource(peer).setField(
+                        DMT.UID, id);
+                MessageFilter qrFilter = MessageFilter.create().setType(
+                        DMT.rejectDueToLoop).setSource(peer).setField(DMT.UID,
+                        id);
+                peersSentTo.add(pn);
+                MessageFilter wait = 
qrFilter.or(ackFilter.or(replyFilter.or(requestFilter)));
+                wait.setTimeout(1000);
+                for (int i = 0; i < 5; i++) {
+                    usm.send(peer, request);
+                    // Wait for Accepted
+                    accepted = usm.waitFor(wait);
+                    if (accepted == null) continue;
+                    if (accepted.getSpec() == DMT.testRequest) {
+                        // Is a request
+                        if(accepted.getSource() == source) {
+                            // Is a rerequest.
+                            // Resend the Accepted.
+                            usm.send(source, DMT.createAcknowledgeRequest(id));
+                        } else {
+                            // Is a loop
+                            usm.send(accepted.getSource(), 
DMT.createRejectDueToLoop(id));
+                        }
+                        accepted = null;
+                        continue;
+                    }
+                    break;
+                    // Didn't get Accepted - probably didn't receive our 
request
+                }
+                Logger.debug(PreNodeTest.class, "Waiting for Accepted got 
"+accepted);
+                if (accepted == null) {
+                    Logger.normal(PreNodeTest.class, "Did not get Accepted");
+                    // Try another node
+                    continue;
+                }
+                if (accepted.getSpec() == DMT.rejectDueToLoop) {
+                    Logger.minor(PreNodeTest.class, "Rejected: Loop");
+                    // Try another node
+                    continue;
+                }
+                Message reply;
+                // If it's not Accepted, it's something else...
+                if (accepted.getSpec() != DMT.acknowledgeRequest)
+                    reply = accepted;
+                else {
+                    while (true) {
+                        Logger.debug(PreNodeTest.class, "Waiting for reply");
+                        reply = usm.waitFor(replyFilter.or(requestFilter)
+                                .setTimeout(5000));
+                        if (reply == null) break;
+                        if (reply.getSpec() == DMT.testRequest) {
+                            if(reply.getSource() == source) {
+                                // Rerequest from requestor; resend
+                                usm.send(source, 
DMT.createAcknowledgeRequest(id));
+                            } else {
+                                // Loop
+                                usm.send(reply.getSource(), 
DMT.createRejectDueToLoop(id));                                
+                            }
+                            continue;
+                        }
+                        break;
+                    }
+                }
+                Logger.debug(PreNodeTest.class, "Got reply: "+reply);
+                // Process reply
+                if (reply == null) {
+                    Logger.normal(PreNodeTest.class,
+                            "Partner node did not reply");
+                    // Same as if can't find enough nodes
+                    continue;
+                    //return null;
+                } else if (reply.getSpec() == DMT.testDataNotFound) {
+                    // DNF
+                    Logger.normal(PreNodeTest.class, "Data Not Found");
+                    Message m = DMT.createTestDataNotFoundAck(id);
+                    usm.send(peer, m);
+                    
+                    if(source != null) {
+                        Message dnf = DMT.createTestDataNotFound(id);
+                        usm.send(source, dnf);
+                    }
+                    // If this gets lost, they'll send it again a few times...
+                    return null;
+                } else if (reply.getSpec() == DMT.testDataReply) {
+                    Logger.debug(PreNodeTest.class, "Got DataReply");
+                    byte[] header = ((Buffer) reply
+                            .getObject(DMT.TEST_CHK_HEADERS)).getData();
+                    // Send the ack
+                    Message m = DMT.createTestDataReplyAck(id);
+                    usm.send(peer, m);
+                    // Now wait for the transfer; he will send me the data
+                    // Receive the data
+                    PartiallyReceivedBlock prb;
+                    prb = new PartiallyReceivedBlock(32, 1024);
+                    BlockReceiver br;
+
+                    // Receive
+                    // ReceiveJob: Receive the entire file, then report back.
+                    ReceiveJob rj = new ReceiveJob(prb, peer, id);
+                    Thread rjt = new Thread(rj);
+                    rjt.start();
+
+                    if(source != null) {
+                        // Send
+                        // SendJob: Send the DataReply, wait for the ack, send 
the
+                        // data, then report back.
+                        SendJob sj = new SendJob(prb, source, id, header, 
false);
+                        Thread sjt = new Thread(sj);
+                        sjt.start();
+                    }
+
+                    /**
+                     * We can now receive: - Resent DataRequest from request
+                     * source => resend - Resent DataReply from peer (data
+                     * source) - Completion notification from SendJob -
+                     * Completion notification from ReceiveJob SendJob handles
+                     * DataReplyAck
+                     */
+
+                    MessageFilter sentCompleteWait = MessageFilter.create()
+                            .setType(DMT.testSendCompleted).setField(DMT.UID,
+                                    id);
+                    MessageFilter receiveCompleteWait = MessageFilter.create()
+                            .setType(DMT.testReceiveCompleted).setField(
+                                    DMT.UID, id);
+
+                    // FIXME: totally arbitrary timeout :)
+                    MessageFilter waitingFor = 
+                        
justReply.or(sentCompleteWait.or(receiveCompleteWait.or(requestFilter)));
+                    waitingFor = waitingFor.setTimeout(30 * 1000);
+
+                    boolean sendCompleted = false;
+                    boolean recvCompleted = false;
+
+                    while (true) {
+                        m = null;
+                        m = usm.waitFor(waitingFor);
+
+                        if (m == null) {
+                            // Timeout
+                            Logger.error(PreNodeTest.class, "Timeout in final 
wait");
+                            if(!recvCompleted) {
+                                // Other side will see broken send
+                                return null;
+                            } else {
+                                // We got it, they didn't
+                                break;
+                            }
+                        } else if (m.getSpec() == DMT.testSendCompleted) {
+                            Logger.minor(PreNodeTest.class, "Send completed");
+                            // Finished send
+                            sendCompleted = true;
+                            if (recvCompleted) break;
+                        } else if (m.getSpec() == DMT.testReceiveCompleted) {
+                            Logger.minor(PreNodeTest.class, "Receive 
completed");
+                            if(!m.getBoolean(DMT.SUCCESS)) {
+                                prb.abort(RetrievalException.SENDER_DIED, 
"Sender died");
+                                return null;
+                            }
+                            recvCompleted = true;
+                            if (sendCompleted || source == null) break;
+                        } else if (m.getSpec() == DMT.testDataReply) {
+                            Logger.minor(PreNodeTest.class, "Got DataReply");
+                            // Data source didn't get the acknowledgement
+                            // Resend the acknowledgement
+                            Message ack = DMT.createTestDataReplyAck(id);
+                            usm.send(peer, ack);
+                        } else if (m.getSpec() == DMT.testRequest) {
+                            Logger.minor(PreNodeTest.class, "Got DataRequest");
+                            if(m.getSource() == source) {
+                                Logger.minor(PreNodeTest.class, "DataRequest 
from source");
+                                // Resend request
+                                // Source got neither the accepted nor the 
DataReply
+                                // Resend the accepted, and let SendJob resend 
the DataReply
+                                // Difficult to get it to resend it 
immediately because it might just have sent it so just let it time out.
+                                usm.send(source, 
DMT.createAcknowledgeRequest(id));
+                            } else {
+                                // Loop - shouldn't happen at this stage
+                                Logger.normal(PreNodeTest.class, "Loop after 
have started sending");
+                                usm.send(m.getSource(), 
DMT.createRejectDueToLoop(id));                                
+                            }
+                            
+                        }
+                    }
+
+                    // Got data
+
+                    byte[] data = prb.getBlock();
+
+                    if (data == null)
+                            Logger.error(PreQuasiNodeTest.class,
+                                    "Could not receive data");
+                    System.err.println("Received " + data.length + " bytes");
+                    // Now decode it
+                    try {
+                        block = new CHKBlock(data, header, nodeCHK);
+                    } catch (CHKVerifyException e) {
+                        Logger.error(PreNodeTest.class, "Couldn't verify", e);
+                        return null;
+                    }
+                    return block;
+                } else {
+                    Logger.error(PreNodeTest.class, "Message " + reply
+                            + " - WTF?");
+                    return null;
+                }
+            }
+        } finally {
+            idsRunning.unregister(id);
+        }
+    }
+
+    private static void printHeader() {
+        // Write header
+        System.out.println("PreNode tester");
+        System.out.println("--------------");
+        System.out.println();
+        System.out.println("Enter one of the following commands:");
+        System.out.println("GET:<Freenet key> - fetch a key");
+        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
+        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
+        System.out.println("QUIT - exit the program");
+    }
+
+    public static class MyDispatcher implements Dispatcher {
+        public boolean handleMessage(Message m) {
+            if(m.getSpec() == DMT.ping) {
+                usm.send(m.getSource(), DMT.createPong(m));
+                return true;
+            }
+            if(m.getSpec() == DMT.testRequest) {
+                Peer origSource = idsRunning.getSource(m.getLong(DMT.UID));
+                Peer reqSource = m.getSource();
+                if(reqSource == origSource)
+                    // Resent by request source; ignore
+                    return true;
+                // Otherwise a genuine request, or a loop; either way needs 
further handling
+                try {
+                    new Thread(new RequestHandler(m)).start();
+                } catch (IllegalStateException e) {
+                    return true;
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+    
+    /**
+     * Handle a request.
+     * Check the store, if we have anything, then send it back.
+     * Otherwise send back DNF.
+     */
+    public static class RequestHandler implements Runnable {
+
+        final long id;
+        final NodeCHK key;
+        final Peer otherSide;
+        int htl;
+        
+        /**
+         * Constructor
+         * @param m
+         */
+        public RequestHandler(Message m) {
+            if(m.getSpec() != DMT.testRequest)
+                throw new IllegalArgumentException("Not a testRequest: 
"+m.getSpec().getName());
+            id = m.getLong(DMT.UID);
+            Object o = m.getObject(DMT.FREENET_ROUTING_KEY);
+            if(o instanceof NodeCHK)
+                key = (NodeCHK) o;
+            else {
+                // Ignore it
+                Logger.error(RequestHandler.class, "Node sent testRequest but 
key not a key! Ignoring request.");
+                throw new IllegalStateException("Node sent testRequest but key 
not a key! Ignoring request.");
+            }
+            otherSide = m.getSource();
+            htl = m.getInt(DMT.HTL);
+            htl--;
+        }
+
+        public void run() {
+            // Check ID
+            // FIXME: use an LRU
+            Long lid = new Long(id);
+            if(previousIDs.contains(lid)) {
+                // Reject
+                usm.send(otherSide, DMT.createRejectDueToLoop(id));
+                return;
+            }
+            try {
+                runRequest(key, htl, id, otherSide, rt.getPeerNode(otherSide));
+            } catch (IOException e) {
+                Logger.error(this, "IO error fetching: "+e,e);
+            } catch (CHKVerifyException e) {
+                Logger.error(this, "Couldn't verify data in store for "+key+": 
"+e,e);
+            }
+        }
+        
+    }
+}

Deleted: trunk/freenet/test/PreQuasiNodeTest.java
===================================================================
--- trunk/freenet/src/test/PreQuasiNodeTest.java        2006-12-13 18:27:21 UTC 
(rev 11374)
+++ trunk/freenet/test/PreQuasiNodeTest.java    2006-12-13 19:38:15 UTC (rev 
11378)
@@ -1,349 +0,0 @@
-package test;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.InetAddress;
-import java.util.Random;
-
-import freenet.io.comm.DMT;
-import freenet.io.comm.Dispatcher;
-import freenet.io.comm.Message;
-import freenet.io.comm.MessageFilter;
-import freenet.io.comm.Peer;
-import freenet.io.comm.RetrievalException;
-import freenet.io.comm.UdpSocketManager;
-import freenet.io.xfer.BlockReceiver;
-import freenet.io.xfer.BlockTransmitter;
-import freenet.io.xfer.PartiallyReceivedBlock;
-import freenet.keys.CHKBlock;
-import freenet.keys.CHKDecodeException;
-import freenet.keys.CHKEncodeException;
-import freenet.keys.CHKVerifyException;
-import freenet.keys.ClientCHK;
-import freenet.keys.ClientCHKBlock;
-import freenet.keys.FreenetURI;
-import freenet.keys.NodeCHK;
-import freenet.store.FreenetStore;
-import freenet.support.Buffer;
-import freenet.support.Logger;
-
-/**
- * First do 5 consecutive pings. Then:
- * Take requests and inserts from stdin text interface, like 
- * DatastoreTest.
- * Requests:
- * - If can answer from local datastore, do so.
- * - Otherwise route request to partner node.
- * - Partner node may return data, in which case use that.
- * Inserts:
- * - Insert goes just to this node.
- */
-public class PreQuasiNodeTest {
-
-    static FreenetStore fs;
-    static UdpSocketManager usm;
-    static Peer otherSide;
-    final static Random r = new Random();
-    
-    public static void main(String[] args) throws Exception {
-        if(args.length < 2) {
-            System.err.println("Syntax: PingTest <myPort> <hisPort>");
-            System.exit(1);
-        }
-        Logger.setupStdoutLogging(Logger.DEBUG, "");
-        int myPort = Integer.parseInt(args[0]);
-        int hisPort = Integer.parseInt(args[1]);
-        Logger.minor(TransferBlockTest.class, "My port: "+myPort+", his port: 
"+hisPort);
-        // Set up a UdpSocketManager
-        usm = new UdpSocketManager(myPort);
-        usm.setDropProbability(5);
-        usm.setDispatcher(new PingingReceivingDispatcher());
-        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
-        int consecutivePings = 0;
-        while(consecutivePings < 3) {
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-            }
-            Logger.normal(TransferBlockTest.class, "Sending ping");
-            usm.send(otherSide, DMT.createPing());
-            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
-            if(m != null) {
-                consecutivePings++;
-                Logger.normal(TransferBlockTest.class, "Got pong: "+m);
-            } else consecutivePings = 0;
-        }
-        Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings");
-        
-        // Setup datastore
-        fs = new FreenetStore("datastore-"+myPort, "headerstore-"+myPort, 
1024);
-        // Setup logging
-        Logger.setupStdoutLogging(Logger.DEBUG, "");
-        printHeader();
-        // Read command, and data
-        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
-        while(true) {
-            String line = reader.readLine();
-            if(line.startsWith("GET:")) {
-                // Should have a key next
-                String key = line.substring("GET:".length());
-                while(key.length() > 0 && key.charAt(0) == ' ')
-                    key = key.substring(1);
-                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
-                    key = key.substring(0, key.length()-2);
-                Logger.normal(DatastoreTest.class, "Key: "+key);
-                FreenetURI uri = new FreenetURI(key);
-                ClientCHK chk = new ClientCHK(uri);
-                CHKBlock block;
-                try {
-                    // Fetch, possibly from other node.
-                    block = fetch(chk.getNodeCHK());
-                } catch (CHKVerifyException e1) {
-                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
-                    continue;
-                }
-                if(block == null) {
-                    System.out.println("Not found in store: "+chk.getURI());
-                } else {
-                    // Decode it
-                    byte[] decoded;
-                    try {
-                        decoded = block.decode(chk);
-                    } catch (CHKDecodeException e) {
-                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
-                        continue;
-                    }
-                    System.out.println("Decoded data:\n");
-                    System.out.println(new String(decoded));
-                }
-            } else if(line.startsWith("QUIT")) {
-                System.out.println("Goodbye.");
-                System.exit(0);
-            } else if(line.startsWith("PUT:")) {
-                // Just insert to local store
-                line = line.substring("PUT:".length());
-                while(line.length() > 0 && line.charAt(0) == ' ')
-                    line = line.substring(1);
-                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
-                    line = line.substring(0, line.length()-2);
-                String content;
-                if(line.length() > 0) {
-                    // Single line insert
-                    content = line;
-                } else {
-                    // Multiple line insert
-                    StringBuffer sb = new StringBuffer(1000);
-                    while(true) {
-                        line = reader.readLine();
-                        if(line.equals(".")) break;
-                        sb.append(line).append('\n');
-                    }
-                    content = sb.toString();
-                }
-                // Insert
-                byte[] data = content.getBytes();
-                ClientCHKBlock block;
-                try {
-                    block = ClientCHKBlock.encode(data);
-                } catch (CHKEncodeException e) {
-                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
-                    continue;
-                }
-                ClientCHK chk = block.getClientKey();
-                FreenetURI uri = 
-                    chk.getURI();
-                fs.put(block);
-                // Definitely interface
-                System.out.println("URI: "+uri);
-            } else {
-                
-            }
-        }
-    }
-
-    /**
-     * Either fetch the key from the datastore, or request it 
-     * from the other node.
-     * @param nodeCHK The key to fetch.
-     * @return null if we can't find the data.
-     */
-    private static CHKBlock fetch(NodeCHK nodeCHK) throws IOException, 
CHKVerifyException {
-        // First try the store
-        CHKBlock block = fs.fetch(nodeCHK);
-        if(block != null) return block;
-        // Otherwise...
-        long id = r.nextLong();
-        Message request = DMT.createTestRequest(nodeCHK, id, -1);
-        usm.send(otherSide, request);
-        // Wait for response
-        Message reply = 
usm.waitFor(MessageFilter.create().setTimeout(5000).setType(DMT.testDataReply).setField(DMT.UID,
 id).
-                or(MessageFilter.create().setField(DMT.UID, 
id).setType(DMT.testDataNotFound)));
-        // Process reply
-        if(reply == null) {
-            Logger.normal(PreQuasiNodeTest.class, "Partner node did not 
reply");
-            return null;
-        } else if(reply.getSpec() == DMT.testDataNotFound) {
-            // DNF
-            Logger.normal(PreQuasiNodeTest.class, "Data Not Found");
-            Message m = DMT.createTestDataNotFound(id);
-            usm.send(otherSide, m);
-            // If this gets lost, they'll send it again a few times...
-            return null;
-        } else if(reply.getSpec() == DMT.testDataReply) {
-            byte[] header = 
((Buffer)reply.getObject(DMT.TEST_CHK_HEADERS)).getData();
-            // Send the ack
-            Message m = DMT.createTestDataReplyAck(id);
-            usm.send(otherSide, m);
-            // Now wait for the transfer; he will send me the data
-            // Receive the data
-            PartiallyReceivedBlock prb;
-            prb = new PartiallyReceivedBlock(32, 1024);
-            BlockReceiver br;
-            br = new BlockReceiver(usm, otherSide, id, prb);
-            byte[] data = null;
-            for(int i=0;i<5;i++) {
-                try {
-                    data = br.receive();
-                    break;
-                } catch (RetrievalException e1) {
-                    if(e1.getReason() == RetrievalException.SENDER_DIED) 
continue;
-                    Logger.error(PreQuasiNodeTest.class, "Failed to receive", 
e1);
-                    return null;
-                }
-            }
-            if(data == null)
-                Logger.error(PreQuasiNodeTest.class, "Could not receive data");
-            System.err.println("Received "+data.length+" bytes");
-            // Now decode it
-            try {
-                block = new CHKBlock(data, header, nodeCHK);
-            } catch (CHKVerifyException e) {
-                Logger.error(PreQuasiNodeTest.class, "Couldn't verify", e);
-                return null;
-            }
-            return block;
-        } else {
-            Logger.error(PreQuasiNodeTest.class, "Message "+reply+" - WTF?");
-            return null;
-        }
-    }
-
-    private static void printHeader() {
-        // Write header
-        System.out.println("PreQuasiNode tester");
-        System.out.println("-------------------");
-        System.out.println();
-        System.out.println("Enter one of the following commands:");
-        System.out.println("GET:<Freenet key> - fetch a key");
-        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
-        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
-        System.out.println("QUIT - exit the program");
-    }
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class PingingReceivingDispatcher implements Dispatcher {
-        public boolean handleMessage(Message m) {
-            if(m.getSpec() == DMT.ping) {
-                usm.send(m.getSource(), DMT.createPong(m));
-                return true;
-            }
-            if(m.getSpec() == DMT.testRequest) {
-                // Handle it
-                try {
-                    new Thread(new RequestHandler(m)).start();
-                } catch (IllegalStateException e) {
-                    return true;
-                }
-                return true;
-            }
-            return false;
-        }
-    }
-    
-    /**
-     * Handle a request.
-     * Check the store, if we have anything, then send it back.
-     * Otherwise send back DNF.
-     */
-    public static class RequestHandler implements Runnable {
-
-        final long id;
-        final NodeCHK key;
-        
-        /**
-         * Constructor
-         * @param m
-         */
-        public RequestHandler(Message m) {
-            if(m.getSpec() != DMT.testRequest)
-                throw new IllegalArgumentException("Not a testRequest: 
"+m.getSpec().getName());
-            id = m.getLong(DMT.UID);
-            Object o = m.getObject(DMT.FREENET_ROUTING_KEY);
-            if(o instanceof NodeCHK)
-                key = (NodeCHK) o;
-            else {
-                // Ignore it
-                Logger.error(RequestHandler.class, "Node sent testRequest but 
key not a key! Ignoring request.");
-                throw new IllegalStateException("Node sent testRequest but key 
not a key! Ignoring request.");
-            }
-        }
-
-        public void run() {
-            CHKBlock block = null;
-            try {
-                // First try the store
-                block = fs.fetch(key);
-            } catch (IOException e) {
-                Logger.error(this, "IO error fetching: "+e,e);
-            } catch (CHKVerifyException e) {
-                Logger.error(this, "Couldn't verify data in store for "+key+": 
"+e,e);
-            }
-            if(block != null) {
-                byte[] header = block.getHeader();
-                // First send the header
-                Message m = DMT.createTestDataReply(id, header);
-                Message ack = null;
-                for(int i=0;i<5;i++) {
-                    usm.send(otherSide, m);
-                    // Wait for the ack
-                    ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataReplyAck).setTimeout(1000).setField(DMT.UID,
 id));
-                    if(ack == null) {
-                        // They didn't receive it.
-                        // Try again.
-                        usm.send(otherSide, m);
-                    } else break;
-                }
-                if(ack == null) {
-                    // ack still null
-                    Logger.error(this, "Other side not acknowledging 
DataReply");
-                    return;
-                }
-                // Now send the actual data
-                byte[] data = block.getData();
-                PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 
1024, data);
-                BlockTransmitter bt = new BlockTransmitter(usm, otherSide, id, 
prb);
-                bt.send();
-                // All done
-                return;
-            } else {
-                // block == null
-                Message m = DMT.createTestDataNotFound(id);
-                for(int i=0;i<5;i++) {
-                    usm.send(otherSide, m);
-                    // Wait for the ack
-                    Message ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataNotFoundAck).setField(DMT.UID,
 id).setTimeout(1000));
-                    if(ack != null) return; // done :(
-                    // Go around again;
-                }
-                // Still here, so they didn't ack
-                Logger.error(this, "Other side not acknowledging DNF");
-            }
-        }
-        
-    }
-}

Copied: trunk/freenet/test/PreQuasiNodeTest.java (from rev 11377, 
trunk/freenet/src/test/PreQuasiNodeTest.java)
===================================================================
--- trunk/freenet/test/PreQuasiNodeTest.java                            (rev 0)
+++ trunk/freenet/test/PreQuasiNodeTest.java    2006-12-13 19:38:15 UTC (rev 
11378)
@@ -0,0 +1,349 @@
+package test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.util.Random;
+
+import freenet.io.comm.DMT;
+import freenet.io.comm.Dispatcher;
+import freenet.io.comm.Message;
+import freenet.io.comm.MessageFilter;
+import freenet.io.comm.Peer;
+import freenet.io.comm.RetrievalException;
+import freenet.io.comm.UdpSocketManager;
+import freenet.io.xfer.BlockReceiver;
+import freenet.io.xfer.BlockTransmitter;
+import freenet.io.xfer.PartiallyReceivedBlock;
+import freenet.keys.CHKBlock;
+import freenet.keys.CHKDecodeException;
+import freenet.keys.CHKEncodeException;
+import freenet.keys.CHKVerifyException;
+import freenet.keys.ClientCHK;
+import freenet.keys.ClientCHKBlock;
+import freenet.keys.FreenetURI;
+import freenet.keys.NodeCHK;
+import freenet.store.FreenetStore;
+import freenet.support.Buffer;
+import freenet.support.Logger;
+
+/**
+ * First do 5 consecutive pings. Then:
+ * Take requests and inserts from stdin text interface, like 
+ * DatastoreTest.
+ * Requests:
+ * - If can answer from local datastore, do so.
+ * - Otherwise route request to partner node.
+ * - Partner node may return data, in which case use that.
+ * Inserts:
+ * - Insert goes just to this node.
+ */
+public class PreQuasiNodeTest {
+
+    static FreenetStore fs;
+    static UdpSocketManager usm;
+    static Peer otherSide;
+    final static Random r = new Random();
+    
+    public static void main(String[] args) throws Exception {
+        if(args.length < 2) {
+            System.err.println("Syntax: PingTest <myPort> <hisPort>");
+            System.exit(1);
+        }
+        Logger.setupStdoutLogging(Logger.DEBUG, "");
+        int myPort = Integer.parseInt(args[0]);
+        int hisPort = Integer.parseInt(args[1]);
+        Logger.minor(TransferBlockTest.class, "My port: "+myPort+", his port: 
"+hisPort);
+        // Set up a UdpSocketManager
+        usm = new UdpSocketManager(myPort);
+        usm.setDropProbability(5);
+        usm.setDispatcher(new PingingReceivingDispatcher());
+        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
+        int consecutivePings = 0;
+        while(consecutivePings < 3) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+            Logger.normal(TransferBlockTest.class, "Sending ping");
+            usm.send(otherSide, DMT.createPing());
+            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
+            if(m != null) {
+                consecutivePings++;
+                Logger.normal(TransferBlockTest.class, "Got pong: "+m);
+            } else consecutivePings = 0;
+        }
+        Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings");
+        
+        // Setup datastore
+        fs = new FreenetStore("datastore-"+myPort, "headerstore-"+myPort, 
1024);
+        // Setup logging
+        Logger.setupStdoutLogging(Logger.DEBUG, "");
+        printHeader();
+        // Read command, and data
+        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
+        while(true) {
+            String line = reader.readLine();
+            if(line.startsWith("GET:")) {
+                // Should have a key next
+                String key = line.substring("GET:".length());
+                while(key.length() > 0 && key.charAt(0) == ' ')
+                    key = key.substring(1);
+                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
+                    key = key.substring(0, key.length()-2);
+                Logger.normal(DatastoreTest.class, "Key: "+key);
+                FreenetURI uri = new FreenetURI(key);
+                ClientCHK chk = new ClientCHK(uri);
+                CHKBlock block;
+                try {
+                    // Fetch, possibly from other node.
+                    block = fetch(chk.getNodeCHK());
+                } catch (CHKVerifyException e1) {
+                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
+                    continue;
+                }
+                if(block == null) {
+                    System.out.println("Not found in store: "+chk.getURI());
+                } else {
+                    // Decode it
+                    byte[] decoded;
+                    try {
+                        decoded = block.decode(chk);
+                    } catch (CHKDecodeException e) {
+                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
+                        continue;
+                    }
+                    System.out.println("Decoded data:\n");
+                    System.out.println(new String(decoded));
+                }
+            } else if(line.startsWith("QUIT")) {
+                System.out.println("Goodbye.");
+                System.exit(0);
+            } else if(line.startsWith("PUT:")) {
+                // Just insert to local store
+                line = line.substring("PUT:".length());
+                while(line.length() > 0 && line.charAt(0) == ' ')
+                    line = line.substring(1);
+                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
+                    line = line.substring(0, line.length()-2);
+                String content;
+                if(line.length() > 0) {
+                    // Single line insert
+                    content = line;
+                } else {
+                    // Multiple line insert
+                    StringBuffer sb = new StringBuffer(1000);
+                    while(true) {
+                        line = reader.readLine();
+                        if(line.equals(".")) break;
+                        sb.append(line).append('\n');
+                    }
+                    content = sb.toString();
+                }
+                // Insert
+                byte[] data = content.getBytes();
+                ClientCHKBlock block;
+                try {
+                    block = ClientCHKBlock.encode(data);
+                } catch (CHKEncodeException e) {
+                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
+                    continue;
+                }
+                ClientCHK chk = block.getClientKey();
+                FreenetURI uri = 
+                    chk.getURI();
+                fs.put(block);
+                // Definitely interface
+                System.out.println("URI: "+uri);
+            } else {
+                
+            }
+        }
+    }
+
+    /**
+     * Either fetch the key from the datastore, or request it 
+     * from the other node.
+     * @param nodeCHK The key to fetch.
+     * @return null if we can't find the data.
+     */
+    private static CHKBlock fetch(NodeCHK nodeCHK) throws IOException, 
CHKVerifyException {
+        // First try the store
+        CHKBlock block = fs.fetch(nodeCHK);
+        if(block != null) return block;
+        // Otherwise...
+        long id = r.nextLong();
+        Message request = DMT.createTestRequest(nodeCHK, id, -1);
+        usm.send(otherSide, request);
+        // Wait for response
+        Message reply = 
usm.waitFor(MessageFilter.create().setTimeout(5000).setType(DMT.testDataReply).setField(DMT.UID,
 id).
+                or(MessageFilter.create().setField(DMT.UID, 
id).setType(DMT.testDataNotFound)));
+        // Process reply
+        if(reply == null) {
+            Logger.normal(PreQuasiNodeTest.class, "Partner node did not 
reply");
+            return null;
+        } else if(reply.getSpec() == DMT.testDataNotFound) {
+            // DNF
+            Logger.normal(PreQuasiNodeTest.class, "Data Not Found");
+            Message m = DMT.createTestDataNotFound(id);
+            usm.send(otherSide, m);
+            // If this gets lost, they'll send it again a few times...
+            return null;
+        } else if(reply.getSpec() == DMT.testDataReply) {
+            byte[] header = 
((Buffer)reply.getObject(DMT.TEST_CHK_HEADERS)).getData();
+            // Send the ack
+            Message m = DMT.createTestDataReplyAck(id);
+            usm.send(otherSide, m);
+            // Now wait for the transfer; he will send me the data
+            // Receive the data
+            PartiallyReceivedBlock prb;
+            prb = new PartiallyReceivedBlock(32, 1024);
+            BlockReceiver br;
+            br = new BlockReceiver(usm, otherSide, id, prb);
+            byte[] data = null;
+            for(int i=0;i<5;i++) {
+                try {
+                    data = br.receive();
+                    break;
+                } catch (RetrievalException e1) {
+                    if(e1.getReason() == RetrievalException.SENDER_DIED) 
continue;
+                    Logger.error(PreQuasiNodeTest.class, "Failed to receive", 
e1);
+                    return null;
+                }
+            }
+            if(data == null)
+                Logger.error(PreQuasiNodeTest.class, "Could not receive data");
+            System.err.println("Received "+data.length+" bytes");
+            // Now decode it
+            try {
+                block = new CHKBlock(data, header, nodeCHK);
+            } catch (CHKVerifyException e) {
+                Logger.error(PreQuasiNodeTest.class, "Couldn't verify", e);
+                return null;
+            }
+            return block;
+        } else {
+            Logger.error(PreQuasiNodeTest.class, "Message "+reply+" - WTF?");
+            return null;
+        }
+    }
+
+    private static void printHeader() {
+        // Write header
+        System.out.println("PreQuasiNode tester");
+        System.out.println("-------------------");
+        System.out.println();
+        System.out.println("Enter one of the following commands:");
+        System.out.println("GET:<Freenet key> - fetch a key");
+        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
+        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
+        System.out.println("QUIT - exit the program");
+    }
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class PingingReceivingDispatcher implements Dispatcher {
+        public boolean handleMessage(Message m) {
+            if(m.getSpec() == DMT.ping) {
+                usm.send(m.getSource(), DMT.createPong(m));
+                return true;
+            }
+            if(m.getSpec() == DMT.testRequest) {
+                // Handle it
+                try {
+                    new Thread(new RequestHandler(m)).start();
+                } catch (IllegalStateException e) {
+                    return true;
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+    
+    /**
+     * Handle a request.
+     * Check the store, if we have anything, then send it back.
+     * Otherwise send back DNF.
+     */
+    public static class RequestHandler implements Runnable {
+
+        final long id;
+        final NodeCHK key;
+        
+        /**
+         * Constructor
+         * @param m
+         */
+        public RequestHandler(Message m) {
+            if(m.getSpec() != DMT.testRequest)
+                throw new IllegalArgumentException("Not a testRequest: 
"+m.getSpec().getName());
+            id = m.getLong(DMT.UID);
+            Object o = m.getObject(DMT.FREENET_ROUTING_KEY);
+            if(o instanceof NodeCHK)
+                key = (NodeCHK) o;
+            else {
+                // Ignore it
+                Logger.error(RequestHandler.class, "Node sent testRequest but 
key not a key! Ignoring request.");
+                throw new IllegalStateException("Node sent testRequest but key 
not a key! Ignoring request.");
+            }
+        }
+
+        public void run() {
+            CHKBlock block = null;
+            try {
+                // First try the store
+                block = fs.fetch(key);
+            } catch (IOException e) {
+                Logger.error(this, "IO error fetching: "+e,e);
+            } catch (CHKVerifyException e) {
+                Logger.error(this, "Couldn't verify data in store for "+key+": 
"+e,e);
+            }
+            if(block != null) {
+                byte[] header = block.getHeader();
+                // First send the header
+                Message m = DMT.createTestDataReply(id, header);
+                Message ack = null;
+                for(int i=0;i<5;i++) {
+                    usm.send(otherSide, m);
+                    // Wait for the ack
+                    ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataReplyAck).setTimeout(1000).setField(DMT.UID,
 id));
+                    if(ack == null) {
+                        // They didn't receive it.
+                        // Try again.
+                        usm.send(otherSide, m);
+                    } else break;
+                }
+                if(ack == null) {
+                    // ack still null
+                    Logger.error(this, "Other side not acknowledging 
DataReply");
+                    return;
+                }
+                // Now send the actual data
+                byte[] data = block.getData();
+                PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 
1024, data);
+                BlockTransmitter bt = new BlockTransmitter(usm, otherSide, id, 
prb);
+                bt.send();
+                // All done
+                return;
+            } else {
+                // block == null
+                Message m = DMT.createTestDataNotFound(id);
+                for(int i=0;i<5;i++) {
+                    usm.send(otherSide, m);
+                    // Wait for the ack
+                    Message ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataNotFoundAck).setField(DMT.UID,
 id).setTimeout(1000));
+                    if(ack != null) return; // done :(
+                    // Go around again;
+                }
+                // Still here, so they didn't ack
+                Logger.error(this, "Other side not acknowledging DNF");
+            }
+        }
+        
+    }
+}

Deleted: trunk/freenet/test/QuasiNodeTest.java
===================================================================
--- trunk/freenet/src/test/QuasiNodeTest.java   2006-12-13 18:27:21 UTC (rev 
11374)
+++ trunk/freenet/test/QuasiNodeTest.java       2006-12-13 19:38:15 UTC (rev 
11378)
@@ -1,533 +0,0 @@
-package test;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HashSet;
-import java.util.Random;
-
-import freenet.io.comm.DMT;
-import freenet.io.comm.Dispatcher;
-import freenet.io.comm.Message;
-import freenet.io.comm.MessageFilter;
-import freenet.io.comm.Peer;
-import freenet.io.comm.RetrievalException;
-import freenet.io.comm.UdpSocketManager;
-import freenet.io.xfer.BlockReceiver;
-import freenet.io.xfer.BlockTransmitter;
-import freenet.io.xfer.PartiallyReceivedBlock;
-import freenet.keys.CHKBlock;
-import freenet.keys.CHKDecodeException;
-import freenet.keys.CHKEncodeException;
-import freenet.keys.CHKVerifyException;
-import freenet.keys.ClientCHK;
-import freenet.keys.ClientCHKBlock;
-import freenet.keys.FreenetURI;
-import freenet.keys.NodeCHK;
-import freenet.store.FreenetStore;
-import freenet.support.Buffer;
-import freenet.support.Logger;
-
-/**
- * Invoker provides list of nodes to connect to (port #s).
- * Do handshake with each.. 5 consecutive pings.
- * 
- * Then:
- * Take requests and inserts from stdin, like DatastoreTest.
- * Inserts:
- * - Just put to local store.
- * Requests:
- * - Choose a (random) peer to request from.
- * 
- * Requests are still 1-hop-only.
- */
-public class QuasiNodeTest {
-
-
-    /**
-     * @author amphibian
-     * 
-     * Keeps track of who we are connected to.
-     * Also provides functionality for routing.
-     * In a full implementation, we would keep estimators for
-     * each node. In this version, we merely choose a peer 
-     * randomly.
-     */
-    public static class RoutingTable {
-
-        PeerNode[] peerNodes = null;
-
-        HashSet connectedNodes = new HashSet();
-        PeerNode[] connectedNodesArray;
-
-        public int connectedNodes() {
-            return connectedNodes.size();
-        }
-
-        public PeerNode route() {
-            PeerNode[] nodes = getConnectedNodes();
-            return nodes[r.nextInt(nodes.length)];
-        }
-        
-        public synchronized PeerNode[] getConnectedNodes() {
-            if(connectedNodesArray == null) {
-                connectedNodesArray = new PeerNode[connectedNodes.size()];
-                connectedNodes.toArray(connectedNodesArray);
-            }
-            return connectedNodesArray;
-        }
-
-        /**
-         * Try to connect to all nodes.
-         */
-        public synchronized void doInitialConnectAll() {
-            // Connect to all peers
-            if(peerNodes == null || peerNodes.length == 0) {
-                Logger.error(this, "No peer nodes");
-                return;
-            }
-            while(true) {
-                boolean failedConnect = false;
-                for(int i=0;i<peerNodes.length;i++) {
-                    PeerNode pn = peerNodes[i];
-                    Logger.debug(this, "["+i+"]: "+pn);
-                    if(!pn.isConnected()) {
-                        Logger.minor(this, "Trying to connect to "+pn);
-                        if(!pn.tryConnectOnce())
-                            failedConnect = true;
-                    }
-                }
-                if(!failedConnect) break;
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    // Ignore
-                }
-            }
-        }
-
-        public synchronized void addPeerNode(PeerNode p) {
-            Logger.debug(this,"Adding "+p);
-            if(peerNodes == null)
-                Logger.debug(this, "peerNodes = null");
-            else
-                Logger.debug(this, "peerNodes size = "+peerNodes.length);
-            int length;
-            if(p == null) throw new NullPointerException();
-            if(peerNodes == null) length = 0;
-            else length = peerNodes.length;
-            PeerNode[] newPeers = new PeerNode[length+1];
-            if(length > 0)
-                System.arraycopy(peerNodes, 0, newPeers, 0, peerNodes.length);
-            newPeers[newPeers.length-1] = p;
-            peerNodes = newPeers;
-            for(int i=0;i<peerNodes.length;i++)
-                Logger.debug(this, "peerNodes["+i+"] = "+peerNodes[i]);
-        }
-
-        public synchronized void onConnected(PeerNode p) {
-            connectedNodes.add(p);
-            connectedNodesArray = null;
-        }
-        
-        public synchronized void onDisconnected(PeerNode p) {
-            connectedNodesArray = null;
-            // FIXME
-        }
-
-        /**
-         * @return The total number of nodes known.
-         */
-        public int totalPeers() {
-            return peerNodes.length;
-        }
-    }
-    
-    /**
-     * A peer node. Would contain estimators as well as contact
-     * details.
-     * @author amphibian
-     */
-    public static class PeerNode {
-        int portNumber;
-        Peer peer;
-        
-        PeerNode(int portNum) {
-            this.portNumber = portNum;
-            try {
-                peer = new Peer(InetAddress.getByName("127.0.0.1"), portNum);
-            } catch (UnknownHostException e) {
-                // WTF?
-                throw new Error(e);
-            }
-        }
-
-        public int hashCode() {
-            return portNumber;
-        }
-        
-        public String toString() {
-            return super.toString()+":port="+portNumber;
-        }
-
-        public boolean equals(Object o) {
-            // FIXME: do we need to actually compare content?
-            // Probably not... there should only be one PeerNode for each peer.
-            return (o == this);
-        }
-        
-        /**
-         * @return
-         */
-        public boolean isConnected() {
-            return connected;
-        }
-
-        int consecutivePings = 0;
-        boolean connected = false;
-        
-        /**
-         * Attempt to connect to this node.
-         * @return true if we have succeeded
-         */
-        public boolean tryConnectOnce() {
-            if(!connected) {
-                Logger.normal(TransferBlockTest.class, "Sending ping");
-                usm.send(peer, DMT.createPing());
-                Message m = usm.waitFor(MessageFilter.create().
-                        setTimeout(1000).setType(DMT.pong).setSource(peer));
-                if(m != null) {
-                    consecutivePings++;
-                    Logger.normal(TransferBlockTest.class, "Got pong: "+m);
-                } else {
-                    consecutivePings = 0;
-                    connected = false;
-                }
-            }
-            if(consecutivePings >= 3) {
-                connected = true;
-                rt.onConnected(this);
-                return true;
-            }
-            Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings to "+this);
-            return false;
-        }
-    }
-    
-    static FreenetStore fs;
-    static UdpSocketManager usm;
-    final static Random r = new Random();
-    static RoutingTable rt;
-    static int myPort;
-    
-    public static void main(String[] args) throws Exception {
-        Logger.setupStdoutLogging(Logger.DEBUG, "");
-        rt = new RoutingTable();
-        // Parse parameters.
-        parseParameters(args);
-        // Set up a UdpSocketManager
-        usm = new UdpSocketManager(myPort);
-        usm.setDispatcher(new MyDispatcher());
-        usm.setDropProbability(10);
-        rt.doInitialConnectAll();
-        // Setup datastore
-        fs = new FreenetStore("datastore-"+myPort, "headerstore-"+myPort, 
1024);
-        printHeader();
-        interfaceLoop();
-    }
-
-    private static void interfaceLoop() throws IOException {
-        // Read command, and data
-        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
-        while(true) {
-            String line = reader.readLine();
-            if(line.startsWith("GET:")) {
-                // Should have a key next
-                String key = line.substring("GET:".length());
-                while(key.length() > 0 && key.charAt(0) == ' ')
-                    key = key.substring(1);
-                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
-                    key = key.substring(0, key.length()-2);
-                Logger.normal(DatastoreTest.class, "Key: "+key);
-                FreenetURI uri = new FreenetURI(key);
-                ClientCHK chk = new ClientCHK(uri);
-                CHKBlock block;
-                try {
-                    // Fetch, possibly from other node.
-                    block = fetch(chk.getNodeCHK());
-                } catch (CHKVerifyException e1) {
-                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
-                    continue;
-                }
-                if(block == null) {
-                    System.out.println("Not found in store: "+chk.getURI());
-                } else {
-                    // Decode it
-                    byte[] decoded;
-                    try {
-                        decoded = block.decode(chk);
-                    } catch (CHKDecodeException e) {
-                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
-                        continue;
-                    }
-                    System.out.println("Decoded data:\n");
-                    System.out.println(new String(decoded));
-                }
-            } else if(line.startsWith("QUIT")) {
-                System.out.println("Goodbye.");
-                System.exit(0);
-            } else if(line.startsWith("PUT:")) {
-                // Just insert to local store
-                line = line.substring("PUT:".length());
-                while(line.length() > 0 && line.charAt(0) == ' ')
-                    line = line.substring(1);
-                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
-                    line = line.substring(0, line.length()-2);
-                String content;
-                if(line.length() > 0) {
-                    // Single line insert
-                    content = line;
-                } else {
-                    // Multiple line insert
-                    StringBuffer sb = new StringBuffer(1000);
-                    while(true) {
-                        line = reader.readLine();
-                        if(line.equals(".")) break;
-                        sb.append(line).append('\n');
-                    }
-                    content = sb.toString();
-                }
-                // Insert
-                byte[] data = content.getBytes();
-                ClientCHKBlock block;
-                try {
-                    block = ClientCHKBlock.encode(data);
-                } catch (CHKEncodeException e) {
-                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
-                    continue;
-                }
-                ClientCHK chk = block.getClientKey();
-                FreenetURI uri = 
-                    chk.getURI();
-                fs.put(block);
-                // Definitely interface
-                System.out.println("URI: "+uri);
-            } else {
-                
-            }
-        }
-    }
-
-    /**
-     * Parse parameters.
-     * The first one is my port number.
-     * The second, third, fourth... are the port numbers of
-     * nodes to add to the routing table.
-     */
-    private static void parseParameters(String[] args) {
-        if(args.length < 2) {
-            System.err.println("Syntax: QuasiNodeTest <myPort> <node1's port> 
<node2's port> <node3's port>... ");
-            System.exit(1);
-        }
-        myPort = Integer.parseInt(args[0]);
-        for(int i=1;i<args.length;i++) {
-            int port = Integer.parseInt(args[i]);
-            Logger.minor(QuasiNodeTest.class, "Adding node on port "+port);
-            PeerNode p = new PeerNode(port);
-            rt.addPeerNode(p);
-        }
-        Logger.normal(QuasiNodeTest.class, "Added "+rt.totalPeers()+" peers");
-    }
-
-    /**
-     * Either fetch the key from the datastore, or request it 
-     * from the other node.
-     * @param nodeCHK The key to fetch.
-     * @return null if we can't find the data.
-     */
-    private static CHKBlock fetch(NodeCHK nodeCHK) throws IOException, 
CHKVerifyException {
-        // First try the store
-        CHKBlock block = fs.fetch(nodeCHK);
-        if(block != null) return block;
-        // Otherwise...
-        PeerNode pn = rt.route();
-        Logger.minor(QuasiNodeTest.class, "Routing to "+pn);
-        Peer peer = pn.peer;
-        long id = r.nextLong();
-        Message request = DMT.createTestRequest(nodeCHK, id, -1);
-        usm.send(peer, request);
-        // Wait for response
-        Message reply = 
usm.waitFor(MessageFilter.create().setTimeout(5000).setType(DMT.testDataReply).setField(DMT.UID,
 id).setSource(peer).
-                or(MessageFilter.create().setField(DMT.UID, 
id).setType(DMT.testDataNotFound).setSource(peer)));
-        // Process reply
-        if(reply == null) {
-            Logger.normal(QuasiNodeTest.class, "Partner node did not reply");
-            return null;
-        } else if(reply.getSpec() == DMT.testDataNotFound) {
-            // DNF
-            Logger.normal(QuasiNodeTest.class, "Data Not Found");
-            Message m = DMT.createTestDataNotFoundAck(id);
-            usm.send(peer, m);
-            // If this gets lost, they'll send it again a few times...
-            return null;
-        } else if(reply.getSpec() == DMT.testDataReply) {
-            byte[] header = 
((Buffer)reply.getObject(DMT.TEST_CHK_HEADERS)).getData();
-            // Send the ack
-            Message m = DMT.createTestDataReplyAck(id);
-            usm.send(peer, m);
-            // Now wait for the transfer; he will send me the data
-            // Receive the data
-            PartiallyReceivedBlock prb;
-            prb = new PartiallyReceivedBlock(32, 1024);
-            BlockReceiver br;
-            br = new BlockReceiver(usm, peer, id, prb);
-            byte[] data = null;
-            for(int i=0;i<5;i++) {
-                try {
-                    data = br.receive();
-                    break;
-                } catch (RetrievalException e1) {
-                    if(e1.getReason() == RetrievalException.SENDER_DIED) 
continue;
-                    Logger.error(QuasiNodeTest.class, "Failed to receive", e1);
-                    return null;
-                }
-            }
-            if(data == null)
-                Logger.error(PreQuasiNodeTest.class, "Could not receive data");
-            System.err.println("Received "+data.length+" bytes");
-            // Now decode it
-            try {
-                block = new CHKBlock(data, header, nodeCHK);
-            } catch (CHKVerifyException e) {
-                Logger.error(QuasiNodeTest.class, "Couldn't verify", e);
-                return null;
-            }
-            return block;
-        } else {
-            Logger.error(QuasiNodeTest.class, "Message "+reply+" - WTF?");
-            return null;
-        }
-    }
-
-    private static void printHeader() {
-        // Write header
-        System.out.println("QuasiNode tester");
-        System.out.println("----------------");
-        System.out.println();
-        System.out.println("Enter one of the following commands:");
-        System.out.println("GET:<Freenet key> - fetch a key");
-        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
-        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
-        System.out.println("QUIT - exit the program");
-    }
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class MyDispatcher implements Dispatcher {
-        public boolean handleMessage(Message m) {
-            if(m.getSpec() == DMT.ping) {
-                usm.send(m.getSource(), DMT.createPong(m));
-                return true;
-            }
-            if(m.getSpec() == DMT.testRequest) {
-                // Handle it
-                try {
-                    new Thread(new RequestHandler(m)).start();
-                } catch (IllegalStateException e) {
-                    return true;
-                }
-                return true;
-            }
-            return false;
-        }
-    }
-    
-    /**
-     * Handle a request.
-     * Check the store, if we have anything, then send it back.
-     * Otherwise send back DNF.
-     */
-    public static class RequestHandler implements Runnable {
-
-        final long id;
-        final NodeCHK key;
-        final Peer otherSide;
-        
-        /**
-         * Constructor
-         * @param m
-         */
-        public RequestHandler(Message m) {
-            if(m.getSpec() != DMT.testRequest)
-                throw new IllegalArgumentException("Not a testRequest: 
"+m.getSpec().getName());
-            id = m.getLong(DMT.UID);
-            Object o = m.getObject(DMT.FREENET_ROUTING_KEY);
-            if(o instanceof NodeCHK)
-                key = (NodeCHK) o;
-            else {
-                // Ignore it
-                Logger.error(RequestHandler.class, "Node sent testRequest but 
key not a key! Ignoring request.");
-                throw new IllegalStateException("Node sent testRequest but key 
not a key! Ignoring request.");
-            }
-            otherSide = m.getSource();
-        }
-
-        public void run() {
-            CHKBlock block = null;
-            try {
-                // First try the store
-                block = fs.fetch(key);
-            } catch (IOException e) {
-                Logger.error(this, "IO error fetching: "+e,e);
-            } catch (CHKVerifyException e) {
-                Logger.error(this, "Couldn't verify data in store for "+key+": 
"+e,e);
-            }
-            if(block != null) {
-                byte[] header = block.getHeader();
-                // First send the header
-                Message m = DMT.createTestDataReply(id, header);
-                Message ack = null;
-                for(int i=0;i<5;i++) {
-                    usm.send(otherSide, m);
-                    // Wait for the ack
-                    ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataReplyAck).setTimeout(1000).setField(DMT.UID,
 id));
-                    if(ack == null) {
-                        // They didn't receive it.
-                        // Try again.
-                        usm.send(otherSide, m);
-                    } else break;
-                }
-                if(ack == null) {
-                    // ack still null
-                    Logger.error(this, "Other side not acknowledging 
DataReply");
-                    return;
-                }
-                // Now send the actual data
-                byte[] data = block.getData();
-                PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 
1024, data);
-                BlockTransmitter bt = new BlockTransmitter(usm, otherSide, id, 
prb);
-                bt.send();
-                // All done
-                return;
-            } else {
-                // block == null
-                Message m = DMT.createTestDataNotFound(id);
-                for(int i=0;i<5;i++) {
-                    usm.send(otherSide, m);
-                    // Wait for the ack
-                    Message ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataNotFoundAck).setField(DMT.UID,
 id).setTimeout(1000));
-                    if(ack != null) return; // done :(
-                    // Go around again;
-                }
-                // Still here, so they didn't ack
-                Logger.error(this, "Other side not acknowledging DNF");
-            }
-        }
-        
-    }
-}

Copied: trunk/freenet/test/QuasiNodeTest.java (from rev 11377, 
trunk/freenet/src/test/QuasiNodeTest.java)
===================================================================
--- trunk/freenet/test/QuasiNodeTest.java                               (rev 0)
+++ trunk/freenet/test/QuasiNodeTest.java       2006-12-13 19:38:15 UTC (rev 
11378)
@@ -0,0 +1,533 @@
+package test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashSet;
+import java.util.Random;
+
+import freenet.io.comm.DMT;
+import freenet.io.comm.Dispatcher;
+import freenet.io.comm.Message;
+import freenet.io.comm.MessageFilter;
+import freenet.io.comm.Peer;
+import freenet.io.comm.RetrievalException;
+import freenet.io.comm.UdpSocketManager;
+import freenet.io.xfer.BlockReceiver;
+import freenet.io.xfer.BlockTransmitter;
+import freenet.io.xfer.PartiallyReceivedBlock;
+import freenet.keys.CHKBlock;
+import freenet.keys.CHKDecodeException;
+import freenet.keys.CHKEncodeException;
+import freenet.keys.CHKVerifyException;
+import freenet.keys.ClientCHK;
+import freenet.keys.ClientCHKBlock;
+import freenet.keys.FreenetURI;
+import freenet.keys.NodeCHK;
+import freenet.store.FreenetStore;
+import freenet.support.Buffer;
+import freenet.support.Logger;
+
+/**
+ * Invoker provides list of nodes to connect to (port #s).
+ * Do handshake with each.. 5 consecutive pings.
+ * 
+ * Then:
+ * Take requests and inserts from stdin, like DatastoreTest.
+ * Inserts:
+ * - Just put to local store.
+ * Requests:
+ * - Choose a (random) peer to request from.
+ * 
+ * Requests are still 1-hop-only.
+ */
+public class QuasiNodeTest {
+
+
+    /**
+     * @author amphibian
+     * 
+     * Keeps track of who we are connected to.
+     * Also provides functionality for routing.
+     * In a full implementation, we would keep estimators for
+     * each node. In this version, we merely choose a peer 
+     * randomly.
+     */
+    public static class RoutingTable {
+
+        PeerNode[] peerNodes = null;
+
+        HashSet connectedNodes = new HashSet();
+        PeerNode[] connectedNodesArray;
+
+        public int connectedNodes() {
+            return connectedNodes.size();
+        }
+
+        public PeerNode route() {
+            PeerNode[] nodes = getConnectedNodes();
+            return nodes[r.nextInt(nodes.length)];
+        }
+        
+        public synchronized PeerNode[] getConnectedNodes() {
+            if(connectedNodesArray == null) {
+                connectedNodesArray = new PeerNode[connectedNodes.size()];
+                connectedNodes.toArray(connectedNodesArray);
+            }
+            return connectedNodesArray;
+        }
+
+        /**
+         * Try to connect to all nodes.
+         */
+        public synchronized void doInitialConnectAll() {
+            // Connect to all peers
+            if(peerNodes == null || peerNodes.length == 0) {
+                Logger.error(this, "No peer nodes");
+                return;
+            }
+            while(true) {
+                boolean failedConnect = false;
+                for(int i=0;i<peerNodes.length;i++) {
+                    PeerNode pn = peerNodes[i];
+                    Logger.debug(this, "["+i+"]: "+pn);
+                    if(!pn.isConnected()) {
+                        Logger.minor(this, "Trying to connect to "+pn);
+                        if(!pn.tryConnectOnce())
+                            failedConnect = true;
+                    }
+                }
+                if(!failedConnect) break;
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+        }
+
+        public synchronized void addPeerNode(PeerNode p) {
+            Logger.debug(this,"Adding "+p);
+            if(peerNodes == null)
+                Logger.debug(this, "peerNodes = null");
+            else
+                Logger.debug(this, "peerNodes size = "+peerNodes.length);
+            int length;
+            if(p == null) throw new NullPointerException();
+            if(peerNodes == null) length = 0;
+            else length = peerNodes.length;
+            PeerNode[] newPeers = new PeerNode[length+1];
+            if(length > 0)
+                System.arraycopy(peerNodes, 0, newPeers, 0, peerNodes.length);
+            newPeers[newPeers.length-1] = p;
+            peerNodes = newPeers;
+            for(int i=0;i<peerNodes.length;i++)
+                Logger.debug(this, "peerNodes["+i+"] = "+peerNodes[i]);
+        }
+
+        public synchronized void onConnected(PeerNode p) {
+            connectedNodes.add(p);
+            connectedNodesArray = null;
+        }
+        
+        public synchronized void onDisconnected(PeerNode p) {
+            connectedNodesArray = null;
+            // FIXME
+        }
+
+        /**
+         * @return The total number of nodes known.
+         */
+        public int totalPeers() {
+            return peerNodes.length;
+        }
+    }
+    
+    /**
+     * A peer node. Would contain estimators as well as contact
+     * details.
+     * @author amphibian
+     */
+    public static class PeerNode {
+        int portNumber;
+        Peer peer;
+        
+        PeerNode(int portNum) {
+            this.portNumber = portNum;
+            try {
+                peer = new Peer(InetAddress.getByName("127.0.0.1"), portNum);
+            } catch (UnknownHostException e) {
+                // WTF?
+                throw new Error(e);
+            }
+        }
+
+        public int hashCode() {
+            return portNumber;
+        }
+        
+        public String toString() {
+            return super.toString()+":port="+portNumber;
+        }
+
+        public boolean equals(Object o) {
+            // FIXME: do we need to actually compare content?
+            // Probably not... there should only be one PeerNode for each peer.
+            return (o == this);
+        }
+        
+        /**
+         * @return
+         */
+        public boolean isConnected() {
+            return connected;
+        }
+
+        int consecutivePings = 0;
+        boolean connected = false;
+        
+        /**
+         * Attempt to connect to this node.
+         * @return true if we have succeeded
+         */
+        public boolean tryConnectOnce() {
+            if(!connected) {
+                Logger.normal(TransferBlockTest.class, "Sending ping");
+                usm.send(peer, DMT.createPing());
+                Message m = usm.waitFor(MessageFilter.create().
+                        setTimeout(1000).setType(DMT.pong).setSource(peer));
+                if(m != null) {
+                    consecutivePings++;
+                    Logger.normal(TransferBlockTest.class, "Got pong: "+m);
+                } else {
+                    consecutivePings = 0;
+                    connected = false;
+                }
+            }
+            if(consecutivePings >= 3) {
+                connected = true;
+                rt.onConnected(this);
+                return true;
+            }
+            Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings to "+this);
+            return false;
+        }
+    }
+    
+    static FreenetStore fs;
+    static UdpSocketManager usm;
+    final static Random r = new Random();
+    static RoutingTable rt;
+    static int myPort;
+    
+    public static void main(String[] args) throws Exception {
+        Logger.setupStdoutLogging(Logger.DEBUG, "");
+        rt = new RoutingTable();
+        // Parse parameters.
+        parseParameters(args);
+        // Set up a UdpSocketManager
+        usm = new UdpSocketManager(myPort);
+        usm.setDispatcher(new MyDispatcher());
+        usm.setDropProbability(10);
+        rt.doInitialConnectAll();
+        // Setup datastore
+        fs = new FreenetStore("datastore-"+myPort, "headerstore-"+myPort, 
1024);
+        printHeader();
+        interfaceLoop();
+    }
+
+    private static void interfaceLoop() throws IOException {
+        // Read command, and data
+        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
+        while(true) {
+            String line = reader.readLine();
+            if(line.startsWith("GET:")) {
+                // Should have a key next
+                String key = line.substring("GET:".length());
+                while(key.length() > 0 && key.charAt(0) == ' ')
+                    key = key.substring(1);
+                while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
+                    key = key.substring(0, key.length()-2);
+                Logger.normal(DatastoreTest.class, "Key: "+key);
+                FreenetURI uri = new FreenetURI(key);
+                ClientCHK chk = new ClientCHK(uri);
+                CHKBlock block;
+                try {
+                    // Fetch, possibly from other node.
+                    block = fetch(chk.getNodeCHK());
+                } catch (CHKVerifyException e1) {
+                    Logger.error(DatastoreTest.class, "Did not verify: "+e1, 
e1);
+                    continue;
+                }
+                if(block == null) {
+                    System.out.println("Not found in store: "+chk.getURI());
+                } else {
+                    // Decode it
+                    byte[] decoded;
+                    try {
+                        decoded = block.decode(chk);
+                    } catch (CHKDecodeException e) {
+                        Logger.error(DatastoreTest.class, "Cannot decode: "+e, 
e);
+                        continue;
+                    }
+                    System.out.println("Decoded data:\n");
+                    System.out.println(new String(decoded));
+                }
+            } else if(line.startsWith("QUIT")) {
+                System.out.println("Goodbye.");
+                System.exit(0);
+            } else if(line.startsWith("PUT:")) {
+                // Just insert to local store
+                line = line.substring("PUT:".length());
+                while(line.length() > 0 && line.charAt(0) == ' ')
+                    line = line.substring(1);
+                while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
+                    line = line.substring(0, line.length()-2);
+                String content;
+                if(line.length() > 0) {
+                    // Single line insert
+                    content = line;
+                } else {
+                    // Multiple line insert
+                    StringBuffer sb = new StringBuffer(1000);
+                    while(true) {
+                        line = reader.readLine();
+                        if(line.equals(".")) break;
+                        sb.append(line).append('\n');
+                    }
+                    content = sb.toString();
+                }
+                // Insert
+                byte[] data = content.getBytes();
+                ClientCHKBlock block;
+                try {
+                    block = ClientCHKBlock.encode(data);
+                } catch (CHKEncodeException e) {
+                    Logger.error(DatastoreTest.class, "Couldn't encode: "+e, 
e);
+                    continue;
+                }
+                ClientCHK chk = block.getClientKey();
+                FreenetURI uri = 
+                    chk.getURI();
+                fs.put(block);
+                // Definitely interface
+                System.out.println("URI: "+uri);
+            } else {
+                
+            }
+        }
+    }
+
+    /**
+     * Parse parameters.
+     * The first one is my port number.
+     * The second, third, fourth... are the port numbers of
+     * nodes to add to the routing table.
+     */
+    private static void parseParameters(String[] args) {
+        if(args.length < 2) {
+            System.err.println("Syntax: QuasiNodeTest <myPort> <node1's port> 
<node2's port> <node3's port>... ");
+            System.exit(1);
+        }
+        myPort = Integer.parseInt(args[0]);
+        for(int i=1;i<args.length;i++) {
+            int port = Integer.parseInt(args[i]);
+            Logger.minor(QuasiNodeTest.class, "Adding node on port "+port);
+            PeerNode p = new PeerNode(port);
+            rt.addPeerNode(p);
+        }
+        Logger.normal(QuasiNodeTest.class, "Added "+rt.totalPeers()+" peers");
+    }
+
+    /**
+     * Either fetch the key from the datastore, or request it 
+     * from the other node.
+     * @param nodeCHK The key to fetch.
+     * @return null if we can't find the data.
+     */
+    private static CHKBlock fetch(NodeCHK nodeCHK) throws IOException, 
CHKVerifyException {
+        // First try the store
+        CHKBlock block = fs.fetch(nodeCHK);
+        if(block != null) return block;
+        // Otherwise...
+        PeerNode pn = rt.route();
+        Logger.minor(QuasiNodeTest.class, "Routing to "+pn);
+        Peer peer = pn.peer;
+        long id = r.nextLong();
+        Message request = DMT.createTestRequest(nodeCHK, id, -1);
+        usm.send(peer, request);
+        // Wait for response
+        Message reply = 
usm.waitFor(MessageFilter.create().setTimeout(5000).setType(DMT.testDataReply).setField(DMT.UID,
 id).setSource(peer).
+                or(MessageFilter.create().setField(DMT.UID, 
id).setType(DMT.testDataNotFound).setSource(peer)));
+        // Process reply
+        if(reply == null) {
+            Logger.normal(QuasiNodeTest.class, "Partner node did not reply");
+            return null;
+        } else if(reply.getSpec() == DMT.testDataNotFound) {
+            // DNF
+            Logger.normal(QuasiNodeTest.class, "Data Not Found");
+            Message m = DMT.createTestDataNotFoundAck(id);
+            usm.send(peer, m);
+            // If this gets lost, they'll send it again a few times...
+            return null;
+        } else if(reply.getSpec() == DMT.testDataReply) {
+            byte[] header = 
((Buffer)reply.getObject(DMT.TEST_CHK_HEADERS)).getData();
+            // Send the ack
+            Message m = DMT.createTestDataReplyAck(id);
+            usm.send(peer, m);
+            // Now wait for the transfer; he will send me the data
+            // Receive the data
+            PartiallyReceivedBlock prb;
+            prb = new PartiallyReceivedBlock(32, 1024);
+            BlockReceiver br;
+            br = new BlockReceiver(usm, peer, id, prb);
+            byte[] data = null;
+            for(int i=0;i<5;i++) {
+                try {
+                    data = br.receive();
+                    break;
+                } catch (RetrievalException e1) {
+                    if(e1.getReason() == RetrievalException.SENDER_DIED) 
continue;
+                    Logger.error(QuasiNodeTest.class, "Failed to receive", e1);
+                    return null;
+                }
+            }
+            if(data == null)
+                Logger.error(PreQuasiNodeTest.class, "Could not receive data");
+            System.err.println("Received "+data.length+" bytes");
+            // Now decode it
+            try {
+                block = new CHKBlock(data, header, nodeCHK);
+            } catch (CHKVerifyException e) {
+                Logger.error(QuasiNodeTest.class, "Couldn't verify", e);
+                return null;
+            }
+            return block;
+        } else {
+            Logger.error(QuasiNodeTest.class, "Message "+reply+" - WTF?");
+            return null;
+        }
+    }
+
+    private static void printHeader() {
+        // Write header
+        System.out.println("QuasiNode tester");
+        System.out.println("----------------");
+        System.out.println();
+        System.out.println("Enter one of the following commands:");
+        System.out.println("GET:<Freenet key> - fetch a key");
+        System.out.println("PUT:\n<text, until a . on a line by itself> - We 
will insert the document and return the key.");
+        System.out.println("PUT:<text> - put a single line of text to a CHK 
and return the key.");
+        System.out.println("QUIT - exit the program");
+    }
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class MyDispatcher implements Dispatcher {
+        public boolean handleMessage(Message m) {
+            if(m.getSpec() == DMT.ping) {
+                usm.send(m.getSource(), DMT.createPong(m));
+                return true;
+            }
+            if(m.getSpec() == DMT.testRequest) {
+                // Handle it
+                try {
+                    new Thread(new RequestHandler(m)).start();
+                } catch (IllegalStateException e) {
+                    return true;
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+    
+    /**
+     * Handle a request.
+     * Check the store, if we have anything, then send it back.
+     * Otherwise send back DNF.
+     */
+    public static class RequestHandler implements Runnable {
+
+        final long id;
+        final NodeCHK key;
+        final Peer otherSide;
+        
+        /**
+         * Constructor
+         * @param m
+         */
+        public RequestHandler(Message m) {
+            if(m.getSpec() != DMT.testRequest)
+                throw new IllegalArgumentException("Not a testRequest: 
"+m.getSpec().getName());
+            id = m.getLong(DMT.UID);
+            Object o = m.getObject(DMT.FREENET_ROUTING_KEY);
+            if(o instanceof NodeCHK)
+                key = (NodeCHK) o;
+            else {
+                // Ignore it
+                Logger.error(RequestHandler.class, "Node sent testRequest but 
key not a key! Ignoring request.");
+                throw new IllegalStateException("Node sent testRequest but key 
not a key! Ignoring request.");
+            }
+            otherSide = m.getSource();
+        }
+
+        public void run() {
+            CHKBlock block = null;
+            try {
+                // First try the store
+                block = fs.fetch(key);
+            } catch (IOException e) {
+                Logger.error(this, "IO error fetching: "+e,e);
+            } catch (CHKVerifyException e) {
+                Logger.error(this, "Couldn't verify data in store for "+key+": 
"+e,e);
+            }
+            if(block != null) {
+                byte[] header = block.getHeader();
+                // First send the header
+                Message m = DMT.createTestDataReply(id, header);
+                Message ack = null;
+                for(int i=0;i<5;i++) {
+                    usm.send(otherSide, m);
+                    // Wait for the ack
+                    ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataReplyAck).setTimeout(1000).setField(DMT.UID,
 id));
+                    if(ack == null) {
+                        // They didn't receive it.
+                        // Try again.
+                        usm.send(otherSide, m);
+                    } else break;
+                }
+                if(ack == null) {
+                    // ack still null
+                    Logger.error(this, "Other side not acknowledging 
DataReply");
+                    return;
+                }
+                // Now send the actual data
+                byte[] data = block.getData();
+                PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 
1024, data);
+                BlockTransmitter bt = new BlockTransmitter(usm, otherSide, id, 
prb);
+                bt.send();
+                // All done
+                return;
+            } else {
+                // block == null
+                Message m = DMT.createTestDataNotFound(id);
+                for(int i=0;i<5;i++) {
+                    usm.send(otherSide, m);
+                    // Wait for the ack
+                    Message ack = 
usm.waitFor(MessageFilter.create().setType(DMT.testDataNotFoundAck).setField(DMT.UID,
 id).setTimeout(1000));
+                    if(ack != null) return; // done :(
+                    // Go around again;
+                }
+                // Still here, so they didn't ack
+                Logger.error(this, "Other side not acknowledging DNF");
+            }
+        }
+        
+    }
+}

Deleted: trunk/freenet/test/TransferBlockTest.java
===================================================================
--- trunk/freenet/src/test/TransferBlockTest.java       2006-12-13 18:27:21 UTC 
(rev 11374)
+++ trunk/freenet/test/TransferBlockTest.java   2006-12-13 19:38:15 UTC (rev 
11378)
@@ -1,237 +0,0 @@
-package test;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.security.NoSuchAlgorithmException;
-import java.util.Random;
-
-import freenet.io.comm.DMT;
-import freenet.io.comm.Dispatcher;
-import freenet.io.comm.Message;
-import freenet.io.comm.MessageFilter;
-import freenet.io.comm.Peer;
-import freenet.io.comm.RetrievalException;
-import freenet.io.comm.UdpSocketManager;
-import freenet.io.xfer.BlockReceiver;
-import freenet.io.xfer.BlockTransmitter;
-import freenet.io.xfer.PartiallyReceivedBlock;
-import freenet.keys.CHKDecodeException;
-import freenet.keys.CHKEncodeException;
-import freenet.keys.CHKVerifyException;
-import freenet.keys.ClientCHK;
-import freenet.keys.CHKBlock;
-import freenet.keys.ClientCHKBlock;
-import freenet.keys.FreenetURI;
-import freenet.support.Buffer;
-import freenet.support.Logger;
-
-/**
- * Read from stdin, encode to a new style CHK, send to other node.
- * When receive it, decode and display.
- * Hence this is the world's slowest UDP chat client.
- * Takes two parameters: ourPort and hisPort.
- * Does a ping handshake first, like TransferSendTest does.
- * @author amphibian
- */
-public class TransferBlockTest {
-
-
-
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class Receiver implements Runnable {
-
-        long uid;
-        String uriS;
-        FreenetURI uri;
-        byte[] header;
-        
-        public Receiver(long uid, String uriS, byte[] header) throws 
MalformedURLException {
-            this.uid = uid;
-            this.header = header;
-            this.uriS = uriS;
-            this.uri = new FreenetURI(uriS);
-        }
-
-        public void run() {
-            // First send the ack
-            usm.send(otherSide, DMT.createTestSendCHKAck(uid, uriS));
-            // Receive the data
-            PartiallyReceivedBlock prb;
-            prb = new PartiallyReceivedBlock(32, 1024);
-            BlockReceiver br;
-            br = new BlockReceiver(usm, otherSide, uid, prb);
-            byte[] data;
-            try {
-                data = br.receive();
-            } catch (RetrievalException e1) {
-                Logger.error(this, "Failed to receive", e1);
-                return;
-            }
-            System.err.println("Received "+data.length+" bytes");
-            ClientCHK k;
-            try {
-                k = new ClientCHK(uri);
-            } catch (MalformedURLException e3) {
-                Logger.error(this, "Invalid URL sent by other side", e3);
-                return;
-            }
-            // Now decode it
-            CHKBlock block;
-            try {
-                block = new CHKBlock(data, header, k.getNodeCHK());
-            } catch (CHKVerifyException e) {
-                Logger.error(this, "Couldn't verify", e);
-                return;
-            }
-            long tStart = System.currentTimeMillis();
-            byte[] decoded;
-            try {
-                decoded = block.decode(k);
-            } catch (CHKDecodeException e2) {
-                Logger.error(this, "Couldn't decode sent data", e2);
-                return;
-            }
-            long tEnd = System.currentTimeMillis();
-            Logger.minor(this, "Time taken to decode: "+(tEnd-tStart)+"ms");
-            Logger.minor(this, "Decoded: "+decoded.length+" bytes");
-            Logger.normal(this, "Decoded data:\n"+new String(decoded));
-            System.out.println("Decoded data:\n"+new String(decoded));
-        }
-    }
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class PingingReceivingDispatcher implements Dispatcher {
-        public boolean handleMessage(Message m) {
-            if(m.getSpec() == DMT.ping) {
-                usm.send(m.getSource(), DMT.createPong(m));
-                return true;
-            }
-            if(m.getSpec() == DMT.testSendCHK) {
-                long uid = m.getLong(DMT.UID);
-                String uri = m.getString(DMT.FREENET_URI);
-                Buffer buf = (Buffer)m.getObject(DMT.CHK_HEADER);
-                byte[] header = buf.getData();
-                Logger.minor(this, "Got send request, uid: "+uid+", key: 
"+uri);
-                // Receive the actual data
-                Receiver r;
-                try {
-                    r = new Receiver(uid, uri, header);
-                } catch (MalformedURLException e) {
-                    System.err.println(e.toString());
-                    e.printStackTrace();
-                    return true;
-                }
-                new Thread(r).start();
-                return true;
-            }
-            return false;
-        }
-    }
-    
-    static UdpSocketManager usm;
-    static Peer otherSide;
-    
-    public TransferBlockTest() {
-        // not much to initialize
-        super();
-    }
-
-    /**
-     * 5 consecutive pings for handshaking.
-     * Then repeatedly:
-     * - Read a line from stdin.
-     * - Encode it to a CHK
-     * - Send it to the other node.
-     */
-    public static void main(String[] args) throws NoSuchAlgorithmException, 
CHKEncodeException, IOException {
-        if(args.length < 2) {
-            System.err.println("Syntax: PingTest <myPort> <hisPort>");
-            System.exit(1);
-        }
-        Logger.setupStdoutLogging(Logger.DEBUG, "");
-        int myPort = Integer.parseInt(args[0]);
-        int hisPort = Integer.parseInt(args[1]);
-        Logger.minor(TransferBlockTest.class, "My port: "+myPort+", his port: 
"+hisPort);
-        // Set up a UdpSocketManager
-        usm = new UdpSocketManager(myPort);
-        usm.setDispatcher(new PingingReceivingDispatcher());
-        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
-        int consecutivePings = 0;
-        while(consecutivePings < 5) {
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-            }
-            Logger.normal(TransferBlockTest.class, "Sending ping");
-            usm.send(otherSide, DMT.createPing());
-            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
-            if(m != null) {
-                consecutivePings++;
-                Logger.normal(TransferBlockTest.class, "Got pong: "+m);
-            } else consecutivePings = 0;
-        }
-        Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings");
-        
-        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
-        
-        Random r = new Random();
-        
-        while(true) {
-            // Interface - goes to stdout, not log
-            System.out.println();
-            System.out.println("World's slowest UDP chat client");
-            System.out.println("-------------------------------");
-            System.out.println("Please enter message to send, terminate with . 
on a line by itself.");
-            String message = "";
-            while(true) {
-                String read = reader.readLine();
-                if(read.equals(".")) break;
-                message += read;
-                message += '\n';
-            }
-            Logger.debug(TransferBlockTest.class, "Read: "+message);
-            // Encode to a CHK
-            byte[] temp = message.getBytes();
-
-            ClientCHKBlock block = ClientCHKBlock.encode(temp);
-            ClientCHK chk = block.getClientKey();
-            FreenetURI uri = 
-                chk.getURI();
-            // Interface, arguably
-            System.out.println("URI: "+uri);
-            byte[] header = block.getHeader();
-            byte[] buf = block.getData();
-            // Get a UID
-            long uid = r.nextLong();
-            Logger.minor(TransferBlockTest.class, "UID: "+uid);
-            // Now send it to the other node
-            Message sendKey = DMT.createTestSendCHK(uid, uri.toString(), new 
Buffer(header));
-            usm.send(otherSide, sendKey);
-            // Wait for ack
-            Message m = 
usm.waitFor(MessageFilter.create().setType(DMT.testSendCHKAck));
-            if(m == null) {
-                // Interface?
-                System.err.println("Did not receive ACK");
-                return;
-            }
-            Logger.minor(TransferBlockTest.class, "Got ack: "+m);
-            PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 1024, 
buf);
-            BlockTransmitter bt = new BlockTransmitter(usm, otherSide, uid, 
prb);
-            bt.send();
-            // Definitely interface.
-            System.out.println("Sent.");
-        }
-    }
-}

Copied: trunk/freenet/test/TransferBlockTest.java (from rev 11377, 
trunk/freenet/src/test/TransferBlockTest.java)
===================================================================
--- trunk/freenet/test/TransferBlockTest.java                           (rev 0)
+++ trunk/freenet/test/TransferBlockTest.java   2006-12-13 19:38:15 UTC (rev 
11378)
@@ -0,0 +1,237 @@
+package test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+
+import freenet.io.comm.DMT;
+import freenet.io.comm.Dispatcher;
+import freenet.io.comm.Message;
+import freenet.io.comm.MessageFilter;
+import freenet.io.comm.Peer;
+import freenet.io.comm.RetrievalException;
+import freenet.io.comm.UdpSocketManager;
+import freenet.io.xfer.BlockReceiver;
+import freenet.io.xfer.BlockTransmitter;
+import freenet.io.xfer.PartiallyReceivedBlock;
+import freenet.keys.CHKDecodeException;
+import freenet.keys.CHKEncodeException;
+import freenet.keys.CHKVerifyException;
+import freenet.keys.ClientCHK;
+import freenet.keys.CHKBlock;
+import freenet.keys.ClientCHKBlock;
+import freenet.keys.FreenetURI;
+import freenet.support.Buffer;
+import freenet.support.Logger;
+
+/**
+ * Read from stdin, encode to a new style CHK, send to other node.
+ * When receive it, decode and display.
+ * Hence this is the world's slowest UDP chat client.
+ * Takes two parameters: ourPort and hisPort.
+ * Does a ping handshake first, like TransferSendTest does.
+ * @author amphibian
+ */
+public class TransferBlockTest {
+
+
+
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class Receiver implements Runnable {
+
+        long uid;
+        String uriS;
+        FreenetURI uri;
+        byte[] header;
+        
+        public Receiver(long uid, String uriS, byte[] header) throws 
MalformedURLException {
+            this.uid = uid;
+            this.header = header;
+            this.uriS = uriS;
+            this.uri = new FreenetURI(uriS);
+        }
+
+        public void run() {
+            // First send the ack
+            usm.send(otherSide, DMT.createTestSendCHKAck(uid, uriS));
+            // Receive the data
+            PartiallyReceivedBlock prb;
+            prb = new PartiallyReceivedBlock(32, 1024);
+            BlockReceiver br;
+            br = new BlockReceiver(usm, otherSide, uid, prb);
+            byte[] data;
+            try {
+                data = br.receive();
+            } catch (RetrievalException e1) {
+                Logger.error(this, "Failed to receive", e1);
+                return;
+            }
+            System.err.println("Received "+data.length+" bytes");
+            ClientCHK k;
+            try {
+                k = new ClientCHK(uri);
+            } catch (MalformedURLException e3) {
+                Logger.error(this, "Invalid URL sent by other side", e3);
+                return;
+            }
+            // Now decode it
+            CHKBlock block;
+            try {
+                block = new CHKBlock(data, header, k.getNodeCHK());
+            } catch (CHKVerifyException e) {
+                Logger.error(this, "Couldn't verify", e);
+                return;
+            }
+            long tStart = System.currentTimeMillis();
+            byte[] decoded;
+            try {
+                decoded = block.decode(k);
+            } catch (CHKDecodeException e2) {
+                Logger.error(this, "Couldn't decode sent data", e2);
+                return;
+            }
+            long tEnd = System.currentTimeMillis();
+            Logger.minor(this, "Time taken to decode: "+(tEnd-tStart)+"ms");
+            Logger.minor(this, "Decoded: "+decoded.length+" bytes");
+            Logger.normal(this, "Decoded data:\n"+new String(decoded));
+            System.out.println("Decoded data:\n"+new String(decoded));
+        }
+    }
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class PingingReceivingDispatcher implements Dispatcher {
+        public boolean handleMessage(Message m) {
+            if(m.getSpec() == DMT.ping) {
+                usm.send(m.getSource(), DMT.createPong(m));
+                return true;
+            }
+            if(m.getSpec() == DMT.testSendCHK) {
+                long uid = m.getLong(DMT.UID);
+                String uri = m.getString(DMT.FREENET_URI);
+                Buffer buf = (Buffer)m.getObject(DMT.CHK_HEADER);
+                byte[] header = buf.getData();
+                Logger.minor(this, "Got send request, uid: "+uid+", key: 
"+uri);
+                // Receive the actual data
+                Receiver r;
+                try {
+                    r = new Receiver(uid, uri, header);
+                } catch (MalformedURLException e) {
+                    System.err.println(e.toString());
+                    e.printStackTrace();
+                    return true;
+                }
+                new Thread(r).start();
+                return true;
+            }
+            return false;
+        }
+    }
+    
+    static UdpSocketManager usm;
+    static Peer otherSide;
+    
+    public TransferBlockTest() {
+        // not much to initialize
+        super();
+    }
+
+    /**
+     * 5 consecutive pings for handshaking.
+     * Then repeatedly:
+     * - Read a line from stdin.
+     * - Encode it to a CHK
+     * - Send it to the other node.
+     */
+    public static void main(String[] args) throws NoSuchAlgorithmException, 
CHKEncodeException, IOException {
+        if(args.length < 2) {
+            System.err.println("Syntax: PingTest <myPort> <hisPort>");
+            System.exit(1);
+        }
+        Logger.setupStdoutLogging(Logger.DEBUG, "");
+        int myPort = Integer.parseInt(args[0]);
+        int hisPort = Integer.parseInt(args[1]);
+        Logger.minor(TransferBlockTest.class, "My port: "+myPort+", his port: 
"+hisPort);
+        // Set up a UdpSocketManager
+        usm = new UdpSocketManager(myPort);
+        usm.setDispatcher(new PingingReceivingDispatcher());
+        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
+        int consecutivePings = 0;
+        while(consecutivePings < 5) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+            Logger.normal(TransferBlockTest.class, "Sending ping");
+            usm.send(otherSide, DMT.createPing());
+            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
+            if(m != null) {
+                consecutivePings++;
+                Logger.normal(TransferBlockTest.class, "Got pong: "+m);
+            } else consecutivePings = 0;
+        }
+        Logger.normal(TransferBlockTest.class, "Got "+consecutivePings+" 
consecutive pings");
+        
+        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
+        
+        Random r = new Random();
+        
+        while(true) {
+            // Interface - goes to stdout, not log
+            System.out.println();
+            System.out.println("World's slowest UDP chat client");
+            System.out.println("-------------------------------");
+            System.out.println("Please enter message to send, terminate with . 
on a line by itself.");
+            String message = "";
+            while(true) {
+                String read = reader.readLine();
+                if(read.equals(".")) break;
+                message += read;
+                message += '\n';
+            }
+            Logger.debug(TransferBlockTest.class, "Read: "+message);
+            // Encode to a CHK
+            byte[] temp = message.getBytes();
+
+            ClientCHKBlock block = ClientCHKBlock.encode(temp);
+            ClientCHK chk = block.getClientKey();
+            FreenetURI uri = 
+                chk.getURI();
+            // Interface, arguably
+            System.out.println("URI: "+uri);
+            byte[] header = block.getHeader();
+            byte[] buf = block.getData();
+            // Get a UID
+            long uid = r.nextLong();
+            Logger.minor(TransferBlockTest.class, "UID: "+uid);
+            // Now send it to the other node
+            Message sendKey = DMT.createTestSendCHK(uid, uri.toString(), new 
Buffer(header));
+            usm.send(otherSide, sendKey);
+            // Wait for ack
+            Message m = 
usm.waitFor(MessageFilter.create().setType(DMT.testSendCHKAck));
+            if(m == null) {
+                // Interface?
+                System.err.println("Did not receive ACK");
+                return;
+            }
+            Logger.minor(TransferBlockTest.class, "Got ack: "+m);
+            PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 1024, 
buf);
+            BlockTransmitter bt = new BlockTransmitter(usm, otherSide, uid, 
prb);
+            bt.send();
+            // Definitely interface.
+            System.out.println("Sent.");
+        }
+    }
+}

Deleted: trunk/freenet/test/TransferSendTest.java
===================================================================
--- trunk/freenet/src/test/TransferSendTest.java        2006-12-13 18:27:21 UTC 
(rev 11374)
+++ trunk/freenet/test/TransferSendTest.java    2006-12-13 19:38:15 UTC (rev 
11378)
@@ -1,163 +0,0 @@
-package test;
-
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Random;
-
-import freenet.io.comm.Dispatcher;
-import freenet.io.comm.Message;
-import freenet.io.comm.Peer;
-import freenet.io.comm.RetrievalException;
-import freenet.io.comm.UdpSocketManager;
-import freenet.io.comm.DMT;
-import freenet.io.comm.MessageFilter;
-import freenet.io.xfer.BlockReceiver;
-import freenet.io.xfer.BlockTransmitter;
-import freenet.io.xfer.PartiallyReceivedBlock;
-import freenet.support.HexUtil;
-
-/**
- * Transfer of random data with a SHA-1 checksum.
- * Takes two parameters: ourPort and hisPort.
- * Sends a ping message every second until we get 10, for handshaking.
- * Then sends a random block.
- * Also receives and handles.
- * SHA-1 is printed on both ends for verification.
- * @author amphibian
- */
-public class TransferSendTest {
-
-
-
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class Receiver implements Runnable {
-
-        int uid;
-        
-        public Receiver(int uid) {
-            this.uid = uid;
-        }
-
-        public void run() {
-            // First send the ack
-            usm.send(otherSide, DMT.createTestTransferSendAck(uid));
-            // Receive the data
-            PartiallyReceivedBlock prb;
-            prb = new PartiallyReceivedBlock(32, 1024);
-            BlockReceiver br;
-            br = new BlockReceiver(usm, otherSide, uid, prb);
-            byte[] block;
-            try {
-                block = br.receive();
-            } catch (RetrievalException e1) {
-                System.err.println("Failed to receive: "+e1);
-                e1.printStackTrace();
-                return;
-            }
-            System.err.println("Received "+block.length+" bytes");
-            MessageDigest md;
-            try {
-                md = MessageDigest.getInstance("SHA-1");
-            } catch (NoSuchAlgorithmException e) {
-                throw new Error(e);
-            }
-            byte[] digest = md.digest(block);
-            System.err.println("Block hash: "+HexUtil.bytesToHex(digest));
-        }
-    }
-    /**
-     * @author root
-     *
-     * TODO To change the template for this generated type comment go to
-     * Window - Preferences - Java - Code Generation - Code and Comments
-     */
-    public static class PingingReceivingDispatcher implements Dispatcher {
-        public boolean handleMessage(Message m) {
-            if(m.getSpec() == DMT.ping) {
-                usm.send(m.getSource(), DMT.createPong(m));
-                return true;
-            }
-            if(m.getSpec() == DMT.testTransferSend) {
-                int uid = m.getInt(DMT.UID);
-                System.err.println("Got send request, uid: "+uid);
-                // Receive the actual data
-                Receiver r = new Receiver(uid);
-                new Thread(r).start();
-                return true;
-            }
-            return false;
-        }
-    }
-    
-    static UdpSocketManager usm;
-    static Peer otherSide;
-    
-    public TransferSendTest() {
-        // not much to initialize
-        super();
-    }
-
-    /**
-     * 10 consecutive pings for handshaking.
-     * Then create a random 32kB chunk of data.
-     * Then send it.
-     */
-    public static void main(String[] args) throws SocketException, 
UnknownHostException, NoSuchAlgorithmException {
-        if(args.length < 2) {
-            System.err.println("Syntax: PingTest <myPort> <hisPort>");
-            System.exit(1);
-        }
-        int myPort = Integer.parseInt(args[0]);
-        int hisPort = Integer.parseInt(args[1]);
-        System.out.println("My port: "+myPort+", his port: "+hisPort);
-        // Set up a UdpSocketManager
-        usm = new UdpSocketManager(myPort);
-        usm.setDispatcher(new PingingReceivingDispatcher());
-        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
-        int consecutivePings = 0;
-        while(consecutivePings < 10) {
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-            }
-            System.err.println("Sending ping");
-            usm.send(otherSide, DMT.createPing());
-            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
-            if(m != null) {
-                consecutivePings++;
-                System.err.println("Got pong: "+m);
-            } else consecutivePings = 0;
-        }
-        System.err.println("Got "+consecutivePings+" consecutive pings");
-        byte[] buf = new byte[32768];
-        Random r = new Random();
-        r.nextBytes(buf);
-        MessageDigest md;
-        md = MessageDigest.getInstance("SHA-1");
-        byte[] digest = md.digest(buf);
-        String readableHash = HexUtil.bytesToHex(digest);
-        System.err.println("Created block, size "+buf.length+", hash: 
"+readableHash);
-        // Send transfer start message
-        int uid = r.nextInt();
-        System.err.println("UID: "+uid);
-        Message start = DMT.createTestTransferSend(uid);
-        usm.send(otherSide, start);
-        // Wait for the ack
-        Message m = 
usm.waitFor(MessageFilter.create().setType(DMT.testTransferSendAck));
-        if(m == null) return;
-        System.err.println("Got "+m);
-        // Now send it
-        PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 1024, buf);
-        BlockTransmitter bt;
-        bt = new BlockTransmitter(usm, otherSide, uid, prb);
-        bt.send();
-    }
-}

Copied: trunk/freenet/test/TransferSendTest.java (from rev 11377, 
trunk/freenet/src/test/TransferSendTest.java)
===================================================================
--- trunk/freenet/test/TransferSendTest.java                            (rev 0)
+++ trunk/freenet/test/TransferSendTest.java    2006-12-13 19:38:15 UTC (rev 
11378)
@@ -0,0 +1,163 @@
+package test;
+
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+
+import freenet.io.comm.Dispatcher;
+import freenet.io.comm.Message;
+import freenet.io.comm.Peer;
+import freenet.io.comm.RetrievalException;
+import freenet.io.comm.UdpSocketManager;
+import freenet.io.comm.DMT;
+import freenet.io.comm.MessageFilter;
+import freenet.io.xfer.BlockReceiver;
+import freenet.io.xfer.BlockTransmitter;
+import freenet.io.xfer.PartiallyReceivedBlock;
+import freenet.support.HexUtil;
+
+/**
+ * Transfer of random data with a SHA-1 checksum.
+ * Takes two parameters: ourPort and hisPort.
+ * Sends a ping message every second until we get 10, for handshaking.
+ * Then sends a random block.
+ * Also receives and handles.
+ * SHA-1 is printed on both ends for verification.
+ * @author amphibian
+ */
+public class TransferSendTest {
+
+
+
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class Receiver implements Runnable {
+
+        int uid;
+        
+        public Receiver(int uid) {
+            this.uid = uid;
+        }
+
+        public void run() {
+            // First send the ack
+            usm.send(otherSide, DMT.createTestTransferSendAck(uid));
+            // Receive the data
+            PartiallyReceivedBlock prb;
+            prb = new PartiallyReceivedBlock(32, 1024);
+            BlockReceiver br;
+            br = new BlockReceiver(usm, otherSide, uid, prb);
+            byte[] block;
+            try {
+                block = br.receive();
+            } catch (RetrievalException e1) {
+                System.err.println("Failed to receive: "+e1);
+                e1.printStackTrace();
+                return;
+            }
+            System.err.println("Received "+block.length+" bytes");
+            MessageDigest md;
+            try {
+                md = MessageDigest.getInstance("SHA-1");
+            } catch (NoSuchAlgorithmException e) {
+                throw new Error(e);
+            }
+            byte[] digest = md.digest(block);
+            System.err.println("Block hash: "+HexUtil.bytesToHex(digest));
+        }
+    }
+    /**
+     * @author root
+     *
+     * TODO To change the template for this generated type comment go to
+     * Window - Preferences - Java - Code Generation - Code and Comments
+     */
+    public static class PingingReceivingDispatcher implements Dispatcher {
+        public boolean handleMessage(Message m) {
+            if(m.getSpec() == DMT.ping) {
+                usm.send(m.getSource(), DMT.createPong(m));
+                return true;
+            }
+            if(m.getSpec() == DMT.testTransferSend) {
+                int uid = m.getInt(DMT.UID);
+                System.err.println("Got send request, uid: "+uid);
+                // Receive the actual data
+                Receiver r = new Receiver(uid);
+                new Thread(r).start();
+                return true;
+            }
+            return false;
+        }
+    }
+    
+    static UdpSocketManager usm;
+    static Peer otherSide;
+    
+    public TransferSendTest() {
+        // not much to initialize
+        super();
+    }
+
+    /**
+     * 10 consecutive pings for handshaking.
+     * Then create a random 32kB chunk of data.
+     * Then send it.
+     */
+    public static void main(String[] args) throws SocketException, 
UnknownHostException, NoSuchAlgorithmException {
+        if(args.length < 2) {
+            System.err.println("Syntax: PingTest <myPort> <hisPort>");
+            System.exit(1);
+        }
+        int myPort = Integer.parseInt(args[0]);
+        int hisPort = Integer.parseInt(args[1]);
+        System.out.println("My port: "+myPort+", his port: "+hisPort);
+        // Set up a UdpSocketManager
+        usm = new UdpSocketManager(myPort);
+        usm.setDispatcher(new PingingReceivingDispatcher());
+        otherSide = new Peer(InetAddress.getByName("127.0.0.1"), hisPort);
+        int consecutivePings = 0;
+        while(consecutivePings < 10) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+            System.err.println("Sending ping");
+            usm.send(otherSide, DMT.createPing());
+            Message m = 
usm.waitFor(MessageFilter.create().setTimeout(1000).setType(DMT.pong).setSource(otherSide));
+            if(m != null) {
+                consecutivePings++;
+                System.err.println("Got pong: "+m);
+            } else consecutivePings = 0;
+        }
+        System.err.println("Got "+consecutivePings+" consecutive pings");
+        byte[] buf = new byte[32768];
+        Random r = new Random();
+        r.nextBytes(buf);
+        MessageDigest md;
+        md = MessageDigest.getInstance("SHA-1");
+        byte[] digest = md.digest(buf);
+        String readableHash = HexUtil.bytesToHex(digest);
+        System.err.println("Created block, size "+buf.length+", hash: 
"+readableHash);
+        // Send transfer start message
+        int uid = r.nextInt();
+        System.err.println("UID: "+uid);
+        Message start = DMT.createTestTransferSend(uid);
+        usm.send(otherSide, start);
+        // Wait for the ack
+        Message m = 
usm.waitFor(MessageFilter.create().setType(DMT.testTransferSendAck));
+        if(m == null) return;
+        System.err.println("Got "+m);
+        // Now send it
+        PartiallyReceivedBlock prb = new PartiallyReceivedBlock(32, 1024, buf);
+        BlockTransmitter bt;
+        bt = new BlockTransmitter(usm, otherSide, uid, prb);
+        bt.send();
+    }
+}

Added: trunk/freenet/test/freenet/io/AddressIdentifierTest.java
===================================================================
--- trunk/freenet/test/freenet/io/AddressIdentifierTest.java                    
        (rev 0)
+++ trunk/freenet/test/freenet/io/AddressIdentifierTest.java    2006-12-13 
19:38:15 UTC (rev 11378)
@@ -0,0 +1,54 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.io;
+
+import junit.framework.TestCase;
+import freenet.io.AddressIdentifier;
+import freenet.io.AddressIdentifier.AddressType;
+
+/**
+ * Test case for the {@link freenet.io.AddressIdentifier} class.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: AddressIdentifierTest.java 10490 2006-09-20 00:07:46Z toad $
+ */
+public class AddressIdentifierTest extends TestCase {
+
+       public void test() {
+               /* test real IPv4 addresses */
+               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("0.0.0.0"));
+               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("127.0.0.1"));
+               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("255.255.255.255"));
+               /* in case you didn't know: 183.24.17 = 183.24.0.17 */
+               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("183.24.17"));
+               /* and 127.1 = 127.0.0.1 */
+               assertEquals(AddressType.IPv4, 
AddressIdentifier.getAddressType("127.1"));
+
+               /* test fake IPv4 addresses */
+               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("192.168.370.12"));
+               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("127.0.0.0.1"));
+
+               /* test real unabridged IPv6 addresses */
+               assertEquals(AddressType.IPv6, 
AddressIdentifier.getAddressType("0:0:0:0:0:0:0:1"));
+               assertEquals(AddressType.IPv6, 
AddressIdentifier.getAddressType("fe80:0:0:0:203:dff:fe22:420f"));
+
+               /* test fake IPv6 addresses */
+               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("1:2:3:4:5:6:7:8:9"));
+               assertEquals(AddressType.OTHER, 
AddressIdentifier.getAddressType("12345:6:7:8:9"));
+       }
+
+}

Added: trunk/freenet/test/freenet/io/Inet4AddressMatcherTest.java
===================================================================
--- trunk/freenet/test/freenet/io/Inet4AddressMatcherTest.java                  
        (rev 0)
+++ trunk/freenet/test/freenet/io/Inet4AddressMatcherTest.java  2006-12-13 
19:38:15 UTC (rev 11378)
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.io;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+import freenet.io.Inet4AddressMatcher;
+
+import junit.framework.TestCase;
+
+/**
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Inet4AddressMatcherTest.java 10490 2006-09-20 00:07:46Z toad $
+ */
+public class Inet4AddressMatcherTest extends TestCase {
+
+       public void test() throws Exception {
+               Inet4AddressMatcher matcher = new 
Inet4AddressMatcher("192.168.1.2");
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.2")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("0.0.0.0")));
+               
+               matcher = new Inet4AddressMatcher("192.168.1.2/8");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.2")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.81.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.255.255.255")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("172.16.1.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("0.0.0.0")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.0.0.0")));
+
+               /* some fancy matching */
+               matcher = new Inet4AddressMatcher("192.168.1.1/255.0.255.0");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.1.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.2.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               
+               matcher = new Inet4AddressMatcher("127.0.0.1/8");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.23.42.64")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.0")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.255.255.255")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("28.0.0.1")));
+
+               matcher = new Inet4AddressMatcher("0.0.0.0/0");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("172.16.42.23")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("10.0.0.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("224.0.0.1")));
+       }
+
+}

Added: trunk/freenet/test/freenet/io/Inet6AddressMatcherTest.java
===================================================================
--- trunk/freenet/test/freenet/io/Inet6AddressMatcherTest.java                  
        (rev 0)
+++ trunk/freenet/test/freenet/io/Inet6AddressMatcherTest.java  2006-12-13 
19:38:15 UTC (rev 11378)
@@ -0,0 +1,65 @@
+/*
+ * freenet0.7 - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.io;
+
+import java.net.InetAddress;
+
+import junit.framework.TestCase;
+import freenet.io.Inet6AddressMatcher;
+
+/**
+ * Test case for the {@link freenet.io.Inet6AddressMatcher} class. Contains 
some
+ * very basic tests. Feel free to add more complicated tests!
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Inet6AddressMatcherTest.java 10490 2006-09-20 00:07:46Z toad $
+ */
+public class Inet6AddressMatcherTest extends TestCase {
+
+       public void test() throws Exception {
+               Inet6AddressMatcher matcher = new 
Inet6AddressMatcher("0:0:0:0:0:0:0:0/0");
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
+
+               matcher = new 
Inet6AddressMatcher("fe80:0:0:0:203:dff:fe22:420f/64");
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0203:0dff:fe22:420f")));
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0204:0dff:fe22:420f")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe81:0:0:0:0203:0dff:fe22:420f")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("0:0:0:0:0:0:0:1")));
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0:0:0:1")));
+
+               matcher = new 
Inet6AddressMatcher("fe80:0:0:0:203:dff:fe22:420f/ffff:ffff:ffff:ffff:0:0:0:0");
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0203:0dff:fe22:420f")));
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0204:0dff:fe22:420f")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe81:0:0:0:0203:0dff:fe22:420f")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("0:0:0:0:0:0:0:1")));
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0:0:0:1")));
+
+               matcher = new 
Inet6AddressMatcher("fe80:0:0:0:203:dff:fe22:420f/128");
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:203:dff:fe22:420f")));
+               assertEquals(true, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0203:0dff:fe22:420f")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0204:0dff:fe22:420f")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe81:0:0:0:0203:0dff:fe22:420f")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("0:0:0:0:0:0:0:1")));
+               assertEquals(false, 
matcher.matches(InetAddress.getByName("fe80:0:0:0:0:0:0:1")));
+       }
+
+}


Reply via email to