diff options
Diffstat (limited to 'src/org/noreply/fancydress/directory/Directory.java')
-rw-r--r-- | src/org/noreply/fancydress/directory/Directory.java | 230 |
1 files changed, 199 insertions, 31 deletions
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]); + } + */ } |