From a4c0d3d6d878da55435cb9d9cc8cff6199644199 Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Sun, 19 Oct 2003 15:08:35 +0000 Subject: Support random path creation --- src/Main.java | 3 +- .../fancydress/crypto/CryptoPrimitives.java | 19 ++ .../noreply/fancydress/directory/Directory.java | 230 +++++++++++-- .../fancydress/directory/IncomingMMTPSection.java | 14 +- src/org/noreply/fancydress/directory/Server.java | 64 +++- .../fancydress/directory/ServerDescriptor.java | 72 ++-- src/org/noreply/fancydress/misc/Util.java | 26 ++ .../status/Mix3BadDirectorySignatureException.java | 3 +- src/org/noreply/fancydress/type3/HalfPath.java | 6 + src/org/noreply/fancydress/type3/Hop.java | 39 ++- src/org/noreply/fancydress/type3/Message.java | 4 +- src/org/noreply/fancydress/type3/Path.java | 4 + src/org/noreply/fancydress/type3/PathSpec.java | 366 ++++++++++++++++++--- src/org/noreply/fancydress/type3/Payload.java | 5 + src/org/noreply/fancydress/type3/mmtp/MMTP.java | 6 +- .../fancydress/type3/routing/RoutingForward.java | 13 + .../fancydress/type3/routing/RoutingHOST.java | 16 + .../fancydress/type3/routing/RoutingIP4.java | 16 + 18 files changed, 773 insertions(+), 133 deletions(-) diff --git a/src/Main.java b/src/Main.java index da89a50..58ef46b 100644 --- a/src/Main.java +++ b/src/Main.java @@ -15,8 +15,7 @@ public class Main { DirectoryParser parser = new DirectoryParser(new DirectoryLexer(new FileReader(argv[0]))); DirectoryMessage dm = (DirectoryMessage)parser.parse().value; Directory dir = new Directory(dm, false); - PathSpec path = new PathSpec(dir,"test1 : tonga", false); - + PathSpec path = new PathSpec(dir,"*4,~1", false); RoutingSMTP destination = new RoutingSMTP("peter@palfrader.org"); String body = "FROM:Peter\n" + "SUBJECT:test fancydress\n" + diff --git a/src/org/noreply/fancydress/crypto/CryptoPrimitives.java b/src/org/noreply/fancydress/crypto/CryptoPrimitives.java index 820dbcb..d9b9884 100644 --- a/src/org/noreply/fancydress/crypto/CryptoPrimitives.java +++ b/src/org/noreply/fancydress/crypto/CryptoPrimitives.java @@ -65,6 +65,25 @@ public class CryptoPrimitives { secureRandom.nextBytes(result); return(result); } + /** + * Get a random value from the normal distrubution with mean u and standard deviation s + * + * @param u mean or the normal distribution + * @param s standard deviation of the normal distribution + * @return a random value from given the normal distrubution + */ + public static double normal(double m, double s) { + return secureRandom.nextGaussian() * s + m; + } + /** + * Return a uniformly distributed int value between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be positive. + * @return a pseudorandom, uniformly distributed int value between 0 (inclusive) and n (exclusive). + */ + public static int randInt(int n) { + return secureRandom.nextInt(n); + } /** * Get n octets of zeroes. * diff --git a/src/org/noreply/fancydress/directory/Directory.java b/src/org/noreply/fancydress/directory/Directory.java index f2eda8c..ff0cfdf 100644 --- a/src/org/noreply/fancydress/directory/Directory.java +++ b/src/org/noreply/fancydress/directory/Directory.java @@ -24,6 +24,12 @@ import java.util.*; * @see Server */ public class Directory { + /** + * directory version we understand. + */ + + private static final String DIRECTORY_VERSION = "0.2"; + /** * Hash holding all Servers. * @@ -37,35 +43,27 @@ public class Directory { private Hashtable byName; /** - * Possibly add a new server descriptor to the directory. + * Useable servers. * - * This method adds a server desccriptor to the directory if it - * - conforms to the syntax specified. - * - the server is not yet known or it's identity key matches the key of the already known ServerDescriptor. + * A server is useable if it understands PacketVersions that we understand + * and has a serverdescriptor that is useable right now. + */ + private Server[] useableServers; + + /** + * Recommended servers. + */ + private Server[] recommendedServers; + + /* + * matrix of friends. * - * @param server a DirectoryMessage consisting of one of more sections. At 'Server' section needs to be present. - * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored. - * @throws Mix3BadServerSignatureException if the server descriptor's signature is invalid. + * (a, b) are friends, if a can send messages to b. */ - private void addServerDescriptor(DirectoryMessage server) throws Mix3BadServerFormatException, Mix3BadServerSignatureException { - try { - ServerDescriptor sd = new ServerDescriptor(server); - String key = sd.getNickname().toLowerCase(); - if (byName.containsKey(key)) { - Server s = (Server) byName.get(key); - try { - s.addDescriptor(sd); - } catch (Mix3BadServerFormatException e) { - System.err.println("Ignoring Descriptor with different identity for "+key); - } - } else { - Server s = new Server(sd); - byName.put(key, s); - } - } catch (Mix3BadServerUnrecognizedVersionException e) { - System.err.println("Ignoring unregonized version"); - } - } + /* + private boolean[][] friends; + */ + /** * Create a directory from an entire DirectoryMessage. @@ -82,11 +80,87 @@ public class Directory { */ public Directory(DirectoryMessage m, boolean checkDirectorySignature) throws Mix3BadDirectorySignatureException, + Mix3BadDirectoryFormatException, Mix3BadServerFormatException, Mix3BadServerSignatureException { byName = new Hashtable(); + + parseDirectory(m, checkDirectorySignature); + + + Collection all = byName.values(); + ArrayList useable = new ArrayList(); + for (Iterator i = all.iterator(); i.hasNext(); ) { + Server s = (Server) i.next(); + if (s.isUseable()) + useable.add(s); + } + useableServers = (Server[]) useable.toArray( new Server[useable.size()] ); + + + ArrayList recommended = new ArrayList(); + for (int i=0; i 65535) throw new Mix3BadServerFormatException("Port is not in TCP/IP port range in " + name + " section"); - protocols = entryProtocols.getValue(); + protocols = Util.tokenize(entryProtocols.getValue(), ','); } public InetAddress getIP() { @@ -110,4 +115,7 @@ public class IncomingMMTPSection { public int getPort() { return port; } + public String[] getProtocols() { + return protocols; + } } diff --git a/src/org/noreply/fancydress/directory/Server.java b/src/org/noreply/fancydress/directory/Server.java index c4052d9..45ca720 100644 --- a/src/org/noreply/fancydress/directory/Server.java +++ b/src/org/noreply/fancydress/directory/Server.java @@ -34,6 +34,11 @@ public class Server { */ ArrayList descriptors; + /** + * whether or not this node is recommended. + */ + boolean recommended; + /** * Construct a Server from a given ServerDescriptor. * @@ -46,6 +51,51 @@ public class Server { descriptors = new ArrayList(); descriptors.add(descriptor); + recommended = false; + } + + /** + * Set this node recommended. + * + * This is done by the Directory according to the recommended-servers list. + * + * @see Directory + */ + public void setRecommended() { + recommended = true; + } + + /** + * Get whether or not this node recommended. + * + * @return whether or not this node is recommended + */ + public boolean isRecommended() { + return recommended; + } + + /** + * Get whether or not this node is useable. + * + * A server is useable if it understands PacketVersions that we speak, + * has a serverdescriptor that is useable right now, and this SD has + * an Incoming/MMTP section. + * + * @return whether or not this node is useable + */ + public boolean isUseable() { + ServerDescriptor sd; + try { + sd = getDescriptor(); + } catch (Mix3NoServerDescriptorException e) { + return false; + } + String[] pv = sd.getPacketVersions(); /* getPacketVersions only returns packet versions that we understand */ + if (pv.length == 0) + return false; + if (sd.getIncomingMMTPSection() == null) + return false; + return true; } /** @@ -76,12 +126,22 @@ public class Server { return keyid; } + /** + * Get the nickname of this server. + * + * @return nickname + */ + public String getNickname() { + return nickname; + } + /** * get the the currently valid server descriptor. * * @return current server descriptor + * @throws Mix3NoServerDescriptorException if there is no valid server descriptor */ - public ServerDescriptor getDescriptor() throws Mix3Exception { + public ServerDescriptor getDescriptor() throws Mix3NoServerDescriptorException { ServerDescriptor result = null; Date now = new Date(); @@ -93,7 +153,7 @@ public class Server { result = desc; } if (result == null) - throw new Mix3Exception("No valid server descriptor found."); + throw new Mix3NoServerDescriptorException("No valid server descriptor found."); return result; } } diff --git a/src/org/noreply/fancydress/directory/ServerDescriptor.java b/src/org/noreply/fancydress/directory/ServerDescriptor.java index 020d31b..4c0cba1 100644 --- a/src/org/noreply/fancydress/directory/ServerDescriptor.java +++ b/src/org/noreply/fancydress/directory/ServerDescriptor.java @@ -23,6 +23,11 @@ import java.text.ParseException; * @see Server */ public class ServerDescriptor { + /* +ปญญญญญญญ * descriptor version we understand. +ปญญญญญญญ */ + private static final String DESCRIPTOR_VERSION = "0.2"; + /* Required */ private String descriptorVersion; private String nickname; @@ -46,7 +51,7 @@ public class ServerDescriptor { private String whyInsecure; private IncomingMMTPSection incomingMMTPSection; - private Object outgoingMMTPSection; + private OutgoingMMTPSection outgoingMMTPSection; private DeliveryMBOXSection deliveryMBOXSection; private DeliverySMTPSection deliverySMTPSection; private Object deliveryFragmentedSection; @@ -82,6 +87,11 @@ public class ServerDescriptor { incomingMMTPSection = section == null ? null : new IncomingMMTPSection(section); } catch (Mix3BadServerFormatException e) { System.err.println(e); }; + section = m.getSection("Outgoing/MMTP"); + try { + outgoingMMTPSection = section == null ? null : new OutgoingMMTPSection(section); + } catch (Mix3BadServerFormatException e) { System.err.println(e); }; + section = m.getSection("Delivery/MBOX"); try { deliveryMBOXSection = section == null ? null : new DeliveryMBOXSection(section); @@ -120,46 +130,18 @@ public class ServerDescriptor { * Whitespace is trimmed off each Packet-Version. * * @param s the comma separated list of Packet-Versions - * @param onlySupported only include Packet-Versions that we can handle * @return array of Packet-Versions. */ - public static String[] parsePacketVersions(String s, boolean onlySupported) { + public static String[] parsePacketVersions(String s) { ArrayList versions = new ArrayList(); int indexFrom = 0; int indexOf; - while ((indexOf = s.indexOf(',', indexFrom)) != -1) { - String v = s.substring(indexFrom, indexOf).trim(); - if (!v.equals("") && (Packet.isPacketVersionSupported(v) || !onlySupported )) - versions.add( v ); - indexFrom = indexOf + 1; - } - String v = s.substring(indexFrom).trim(); - if (!v.equals("") && (Packet.isPacketVersionSupported(v) || !onlySupported )) - versions.add( v ); - - String[] result = new String[versions.size()]; - for (int i=0; i= 0) ? + s.substring(indexFrom, indexOf).trim() : + s.substring(indexFrom).trim(); + list.add( v ); + indexFrom = indexOf + 1; + } while (indexOf >= 0); + + return (String[]) list.toArray(new String[list.size()]); + } } diff --git a/src/org/noreply/fancydress/status/Mix3BadDirectorySignatureException.java b/src/org/noreply/fancydress/status/Mix3BadDirectorySignatureException.java index 2260934..5bd3e5a 100644 --- a/src/org/noreply/fancydress/status/Mix3BadDirectorySignatureException.java +++ b/src/org/noreply/fancydress/status/Mix3BadDirectorySignatureException.java @@ -2,8 +2,7 @@ package org.noreply.fancydress.status; /** - * The operation failed because the directory was not correctly signed, - * or no signature was found. + * The operation failed because the directory was not correctly signed. */ public class Mix3BadDirectorySignatureException extends Mix3BadSignatureException { public Mix3BadDirectorySignatureException(String s) { diff --git a/src/org/noreply/fancydress/type3/HalfPath.java b/src/org/noreply/fancydress/type3/HalfPath.java index 73dfb84..fdde951 100644 --- a/src/org/noreply/fancydress/type3/HalfPath.java +++ b/src/org/noreply/fancydress/type3/HalfPath.java @@ -9,5 +9,11 @@ public class HalfPath { public Hop[] getHops() { return hops; } + public String asString() { + String result = null; + for (int i=0; i 1) + throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: illegal path component '"+c+"'"); + type = TYPE_RANDOM; + numRandoms = 1; + break; + case ':' : + if (c.length() > 1) + throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: illegal path component '"+c+"'"); + type = TYPE_CROSSOVER; + break; + default : + Server server = dir.getServer(c); + if (server == null) + throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: Nickname '"+c+"' not found"); + if (!server.isUseable()) + throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: Nickname '"+c+"' is not useable"); + byNickname = server; + type = TYPE_NICKNAME; + break; + } } - String v = path.substring(indexFrom).trim(); - if (v.equals("")) - throw new Mix3Exception("Invalid path."); - nicks.add( v ); - String[] result = new String[nicks.size()]; - for (int i=0; i= 0) + throw new Mix3BadArgumentsIllegalPathSpecException("Path is not a valid path: crossover point specified in single leg path."); + } else { + /* full paths may have up to one specified crossover point */ + int crossover = pathSpec.indexOf(':'); + if (crossover >= 0) + if (pathSpec.indexOf(':', crossover+1) >= 0) + throw new Mix3BadArgumentsIllegalPathSpecException("Path is not a valid path: more than one crossover points specified."); + } + + this.pathComponents = parsePath(dir, pathSpec); + } + + private class ServerWithCrossover { + public Server[] servers; + public int crossoverPoint; + + public Server getLastServer() { + return (servers[servers.length - 1]); + } + + public void setLastServer(Server s) { + servers[servers.length - 1] = s; + } + + public Server getSecondToLastServer() { + return (servers[servers.length - 2]); + } + + private void fillInRandoms() throws Mix3PathProblemException { + Server[] recommended = dir.getRecommendedServers(); + for (int i=servers.length-1; i>=0 ; i--) { + if (servers[i] != null) + continue; + ArrayList s = new ArrayList(); + for (int r=0; rpayload. * - * @param dir a directory - * @return path + * We build as many paths as payload.numPackets() requires. + * + * Also we filter acceptable exit nodes according to the payload's + * constraints. + * + * @param payload the payload + * @return paths constructed from the PathSpec */ - public Path getPath() throws Mix3Exception { - return singlePath; + public Path[] getPath(Payload payload) throws Mix3PathProblemException { + if (singleLeg) + throw new IllegalArgumentException("getPath() may not be called for single leg path specs."); + + + ServerWithCrossover[] paths = new ServerWithCrossover[payload.numPackets()]; + for (int i=0; i