summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Palfrader <peter@palfrader.org>2003-10-19 15:08:35 +0000
committerPeter Palfrader <peter@palfrader.org>2003-10-19 15:08:35 +0000
commita4c0d3d6d878da55435cb9d9cc8cff6199644199 (patch)
treee066aabfb7a143cd39c3740b4aedd701df5ac758 /src
parent46a03a3ea3c26a65e4428bc9de036a01487aeda3 (diff)
Support random path creation
Diffstat (limited to 'src')
-rw-r--r--src/Main.java3
-rw-r--r--src/org/noreply/fancydress/crypto/CryptoPrimitives.java19
-rw-r--r--src/org/noreply/fancydress/directory/Directory.java230
-rw-r--r--src/org/noreply/fancydress/directory/IncomingMMTPSection.java14
-rw-r--r--src/org/noreply/fancydress/directory/Server.java64
-rw-r--r--src/org/noreply/fancydress/directory/ServerDescriptor.java72
-rw-r--r--src/org/noreply/fancydress/misc/Util.java26
-rw-r--r--src/org/noreply/fancydress/status/Mix3BadDirectorySignatureException.java3
-rw-r--r--src/org/noreply/fancydress/type3/HalfPath.java6
-rw-r--r--src/org/noreply/fancydress/type3/Hop.java39
-rw-r--r--src/org/noreply/fancydress/type3/Message.java4
-rw-r--r--src/org/noreply/fancydress/type3/Path.java4
-rw-r--r--src/org/noreply/fancydress/type3/PathSpec.java366
-rw-r--r--src/org/noreply/fancydress/type3/Payload.java5
-rw-r--r--src/org/noreply/fancydress/type3/mmtp/MMTP.java6
-rw-r--r--src/org/noreply/fancydress/type3/routing/RoutingForward.java13
-rw-r--r--src/org/noreply/fancydress/type3/routing/RoutingHOST.java16
-rw-r--r--src/org/noreply/fancydress/type3/routing/RoutingIP4.java16
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
@@ -66,6 +66,25 @@ public class CryptoPrimitives {
return(result);
}
/**
+ * Get a random value from the normal distrubution with mean <code>u</code> and standard deviation <code>s</code>
+ *
+ * @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 <code>n</code> octets of zeroes.
*
* @param n number of octets
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
@@ -25,6 +25,12 @@ import java.util.*;
*/
public class Directory {
/**
+ * directory version we understand.
+ */
+
+ private static final String DIRECTORY_VERSION = "0.2";
+
+ /**
* Hash holding all Servers.
*
* This hash holds all Servers. Since nickname are to be treaded case
@@ -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<useableServers.length; i++)
+ if (useableServers[i].isRecommended())
+ recommended.add(useableServers[i]);
+ recommendedServers = (Server[]) recommended.toArray( new Server[recommended.size()] );
+ }
+
+
+
+ /**
+ * Possibly add a new server descriptor to the directory.
+ *
+ * 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.
+ *
+ * @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.
+ */
+ private void addServerDescriptor(DirectoryMessage server) throws Mix3BadServerFormatException, Mix3BadServerSignatureException {
+ ServerDescriptor sd;
+ try {
+ sd = new ServerDescriptor(server);
+ } catch (Mix3BadServerUnrecognizedVersionException e) {
+ System.err.println("Ignoring unregonized version");
+ return;
+ }
+ 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);
+ }
+ }
+
+
+ private void parseDirectory(DirectoryMessage m, boolean checkDirectorySignature) throws
+ Mix3BadDirectorySignatureException,
+ Mix3BadDirectoryFormatException,
+ Mix3BadServerFormatException,
+ Mix3BadServerSignatureException
+ {
+ DirectorySection directorySection = m.getSection("Directory");
+ if (directorySection == null)
+ throw new Mix3BadDirectoryFormatException("No Directory section found.");
+
+ DirectoryEntry versionEntry = directorySection.getEntry("Version");
+ if (versionEntry == null)
+ throw new Mix3BadDirectoryFormatException("No Version in Directory section found.");
+ if (! versionEntry.getValue().equals(DIRECTORY_VERSION))
+ throw new Mix3BadDirectoryFormatException("Directory Version "+versionEntry+" not recognized.");
+
+ /* FIXME: check validity (date range) */
+
if (checkDirectorySignature)
checkSignature(m);
DirectoryMessage server = null;
@@ -102,27 +176,38 @@ public class Directory {
}
if (server != null)
addServerDescriptor(server);
+
+ DirectoryEntry recommendedServersEntry = directorySection.getEntry("Recommended-Servers");
+ if (recommendedServersEntry == null)
+ throw new Mix3BadDirectorySignatureException("No Recommended-Servers in Directory section found.");
+ String[] recommendedServers = Util.tokenize( recommendedServersEntry.getValue(), ',');
+ for (int i=0; i<recommendedServers.length; i++) {
+ Server s = getServer(recommendedServers[i]);
+ if (s == null)
+ throw new Mix3BadDirectoryFormatException("Unkown nickname '"+recommendedServers[i]+"'in Recommended-Servers");
+ s.setRecommended();
+ }
}
/* FIXME: known directory servers should be passed as arguments */
/**
* Check the signature of a type III directory.
*/
- private void checkSignature(DirectoryMessage m) throws Mix3BadDirectorySignatureException {
+ private void checkSignature(DirectoryMessage m) throws Mix3BadDirectorySignatureException, Mix3BadDirectoryFormatException {
/* FIXME: handle more than one signature block,
*/
DirectorySection signatureSection = m.getSection("Signature");
if (signatureSection == null)
- throw new Mix3BadDirectorySignatureException("No Signature section found.");
+ throw new Mix3BadDirectoryFormatException("No Signature section found.");
DirectoryEntry signatureEntry = signatureSection.getEntry("DirectorySignature");
if (signatureEntry == null)
- throw new Mix3BadDirectorySignatureException("No DirectorySignature in Signature section found.");
+ throw new Mix3BadDirectoryFormatException("No DirectorySignature in Signature section found.");
DirectoryEntry identityEntry = signatureSection.getEntry("DirectoryIdentity");
if (identityEntry == null)
- throw new Mix3BadDirectorySignatureException("No DirectoryIdentity in Signature section found.");
+ throw new Mix3BadDirectoryFormatException("No DirectoryIdentity in Signature section found.");
byte[] signature = Base64.decode(signatureEntry.getValue());
byte[] identity = Base64.decode(identityEntry.getValue());
@@ -131,7 +216,6 @@ public class Directory {
cleanedDirectory.blindValue("Signature","DirectoryDigest");
cleanedDirectory.blindValue("Signature","DirectorySignature");
- /* FIXME: what if identity is no valid key? */
RSAPublicKey identityKey = new RSAPublicKey(identity);
boolean verifies;
try {
@@ -145,6 +229,9 @@ public class Directory {
/**
* Get a server by nickname.
+ *
+ * @param name nickname of the requested server
+ * @return server specified by the nickname or null if no such server exists
*/
public Server getServer(String name) {
String key = name.toLowerCase();
@@ -152,4 +239,85 @@ public class Directory {
return (Server) byName.get(key);
return null;
}
+
+ /*
+ * Get current server descriptor of useable servers.
+ *
+ * A server is useable if it understands PacketVersions that we understand
+ * and has a serverdescriptor that is useable right now.
+ *
+ * @return server descriptor of useable servers
+ */
+ /*
+ private Server[] getUseableServers() {
+ return useableServers;
+ }
+ */
+
+ /**
+ * Get server descriptor of all recommended servers that are useable.
+ *
+ * @return server descriptor recommended servers
+ * @see #getUseableServers
+ */
+ public Server[] getRecommendedServers() {
+ return recommendedServers;
+ }
+
+ /**
+ * Check if server a can talk to server b.
+ *
+ * A server can talk to another one if they have MMTP/Outgoing and
+ * MMTP/Incoming sections respectively and speak a common MMTP version.
+ *
+ * FIXME: check Allow/Deny ACLs
+ *
+ * @param a server a
+ * @param b server b
+ * @return whether a can send messages to b
+ */
+ public boolean areFriends(Server a, Server b) {
+ ServerDescriptor aa,bb;
+
+ try {
+ aa = a.getDescriptor();
+ } catch (Mix3NoServerDescriptorException e) {
+ throw new Error(a.getNickname()+" should have a valid ServerDescriptor.", e);
+ }
+ try {
+ bb = b.getDescriptor();
+ } catch (Mix3NoServerDescriptorException e) {
+ throw new Error(b.getNickname()+" should have a valid ServerDescriptor.", e);
+ }
+
+ OutgoingMMTPSection out = aa.getOutgoingMMTPSection();
+ IncomingMMTPSection in = bb.getIncomingMMTPSection();
+
+ if (out == null || in == null)
+ return false;
+ String[] inP = in.getProtocols();
+ String[] outP = out.getProtocols();
+ for (int i=0; i<inP.length; i++)
+ for (int o=0; o<outP.length; o++)
+ if (inP[i].equals(outP[o]))
+ return true;
+ return false;
+ }
+
+ /*
+ * Build a matrix of friends.
+ *
+ * (a, b) are friends, if a can send messages to b.
+ */
+ /*
+ private void buildFriendsMatrix() {
+ friends = new boolean[useableServers.length][useableServers.length];
+ for (int i=0; i<useableServers.length; i++)
+ for (int j=0; j<useableServers.length; j++)
+ if (i==j)
+ friends[i][j] = true;
+ else
+ friends[i][j] = areFriends(useableServers[i], useableServers[j]);
+ }
+ */
}
diff --git a/src/org/noreply/fancydress/directory/IncomingMMTPSection.java b/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
index 92e17d7..bf9682f 100644
--- a/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
+++ b/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
@@ -19,6 +19,11 @@ import java.net.UnknownHostException;
* @see ServerDescriptor
*/
public class IncomingMMTPSection {
+ /*
+ปญญญญญญญ * version we understand.
+ปญญญญญญญ */
+ private static final String VERSION = "0.1";
+
private String name;
/* Required */
@@ -26,7 +31,7 @@ public class IncomingMMTPSection {
private InetAddress ip;
private String hostname;
private int port;
- private String protocols;
+ private String[] protocols;
/**
* Construct an Incoming/MMTP section.
@@ -53,7 +58,7 @@ public class IncomingMMTPSection {
if (entryVersion == null)
throw new Mix3BadServerFormatException("Version not in " + name + " section");
version = entryVersion.getValue();
- if (! version.equals("0.1"))
+ if (! version.equals(VERSION))
/* We have to ignore unknown Versions */
throw new Mix3BadServerUnrecognizedVersionException("Unrecognized " + name + " Version "+version);
@@ -98,7 +103,7 @@ public class IncomingMMTPSection {
if (port < 0 || port > 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
@@ -35,6 +35,11 @@ public class Server {
ArrayList descriptors;
/**
+ * whether or not this node is recommended.
+ */
+ boolean recommended;
+
+ /**
* Construct a Server from a given ServerDescriptor.
*
* @param descriptor a 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;
}
/**
@@ -77,11 +127,21 @@ public class Server {
}
/**
+ * 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<result.length; i++)
- result[i] = (String) versions.get(i);
-
- return result;
- }
- /**
- * Tokenize a Packet-Versions string into single Packet-Versions.
- *
- * The Packet-Versions is a comma separated list of Packet-Versions.
- * This method parses a Packet-Versions value and returns an array of
- * Strings, holding one Packet-Version each.
- *
- * Whitespace is trimmed off each Packet-Version.
- *
- * Only Packet-Versions that we know to handle are included n the result.
- *
- * @param s the comma separated list of Packet-Versions
- * @return array of Packet-Versions.
- */
- public static String[] parsePacketVersions(String s) {
- return parsePacketVersions(s, true);
+ String[] tokens = Util.tokenize(s, ',');
+ for (int i=0; i<tokens.length; i++)
+ if (Packet.isPacketVersionSupported(tokens[i]))
+ versions.add( tokens[i] );
+ return (String[]) versions.toArray( new String[versions.size()] );
}
/**
@@ -173,7 +155,7 @@ public class ServerDescriptor {
if (entryDescriptorVersion == null)
throw new Mix3BadServerFormatException("Descriptor-Version not in Server Descriptor");
descriptorVersion = entryDescriptorVersion.getValue();
- if (! descriptorVersion.equals("0.2"))
+ if (! descriptorVersion.equals(DESCRIPTOR_VERSION))
/* We have to ignore unknown Descriptor-Versions */
throw new Mix3BadServerUnrecognizedVersionException("Unrecognized Descriptor-Version "+descriptorVersion);
@@ -319,6 +301,15 @@ public class ServerDescriptor {
}
/**
+ * Get this server descriptor's supported packet versions.
+ *
+ * @return supported packet versions
+ */
+ public String[] getPacketVersions() {
+ return packetVersions;
+ }
+
+ /**
* Get the date after which this server descriptor is valid.
*
* @return date after which this server descriptor is valid
@@ -354,4 +345,13 @@ public class ServerDescriptor {
return incomingMMTPSection;
}
+ /**
+ * Get the Outgoing/MMTP section.
+ *
+ * @return this server descriptor's Outgoing/MMTP section
+ */
+ public OutgoingMMTPSection getOutgoingMMTPSection() {
+ return outgoingMMTPSection;
+ }
+
}
diff --git a/src/org/noreply/fancydress/misc/Util.java b/src/org/noreply/fancydress/misc/Util.java
index a111b88..d9b46da 100644
--- a/src/org/noreply/fancydress/misc/Util.java
+++ b/src/org/noreply/fancydress/misc/Util.java
@@ -234,4 +234,30 @@ public class Util {
throw new ParseException("Cannot parse boolean expression "+s,0);
}
}
+
+ /**
+ * Tokenize comma separated lists into single tokens.
+ *
+ * Single tokens are trimmed of whitespace.
+ *
+ * @param s string of comma separated items.
+ * @param separator a token separator
+ * @return an array of single tokens.
+ */
+ public static String[] tokenize(String s, char separator) {
+ ArrayList list = new ArrayList();
+ int indexFrom = 0;
+ int indexOf;
+
+ do {
+ indexOf = s.indexOf(separator, indexFrom);
+ String v = (indexOf >= 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<hops.length; i++)
+ result = (result == null) ? hops[i].getNickname() : result + "," + hops[i].getNickname();
+ return result;
+ }
}
diff --git a/src/org/noreply/fancydress/type3/Hop.java b/src/org/noreply/fancydress/type3/Hop.java
index 181d2e8..9c61b2d 100644
--- a/src/org/noreply/fancydress/type3/Hop.java
+++ b/src/org/noreply/fancydress/type3/Hop.java
@@ -3,14 +3,40 @@ package org.noreply.fancydress.type3;
import org.noreply.fancydress.type3.routing.*;
import org.noreply.fancydress.crypto.*;
+import org.noreply.fancydress.status.*;
+import org.noreply.fancydress.directory.*;
public class Hop {
private Routing routing;
private RSAPublicKey pubKey;
+ private String[] packetVersions;
+ private String nickname;
- public Hop(Routing routing, RSAPublicKey pubKey) {
+ public Hop(Routing routing, RSAPublicKey pubKey, String[] packetVersions, String nickname) {
this.routing = routing;
this.pubKey = pubKey;
+ this.packetVersions = packetVersions;
+ this.nickname = nickname;
+ }
+
+ public Hop(Server server) throws Mix3PathProblemException {
+ if (!server.isUseable())
+ throw new Mix3PathProblemException("Invalid path: '"+server.getNickname()+"' is not useable");
+ ServerDescriptor desc;
+ try {
+ desc = server.getDescriptor();
+ } catch (Mix3NoServerDescriptorException e) {
+ throw new Error ("We should have a server descriptor at that point");
+ }
+ IncomingMMTPSection incoming = desc.getIncomingMMTPSection();
+
+ if (incoming.getHostname() != null)
+ this.routing = new RoutingHOST(incoming.getHostname(), incoming.getPort(), server.getKeyID());
+ else
+ this.routing = new RoutingIP4(incoming.getIP(), incoming.getPort(), server.getKeyID()); /* FIXME */
+ this.pubKey = desc.getPacketKey();
+ this.packetVersions = desc.getPacketVersions();
+ this.nickname = server.getNickname();
}
public Routing getRouting() {
@@ -20,4 +46,15 @@ public class Hop {
public RSAPublicKey getPubKey() {
return pubKey;
}
+
+ public boolean supportsPacketVersion(String v) {
+ for (int i=0; i<packetVersions.length; i++)
+ if (v.equals(packetVersions[i]))
+ return true;
+ return false;
+ }
+
+ public String getNickname() {
+ return nickname;
+ };
}
diff --git a/src/org/noreply/fancydress/type3/Message.java b/src/org/noreply/fancydress/type3/Message.java
index 4861c85..0925a6c 100644
--- a/src/org/noreply/fancydress/type3/Message.java
+++ b/src/org/noreply/fancydress/type3/Message.java
@@ -15,9 +15,11 @@ public class Message {
public Message(PathSpec path, RoutingDestination destination, String body) throws Mix3Exception {
Payload payload = new Payload(destination, body);
int numberOfPackets = payload.numPackets();
+ Path[] paths = path.getPath(payload);
packets = new Packet[numberOfPackets];
for (int i=0; i<numberOfPackets; i++) {
- packets[i] = new Packet(path.getPath(), payload.getRoute(i), payload.getPayload(i));
+System.err.println("Path: "+paths[i].asString());
+ packets[i] = new Packet(paths[i], payload.getRoute(i), payload.getPayload(i));
}
}
diff --git a/src/org/noreply/fancydress/type3/Path.java b/src/org/noreply/fancydress/type3/Path.java
index 8373990..d9b8950 100644
--- a/src/org/noreply/fancydress/type3/Path.java
+++ b/src/org/noreply/fancydress/type3/Path.java
@@ -23,5 +23,9 @@ public class Path {
public HalfPath getSecondHalf() {
return second;
}
+
+ public String asString() {
+ return (first.asString() + ":" + second.asString());
+ }
}
diff --git a/src/org/noreply/fancydress/type3/PathSpec.java b/src/org/noreply/fancydress/type3/PathSpec.java
index cbc608f..9e975c6 100644
--- a/src/org/noreply/fancydress/type3/PathSpec.java
+++ b/src/org/noreply/fancydress/type3/PathSpec.java
@@ -11,53 +11,125 @@ import java.util.*;
public class PathSpec {
- String pathSpec;
- Path singlePath;
+ Directory dir;
+ PathComponent[] pathComponents;
+ boolean singleLeg;
- private String[] tokenize(String path) throws Mix3Exception {
- ArrayList nicks = new ArrayList();
- int indexFrom = 0;
- int indexOf;
-
- while ((indexOf = path.indexOf(',', indexFrom)) != -1) {
- String v = path.substring(indexFrom, indexOf).trim();
- if (v.equals(""))
- throw new Mix3Exception("Invalid path.");
- nicks.add( v );
- indexFrom = indexOf + 1;
+ private class PathComponent {
+ public final static double GAUSS_STD_DEV = 1.5;
+
+ public final static int TYPE_NICKNAME = 1;
+ public final static int TYPE_RANDOM = 2;
+ public final static int TYPE_RANDOM_GAUSS = 3;
+ public final static int TYPE_CROSSOVER = 4;
+ int type;
+ Server byNickname;
+ int numRandoms;
+
+ public PathComponent(Directory dir, String component) throws Mix3BadArgumentsIllegalPathSpecException {
+ String c = component.trim();
+ if (c.equals(""))
+ throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: empty path component");
+ char b = c.charAt(0);
+
+ Integer integer;
+ switch (b) {
+ case '*' :
+ try {
+ integer = new Integer(c.substring(1));
+ } catch (NumberFormatException e) {
+ throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: illegal path component '"+c+"'");
+ }
+ type = TYPE_RANDOM;
+ numRandoms = integer.intValue();
+ break;
+ case '~' :
+ try {
+ integer = new Integer(c.substring(1));
+ } catch (NumberFormatException e) {
+ throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: illegal path component '"+c+"'");
+ }
+ type = TYPE_RANDOM_GAUSS;
+ numRandoms = integer.intValue();
+ break;
+ case '?' :
+ if (c.length() > 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<result.length; i++)
- result[i] = (String) nicks.get(i);
+ public boolean isCrossover() {
+ return (type == TYPE_CROSSOVER);
+ }
- return result;
+ public Server[] getHops() {
+ Server[] result;
+ switch (type) {
+ case TYPE_NICKNAME :
+ result = new Server[1];
+ result[0] = byNickname;
+ break;
+ case TYPE_RANDOM :
+ result = new Server[numRandoms];
+ break;
+ case TYPE_RANDOM_GAUSS :
+ double d = CryptoPrimitives.normal(numRandoms, GAUSS_STD_DEV);
+ int num = (int) (d+0.5);
+ result = new Server[ num<0 ? 0 : num ];
+ break;
+ default :
+ throw new Error("Unkown type "+type);
+ }
+ return result;
+ }
}
- private Hop[] parseHalfPath(Directory dir, String path) throws Mix3Exception {
- String[] nicks = tokenize(path);
- Hop[] hops = new Hop[nicks.length];
-
- for (int i=0; i<hops.length; i++) {
- Server server = dir.getServer(nicks[i]);
- if (server == null)
- throw new Mix3Exception("Invalid path: "+nicks[i]+" not found");
- ServerDescriptor desc = server.getDescriptor();
- IncomingMMTPSection incoming = desc.getIncomingMMTPSection();
- Routing routing;
-
- if (incoming.getHostname() != null) { /* FIXME */
- routing = new RoutingHOST(incoming.getHostname(), incoming.getPort(), server.getKeyID());
- } else {
- routing = new RoutingIP4(incoming.getIP(), incoming.getPort(), server.getKeyID());
- }
- hops[i] = new Hop(routing, desc.getPacketKey());
+ private void splitCrossover(ArrayList tokens, String s) throws Mix3BadArgumentsIllegalPathSpecException {
+ int indexOf = s.indexOf(':');
+ if (indexOf != -1) {
+ String s1 = s.substring(0, indexOf).trim();
+ String s2 = s.substring(indexOf+1).trim();
+ if (s1.equals(""))
+ throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: Empty hop before crossover point.");
+ if (s2.equals(""))
+ throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: Empty hop after crossover point.");
+ tokens.add(s1.trim());
+ tokens.add(s2.trim());
+ } else {
+ if (s.equals(""))
+ throw new Mix3BadArgumentsIllegalPathSpecException("Invalid path: Empty hop in path.");
+ tokens.add(s);
}
- return hops;
+ }
+
+ private PathComponent[] parsePath(Directory dir, String path) throws Mix3BadArgumentsIllegalPathSpecException {
+ ArrayList nicks = new ArrayList();
+ String[] tokens = Util.tokenize(path, ',');
+ for (int i=0; i<tokens.length; i++)
+ splitCrossover( nicks, tokens[i] );
+
+ PathComponent[] components = new PathComponent[nicks.size()];
+ for (int i=0; i<nicks.size(); i++)
+ components[i] = new PathComponent(dir, (String) nicks.get(i));
+
+ return components;
}
@@ -70,26 +142,212 @@ public class PathSpec {
*
* @param path given path
*/
- public PathSpec(Directory dir, String pathSpec, boolean singleLeg) throws Mix3Exception {
- this.pathSpec = pathSpec;
+ public PathSpec(Directory dir, String pathSpec, boolean singleLeg) throws Mix3BadArgumentsIllegalPathSpecException {
+ this.dir = dir;
+ this.singleLeg = singleLeg;
+
+ if (singleLeg) {
+ /* single legs do not have a crossover point */
+ int crossover = pathSpec.indexOf(':');
+ if (crossover >= 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; r<recommended.length; r++)
+ if (
+ /* last hop or */
+ ((i == servers.length-1) || (
+ /* next hop is different */
+ (recommended[r] != servers[i+1]) &&
+ /* and can talk to next hop */
+ dir.areFriends(recommended[r], servers[i+1]) )) &&
+ /* first hop, or previos hop is random, or */
+ ((i == 0) || (servers[i-1] == null) || (
+ /* previous hop is different */
+ (recommended[r] != servers[i-1]) &&
+ /* and prev hop can talk to this */
+ dir.areFriends(servers[i-1], recommended[r]) ))
+ )
+ s.add(recommended[r]);
+ if (s.size() == 0)
+ throw new Mix3PathProblemException("Cannot find useable servers for random hop.");
+ servers[i] = (Server) s.get(CryptoPrimitives.randInt(s.size()));
+ }
+ }
+
+ public Path getPath() throws Mix3PathProblemException {
+ fillInRandoms();
+ Hop[] hops = new Hop[servers.length];
+ for (int i=0; i<hops.length ; i++)
+ hops[i] = new Hop(servers[i]);
+
+ if (crossoverPoint == -1)
+ crossoverPoint = (hops.length+1)/2;
+ int len1 = crossoverPoint;
+ int len2 = hops.length - len1;
+ Hop[] l1 = new Hop[len1];
+ Hop[] l2 = new Hop[len2];
+ System.arraycopy(hops, 0, l1, 0, len1);
+ System.arraycopy(hops, len1, l2, 0, len2);
+ return new Path(l1, l2);
+ }
+ }
+
+ /**
+ * Concat path components, getting random amount of hops where requested.
+ */
+ private ServerWithCrossover concatComponents() throws Mix3PathProblemException {
+ Server[][] components = new Server[pathComponents.length][];
+ int length = 0;
+ int crossoverBefore = -1;
+ for (int i=0; i<pathComponents.length ; i++) {
+ if (pathComponents[i].isCrossover())
+ crossoverBefore = length;
+ else {
+ components[i] = pathComponents[i].getHops();
+ length += components[i].length;
+ }
+ }
+ Server[] servers = new Server[length];
+ int c = 0;
+ for (int i=0; i<pathComponents.length ; i++) {
+ if (components[i] != null) {
+ System.arraycopy(components[i], 0, servers, c, components[i].length);
+ c += components[i].length;
+ }
+ }
+ if (c != length)
+ throw new Error ("Did not fill in length hops ("+c+" vs "+length+")");
+
+ ServerWithCrossover result = new ServerWithCrossover();
+ result.servers = servers;
+ result.crossoverPoint = crossoverBefore;
+ return result;
+ }
+
+ /**
+ * get one instance of this path spec.
+ *
+ * Also we filter acceptable exit nodes according to the payload's
+ * constraints.
+ *
+ * @return one path constructed from the PathSpec
+ */
+ /*
+ private Object getPathInstance() throws Mix3PathProblemException {
- int crossover = pathSpec.indexOf(':');
- if (crossover < 0)
- throw new Mix3Exception("Path is not a valid path: no crossover point specified.");
+ ServerWithCrossover path = concatComponents();
+ fillInRandoms(path.components);
- Hop[] leg1 = parseHalfPath(dir, pathSpec.substring(0, crossover));
- Hop[] leg2 = parseHalfPath(dir, pathSpec.substring(crossover+1));
- singlePath = new Path(leg1, leg2);
+ if (singleLeg)
+ throw new Error("not implemented yet"); // FIXME
+ else
+ return path.getPath();
}
+ */
/**
- * Return a path constructed from this PathSpec
+ * Return paths constructed from this PathSpec.
+ *
+ * Build paths from this pathspec that are able to deliver the payload
+ * in <code>payload</code>.
*
- * @param dir a directory
- * @return path
+ * We build as many paths as <code>payload.numPackets()</code> 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<paths.length; i++) {
+ paths[i] = concatComponents();
+ if (paths[i].servers.length < 2)
+ throw new Mix3PathProblemException("Path too short.");
+ }
+
+ Server lastHop = paths[0].getLastServer();
+ for (int i=1; i<paths.length; i++)
+ if (lastHop != paths[i].getLastServer())
+ throw new Mix3PathProblemException("Exit hop must be the same in all paths (random or fixed)");
+
+ Server[] possibleExitHops = payload.filterExithops( dir.getRecommendedServers() );
+ if (lastHop == null) {
+ boolean[] unuseable = new boolean[possibleExitHops.length];
+ for (int i=0; i<paths.length; i++) {
+ Server stls = paths[i].getSecondToLastServer();
+ if (stls == null)
+ continue;
+ for (int j=0; j<unuseable.length; j++)
+ if (unuseable[j])
+ continue;
+ else
+ if (! dir.areFriends(stls, possibleExitHops[j] ))
+ unuseable[j] = true;
+ }
+ ArrayList list = new ArrayList();
+ for (int j=0; j<unuseable.length; j++)
+ if (! unuseable[j])
+ list.add(possibleExitHops[j]);
+
+ if (list.size() == 0)
+ throw new Mix3PathProblemException("No useable exit hops found");
+
+ lastHop = (Server) list.get( CryptoPrimitives.randInt(list.size()) );
+ for (int i=0; i<paths.length; i++)
+ paths[i].setLastServer(lastHop);
+ } else {
+ boolean exitHopOK = false;
+ for (int j=0; j<possibleExitHops.length; j++)
+ if (possibleExitHops[j] == lastHop) {
+ exitHopOK = true;
+ break;
+ }
+ if (! exitHopOK)
+ throw new Mix3PathProblemException("Exit hop "+lastHop.getNickname()+" does not meet constraints.");
+ }
+
+ Path[] result = new Path[paths.length];
+ for (int i=0; i<paths.length; i++)
+ result[i] = paths[i].getPath();
+
+ return result;
}
}
-
diff --git a/src/org/noreply/fancydress/type3/Payload.java b/src/org/noreply/fancydress/type3/Payload.java
index 73027cd..0294537 100644
--- a/src/org/noreply/fancydress/type3/Payload.java
+++ b/src/org/noreply/fancydress/type3/Payload.java
@@ -4,6 +4,7 @@ package org.noreply.fancydress.type3;
import java.io.*;
import java.util.zip.*;
import org.noreply.fancydress.crypto.*;
+import org.noreply.fancydress.directory.*;
import org.noreply.fancydress.misc.Util;
import org.noreply.fancydress.type3.routing.*;
@@ -77,5 +78,9 @@ public class Payload {
public RoutingDestination getRoute(int i) {
return route[i];
}
+
+ public Server[] filterExithops(Server[] s) {
+ return s;
+ }
}
diff --git a/src/org/noreply/fancydress/type3/mmtp/MMTP.java b/src/org/noreply/fancydress/type3/mmtp/MMTP.java
index 63f1f6f..3695c52 100644
--- a/src/org/noreply/fancydress/type3/mmtp/MMTP.java
+++ b/src/org/noreply/fancydress/type3/mmtp/MMTP.java
@@ -29,7 +29,9 @@ public class MMTP {
context.init(null, trustManagers, null);
SSLSocketFactory socketFactory = context.getSocketFactory();
- SSLSocket socket = (SSLSocket) socketFactory.createSocket("127.0.0.1", 48099);
+ RoutingForward route = packet.getRoute();
+System.err.println("Connecting to "+route.getHostname()+":"+route.getPort());
+ SSLSocket socket = (SSLSocket) socketFactory.createSocket(route.getHostname(), route.getPort());
String[] supportedProtocols = socket.getSupportedProtocols();
@@ -49,11 +51,13 @@ public class MMTP {
socket.setEnabledProtocols( new String[] { TLS_PROTO } );
socket.setEnabledCipherSuites( new String[] { TLS_DHE_RSA_WITH_AES_128_CBC_SHA } );
acceptableFound = true;
+System.err.println("Using TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
break;
} else if (haveSSLv3 && supportedCipherSuits[i].equals(SSL3_RSA_DES_192_CBC3_SHA)) {
socket.setEnabledProtocols( new String[] { SSL_PROTO } );
socket.setEnabledCipherSuites( new String[] { SSL3_RSA_DES_192_CBC3_SHA } );
acceptableFound = true;
+System.err.println("Using SSL3_RSA_DES_192_CBC3_SHA");
break;
}
}
diff --git a/src/org/noreply/fancydress/type3/routing/RoutingForward.java b/src/org/noreply/fancydress/type3/routing/RoutingForward.java
index 183696a..7c05eed 100644
--- a/src/org/noreply/fancydress/type3/routing/RoutingForward.java
+++ b/src/org/noreply/fancydress/type3/routing/RoutingForward.java
@@ -38,5 +38,18 @@ public abstract class RoutingForward extends Routing {
public byte[] getKeyID() {
return keyid;
}
+
+ /**
+ * Get the hostname needed for connectig to the node.
+ *
+ * @return hostname.
+ */
+ public abstract String getHostname();
+ /**
+ * Get the port needed for connectig to the node.
+ *
+ * @return port
+ */
+ public abstract int getPort();
}
diff --git a/src/org/noreply/fancydress/type3/routing/RoutingHOST.java b/src/org/noreply/fancydress/type3/routing/RoutingHOST.java
index 6138c2e..be568b4 100644
--- a/src/org/noreply/fancydress/type3/routing/RoutingHOST.java
+++ b/src/org/noreply/fancydress/type3/routing/RoutingHOST.java
@@ -94,5 +94,21 @@ public class RoutingHOST extends RoutingForward {
return result;
}
+ /**
+ * Get the hostname needed for connectig to the node.
+ *
+ * @return hostname.
+ */
+ public String getHostname() {
+ return hostname;
+ }
+ /**
+ * Get the port needed for connectig to the node.
+ *
+ * @return port
+ */
+ public int getPort() {
+ return port;
+ }
}
diff --git a/src/org/noreply/fancydress/type3/routing/RoutingIP4.java b/src/org/noreply/fancydress/type3/routing/RoutingIP4.java
index e0527a0..9db61dd 100644
--- a/src/org/noreply/fancydress/type3/routing/RoutingIP4.java
+++ b/src/org/noreply/fancydress/type3/routing/RoutingIP4.java
@@ -102,5 +102,21 @@ public class RoutingIP4 extends RoutingForward {
return result;
}
+ /**
+ * Get the hostname needed for connectig to the node.
+ *
+ * @return hostname.
+ */
+ public String getHostname() {
+ return ip.getHostAddress();
+ }
+ /**
+ * Get the port needed for connectig to the node.
+ *
+ * @return port
+ */
+ public int getPort() {
+ return port;
+ }
}