From 84c226bae470c8779ae699d7b0f50bfe196b450c Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Wed, 9 Apr 2008 09:43:44 +0000 Subject: [PATCH] improved (and hopefully final) design git-svn-id: http://trooper/svn/projects/jSite/trunk@654 c3eda9e8-030b-0410-8277-bc7414b0a119 --- src/net/pterodactylus/util/fcp/FcpConnection.java | 266 +++++++++------------ src/net/pterodactylus/util/fcp/FcpListener.java | 28 ++- src/net/pterodactylus/util/fcp/FcpMessage.java | 13 +- src/net/pterodactylus/util/fcp/FcpUtils.java | 28 +++ .../util/fcp/client/FcpHighLevelClient.java | 202 ---------------- .../util/fcp/client/FcpNodeInformation.java | 143 ----------- .../util/fcp/client/NodeHelloCallback.java | 33 --- .../util/fcp/message/BaseMessage.java | 50 ++++ .../util/fcp/message/ClientHello.java | 48 ++++ .../CloseConnectionDuplicateClientName.java | 27 +++ .../util/fcp/message/GenerateSSK.java | 36 +++ .../pterodactylus/util/fcp/message/NodeHello.java | 207 ++++++++++++++++ .../util/fcp/message/package-info.java | 4 + 13 files changed, 544 insertions(+), 541 deletions(-) create mode 100644 src/net/pterodactylus/util/fcp/FcpUtils.java delete mode 100644 src/net/pterodactylus/util/fcp/client/FcpHighLevelClient.java delete mode 100644 src/net/pterodactylus/util/fcp/client/FcpNodeInformation.java delete mode 100644 src/net/pterodactylus/util/fcp/client/NodeHelloCallback.java create mode 100644 src/net/pterodactylus/util/fcp/message/BaseMessage.java create mode 100644 src/net/pterodactylus/util/fcp/message/ClientHello.java create mode 100644 src/net/pterodactylus/util/fcp/message/CloseConnectionDuplicateClientName.java create mode 100644 src/net/pterodactylus/util/fcp/message/GenerateSSK.java create mode 100644 src/net/pterodactylus/util/fcp/message/NodeHello.java create mode 100644 src/net/pterodactylus/util/fcp/message/package-info.java diff --git a/src/net/pterodactylus/util/fcp/FcpConnection.java b/src/net/pterodactylus/util/fcp/FcpConnection.java index 484b46c..4582eca 100644 --- a/src/net/pterodactylus/util/fcp/FcpConnection.java +++ b/src/net/pterodactylus/util/fcp/FcpConnection.java @@ -26,55 +26,95 @@ import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.Map.Entry; +import net.pterodactylus.util.fcp.message.CloseConnectionDuplicateClientName; +import net.pterodactylus.util.fcp.message.NodeHello; import net.pterodactylus.util.io.Closer; /** - * TODO + * An FCP connection to a Freenet node. * * @author David ‘Bombe’ Roden <bombe@freenetproject.org> * @version $Id$ */ public class FcpConnection { + /** The default port for FCP v2. */ public static final int DEFAULT_PORT = 9481; - private final Object messageWaitSync = new Object(); - private FcpMessage receivedMessage = null; - + /** The list of FCP listeners. */ private final List fcpListeners = new ArrayList(); + /** The address of the node. */ private final InetAddress address; + + /** The port number of the node’s FCP port. */ private final int port; - private final String clientName; + /** The remote socket. */ private Socket remoteSocket; + + /** The input stream from the node. */ private InputStream remoteInputStream; + + /** The output stream to the node. */ private OutputStream remoteOutputStream; + + /** The connection handler. */ private FcpConnectionHandler connectionHandler; - private boolean connected; - public FcpConnection(String host, String clientName) throws UnknownHostException { - this(host, DEFAULT_PORT, clientName); + /** + * Creates a new FCP connection to the Freenet node running on the given + * host, listening on the default port. + * + * @param host + * The hostname of the Freenet node + * @throws UnknownHostException + * if host can not be resolved + */ + public FcpConnection(String host) throws UnknownHostException { + this(host, DEFAULT_PORT); } - public FcpConnection(String host, int port, String clientName) throws UnknownHostException { - this(InetAddress.getByName(host), port, clientName); + /** + * Creates a new FCP connection to the Freenet node running on the given + * host, listening on the given port. + * + * @param host + * The hostname of the Freenet node + * @param port + * The port number of the node’s FCP port + * @throws UnknownHostException + * if host can not be resolved + */ + public FcpConnection(String host, int port) throws UnknownHostException { + this(InetAddress.getByName(host), port); } - public FcpConnection(InetAddress address, String clientName) { - this(address, DEFAULT_PORT, clientName); + /** + * Creates a new FCP connection to the Freenet node running at the given + * address, listening on the default port. + * + * @param address + * The address of the Freenet node + */ + public FcpConnection(InetAddress address) { + this(address, DEFAULT_PORT); } - public FcpConnection(InetAddress address, int port, String clientName) { + /** + * Creates a new FCP connection to the Freenet node running at the given + * address, listening on the given port. + * + * @param address + * The address of the Freenet node + * @param port + * The port number of the node’s FCP port + */ + public FcpConnection(InetAddress address, int port) { this.address = address; this.port = port; - this.clientName = clientName; } // @@ -102,6 +142,34 @@ public class FcpConnection { } /** + * Notifies listeners that a “NodeHello” message was received. + * + * @see FcpListener#receivedNodeHello(FcpConnection, NodeHello) + * @param nodeHello + * The “NodeHello” message + */ + private void fireReceivedNodeHello(NodeHello nodeHello) { + for (FcpListener fcpListener: fcpListeners) { + fcpListener.receivedNodeHello(this, nodeHello); + } + } + + /** + * Notifies listeners that a “CloseConnectionDuplicateClientName” message + * was received. + * + * @see FcpListener#receivedCloseConnectionDuplicateClientName(FcpConnection, + * CloseConnectionDuplicateClientName) + * @param closeConnectionDuplicateClientName + * The “CloseConnectionDuplicateClientName” message + */ + private void fireReceivedCloseConnectionDuplicateClientName(CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) { + for (FcpListener fcpListener: fcpListeners) { + fcpListener.receivedCloseConnectionDuplicateClientName(this, closeConnectionDuplicateClientName); + } + } + + /** * Notifies all registered listeners that a message has been received. * * @see FcpListener#receivedMessage(FcpConnection, FcpMessage) @@ -133,7 +201,6 @@ public class FcpConnection { remoteSocket = new Socket(address, port); remoteInputStream = remoteSocket.getInputStream(); remoteOutputStream = remoteSocket.getOutputStream(); - connected = true; new Thread(connectionHandler = new FcpConnectionHandler(this, remoteInputStream)).start(); } @@ -145,158 +212,43 @@ public class FcpConnection { if (connectionHandler == null) { return; } - connected = false; Closer.close(remoteSocket); connectionHandler.stop(); connectionHandler = null; } - public synchronized void sendMessage(FcpMessage fcpMessage) throws IOException { - System.out.println("sending message: " + fcpMessage.getName()); - fcpMessage.write(remoteOutputStream); - } - /** - * Sends a “ListPeer” command to the node and returns the properties of the - * peer. + * Sends the given FCP message. * - * @param nodeIdentifier - * The name (except for OpenNet nodes), the identity or the - * node’s “address:port” pair - * @return The properties of the peer, or null if the peer is - * unknown + * @param fcpMessage + * The FCP message to send * @throws IOException - * @throws FcpException + * if an I/O error occurs */ - public Map sendListPeer(String nodeIdentifier) throws IOException, FcpException { - FcpMessage listPeerMessage = new FcpMessage("ListPeer"); - listPeerMessage.setField("NodeIdentifier", nodeIdentifier); - sendMessage(listPeerMessage); - FcpMessage returnMessage = waitForMessage("Peer", "UnknownNodeIdentifier"); - if (returnMessage.getName().equals("Peer")) { - return returnMessage.getFields(); - } - return null; - } - - void handleMessage(FcpMessage fcpMessage) { - fireMessageReceived(fcpMessage); - } - - public List> sendListPeers(boolean withMetadata, boolean withVolatile) throws IOException, FcpException { - FcpMessage listPeersMessage = new FcpMessage("ListPeers"); - listPeersMessage.setField("WithMetadata", String.valueOf(withMetadata)); - listPeersMessage.setField("WithVolatile", String.valueOf(withVolatile)); - sendMessage(listPeersMessage); - List> peers = new ArrayList>(); - while (true) { - FcpMessage returnMessage = waitForMessage("Peer", "EndListPeers"); - if (returnMessage.getName().equals("EndListPeers")) { - break; - } - peers.add(returnMessage.getFields()); - } - return peers; - } - - public List> sendListPeerNotes(String nodeIdentifier) throws IOException, FcpException { - FcpMessage listPeerNotesMessage = new FcpMessage("ListPeerNotes"); - listPeerNotesMessage.setField("NodeIdentifier", nodeIdentifier); - sendMessage(listPeerNotesMessage); - List> peerNotes = new ArrayList>(); - while (true) { - FcpMessage returnMessage = waitForMessage("PeerNote", "EndListPeerNotes"); - if (returnMessage.getName().equals("EndListPeerNotes")) { - break; - } - peerNotes.add(returnMessage.getFields()); - } - return peerNotes; - } - - public void sendTestDDARequest(String directory, boolean wantReadDirectory, boolean wantWriteDirectory) throws IOException, FcpException { - FcpMessage testDDARequestMessage = new FcpMessage("TestDDARequest"); - testDDARequestMessage.setField("Directory", directory); - testDDARequestMessage.setField("WantReadDirectory", String.valueOf(wantReadDirectory)); - testDDARequestMessage.setField("WantWriteDirectory", String.valueOf(wantWriteDirectory)); - sendMessage(testDDARequestMessage); - } - - public FcpKeyPair generateSSK() throws IOException, FcpException { - FcpMessage generateSSKMessage = new FcpMessage("GenerateSSK"); - String identifier = hashCode() + String.valueOf(System.currentTimeMillis()); - generateSSKMessage.setField("Identifier", identifier); - sendMessage(generateSSKMessage); - FcpMessage returnMessage = waitForMessage("SSKKeypair(Identifier=" + identifier + ")"); - String publicKey = returnMessage.getField("RequestURI"); - String privateKey = returnMessage.getField("InsertURI"); - return new FcpKeyPair(publicKey, privateKey); + public synchronized void sendMessage(FcpMessage fcpMessage) throws IOException { + System.out.println("sending message: " + fcpMessage.getName()); + fcpMessage.write(remoteOutputStream); } // - // PRIVATE METHODS + // PACKAGE-PRIVATE METHODS // - public FcpMessage waitForMessage(String... messageNames) throws FcpException { - FcpMessage oldMessage = null; - synchronized (messageWaitSync) { - while (true) { - while (receivedMessage == oldMessage) { - System.out.println("waiting for receivedMessage"); - try { - messageWaitSync.wait(); - } catch (InterruptedException ie1) { - } - } - System.out.println("got message: " + receivedMessage.getName()); - String receivedMessageName = receivedMessage.getName(); - if ("ProtocolError".equals(receivedMessageName)) { - int code = Integer.valueOf(receivedMessage.getField("Code")); - boolean fatal = Boolean.valueOf(receivedMessage.getField("Fatal")); - boolean global = Boolean.valueOf(receivedMessage.getField("Global")); - String codeDescription = receivedMessage.getField("CodeDescription"); - String extraDescription = receivedMessage.getField("ExtraDescription"); - String identifier = receivedMessage.getField("Identifier"); - FcpProtocolException fcpProtocolException = new FcpProtocolException(code, fatal, global); - fcpProtocolException.setCodeDescription(codeDescription); - fcpProtocolException.setExtraDescription(extraDescription); - fcpProtocolException.setIdentifier(identifier); - throw fcpProtocolException; - } - for (String messageName: messageNames) { - int firstBracket = messageName.indexOf('('); - Map wantedIdentifiers = new HashMap(); - if (firstBracket > -1) { - StringTokenizer identifierTokens = new StringTokenizer(messageName.substring(firstBracket), "()"); - while (identifierTokens.hasMoreTokens()) { - String identifierToken = identifierTokens.nextToken(); - int equalSign = identifierToken.indexOf('='); - if (equalSign > -1) { - wantedIdentifiers.put(identifierToken.substring(0, equalSign), identifierToken.substring(equalSign + 1)); - } - } - messageName = messageName.substring(0, firstBracket); - } - if (receivedMessageName.equals(messageName)) { - boolean found = true; - for (Entry wantedIdentifier: wantedIdentifiers.entrySet()) { - System.out.println("key: " + wantedIdentifier.getKey() + ", value: " + wantedIdentifier.getValue() + ", msg: " + receivedMessage.getField(wantedIdentifier.getKey())); - if (!wantedIdentifier.getValue().equals(receivedMessage.getField(wantedIdentifier.getKey()))) { - found = false; - break; - } - } - if (found) { - System.out.println("message found"); - FcpMessage foundMessage = receivedMessage; - receivedMessage = null; - messageWaitSync.notifyAll(); - return foundMessage; - } - } - } - oldMessage = receivedMessage; - } + /** + * Handles the given message, notifying listeners. This message should only + * be called by {@link FcpConnectionHandler}. + * + * @param fcpMessage + * The received message + */ + void handleMessage(FcpMessage fcpMessage) { + String messageName = fcpMessage.getName(); + if ("NodeHello".equals(messageName)) { + fireReceivedNodeHello(new NodeHello(fcpMessage)); + } else if ("CloseConnectionDuplicateClientName".equals(messageName)) { + fireReceivedCloseConnectionDuplicateClientName(new CloseConnectionDuplicateClientName(fcpMessage)); + } else { + fireMessageReceived(fcpMessage); } } diff --git a/src/net/pterodactylus/util/fcp/FcpListener.java b/src/net/pterodactylus/util/fcp/FcpListener.java index 1efcad8..21caa9c 100644 --- a/src/net/pterodactylus/util/fcp/FcpListener.java +++ b/src/net/pterodactylus/util/fcp/FcpListener.java @@ -21,6 +21,9 @@ package net.pterodactylus.util.fcp; import java.util.EventListener; +import net.pterodactylus.util.fcp.message.CloseConnectionDuplicateClientName; +import net.pterodactylus.util.fcp.message.NodeHello; + /** * Interface for objects that want to be notified on certain FCP events. * @@ -30,7 +33,30 @@ import java.util.EventListener; public interface FcpListener extends EventListener { /** - * Notifies listeners that a message has been received. + * Notifies listeners that a “NodeHello” message was received. + * + * @param fcpConnection + * The connection that received the message + * @param nodeHello + * The “NodeHello” message + */ + public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello); + + /** + * Notifies all listeners that a “CloseConnectionDuplicateClientName” + * message was received. + * + * @param fcpConnection + * The connection that received the message + * @param closeConnectionDuplicateClientName + * The “CloseConnectionDuplicateClientName” message + */ + public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName); + + /** + * Notifies listeners that a message has been received. This method is only + * called if {@link FcpConnection#handleMessage(FcpMessage)} does not + * recognize the message. Should that ever happen, please file a bug report! * * @param fcpConnection * The connection that received the message diff --git a/src/net/pterodactylus/util/fcp/FcpMessage.java b/src/net/pterodactylus/util/fcp/FcpMessage.java index 6ff4ec6..3a23928 100644 --- a/src/net/pterodactylus/util/fcp/FcpMessage.java +++ b/src/net/pterodactylus/util/fcp/FcpMessage.java @@ -56,26 +56,29 @@ public class FcpMessage implements Iterable { public String getName() { return name; } - + public void setField(String field, String value) { + if ((field == null) || (value == null)) { + throw new NullPointerException(((field == null) ? "field " : "value ") + "must not be null"); + } fields.put(field, value); } - + public String getField(String field) { return fields.get(field); } - + public Map getFields() { return Collections.unmodifiableMap(fields); } - + /** * {@inheritDoc} */ public Iterator iterator() { return fields.keySet().iterator(); } - + public void setDataInputStream(InputStream dataInputStream) { this.dataInputStream = dataInputStream; } diff --git a/src/net/pterodactylus/util/fcp/FcpUtils.java b/src/net/pterodactylus/util/fcp/FcpUtils.java new file mode 100644 index 0000000..9892610 --- /dev/null +++ b/src/net/pterodactylus/util/fcp/FcpUtils.java @@ -0,0 +1,28 @@ +/** + * © 2008 INA Service GmbH + */ +package net.pterodactylus.util.fcp; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * Helper class with utility methods for the FCP protocol. + * + * @author David Roden + * @version $Id$ + */ +public class FcpUtils { + + /** Counter for unique identifiers. */ + private static AtomicLong counter = new AtomicLong(); + + /** + * Returns a unique identifier. + * + * @return A unique identifier + */ + public static String getUniqueIdentifier() { + return new StringBuilder().append(System.currentTimeMillis()).append('-').append(counter.getAndIncrement()).toString(); + } + +} diff --git a/src/net/pterodactylus/util/fcp/client/FcpHighLevelClient.java b/src/net/pterodactylus/util/fcp/client/FcpHighLevelClient.java deleted file mode 100644 index 5e02dc6..0000000 --- a/src/net/pterodactylus/util/fcp/client/FcpHighLevelClient.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * jSite2 - FcpHighLevelClient.java - - * Copyright © 2008 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 net.pterodactylus.util.fcp.client; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import net.pterodactylus.util.fcp.FcpConnection; -import net.pterodactylus.util.fcp.FcpException; -import net.pterodactylus.util.fcp.FcpListener; -import net.pterodactylus.util.fcp.FcpMessage; - -/** - * High-level client for FCP connections. - * - * @author David Roden <droden@gmail.com> - * @version $Id$ - */ -public class FcpHighLevelClient implements FcpListener { - - /** The FCP connection of this client. */ - private final FcpConnection fcpConnection; - - /** Storage for incoming messages. */ - private final List incomingMessages = Collections.synchronizedList(new ArrayList()); - - /** Registered handlers for incoming messages. */ - private final List> incomingMessageCallbacks = Collections.synchronizedList(new ArrayList>()); - - /** - * Creates a new high-level client that operates on the given FCP - * connection. - * - * @param fcpConnection - * The FCP connection to operate on - */ - public FcpHighLevelClient(FcpConnection fcpConnection) { - this.fcpConnection = fcpConnection; - fcpConnection.addFcpListener(this); - } - - // - // ACTIONS - // - - /** - * Stops the high-level client. - */ - public void stop() { - fcpConnection.removeFcpListener(this); - } - - public Map login(String clientName, final NodeHelloCallback nodeHelloCallback) throws FcpException, IOException { - FcpMessage clientHelloMessage = new FcpMessage("ClientHello"); - clientHelloMessage.setField("Name", clientName); - clientHelloMessage.setField("ExpectedVersion", "2.0"); - Callback> callback = new Callback>() { - /** - * {@inheritDoc} - */ - @SuppressWarnings("synthetic-access") - public CallbackContainer> consumeMessage(FcpMessage fcpMessage) throws FcpException { - String messageName = fcpMessage.getName(); - if ("CloseConnectionDuplicateClientName".equals(messageName)) { - incomingMessages.remove(0); - if (nodeHelloCallback == null) { - throw new FcpException("duplicate client name"); - } - nodeHelloCallback.closeConnectionDuplicateClientName(); - } - if ("NodeHello".equals(messageName)) { - incomingMessages.remove(0); - return new CallbackContainer>(true, fcpMessage.getFields()); - } - return new CallbackContainer>(false, null); - } - }; - synchronized (incomingMessages) { - synchronized (incomingMessageCallbacks) { - fcpConnection.sendMessage(clientHelloMessage); - if (nodeHelloCallback != null) { - incomingMessageCallbacks.add(callback); - return null; - } - } - return processMessages(callback); - } - } - - // - // PRIVATE METHODS - // - - private T processMessages(Callback callback) throws FcpException { - while (true) { - FcpMessage fcpMessage; - synchronized (incomingMessages) { - while (incomingMessages.isEmpty()) { - try { - incomingMessages.wait(); - } catch (InterruptedException ie1) { - } - } - fcpMessage = incomingMessages.get(0); - } - CallbackContainer callbackContainer = callback.consumeMessage(fcpMessage); - if (callbackContainer.isConsumed()) { - incomingMessages.remove(0); - return callbackContainer.getContent(); - } - } - } - - // - // INTERFACE FcpListener - // - - /** - * {@inheritDoc} - */ - public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) { - if (this.fcpConnection != fcpConnection) { - return; - } - synchronized (incomingMessages) { - incomingMessages.add(fcpMessage); - incomingMessages.notifyAll(); - } - synchronized (incomingMessageCallbacks) { - for (Callback callback: incomingMessageCallbacks) { - try { - CallbackContainer callbackContainer = callback.consumeMessage(fcpMessage); - } catch (FcpException e) { - } - - } - } - } - - public static interface Callback { - - /** - * TODO - * - * @param fcpMessage - * @return - */ - public CallbackContainer consumeMessage(FcpMessage fcpMessage) throws FcpException; - - } - - public static class CallbackContainer { - - private final boolean consumed; - private final T content; - - public CallbackContainer(boolean consumed, T content) { - this.consumed = consumed; - this.content = content; - } - - /** - * TODO - * - * @return - */ - public boolean isConsumed() { - return consumed; - } - - /** - * TODO - * - * @return - */ - public T getContent() { - return content; - } - - } - -} diff --git a/src/net/pterodactylus/util/fcp/client/FcpNodeInformation.java b/src/net/pterodactylus/util/fcp/client/FcpNodeInformation.java deleted file mode 100644 index 5163446..0000000 --- a/src/net/pterodactylus/util/fcp/client/FcpNodeInformation.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * jSite2 - FcpNodeInformation.java - - * Copyright © 2008 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 net.pterodactylus.util.fcp.client; - -/** - * Container for node information. This information is transmitted to the client - * in the “NodeHello” response. - * - * @author David Roden <droden@gmail.com> - * @version $Id$ - */ -public class FcpNodeInformation { - - /** The “FCPVersion” field. */ - private final String fcpVersion; - - /** The “Version” field. */ - private final String version; - - /** The “Node” field. */ - private final String node; - - /** The “Testnet” field. */ - private final boolean testnet; - - /** The “CompressionCodecs” field. */ - private final int compressionCodecs; - - /** The “ConnectionIdentifier” field. */ - private final String connectionIdentifier; - - /** The “NodeLanguage” field. */ - private final String nodeLanguage; - - /** - * Creates a new node information object. - * - * @param fcpVersion - * The “FCPVersion” field - * @param version - * The “Version” field - * @param node - * The “Node” field - * @param testnet - * The “Testnet” field - * @param compressionCodecs - * The “CompressionCodecs” field - * @param connectionIdentifier - * The “ConnectionIdentifier” field - * @param nodeLanguage - * The “NodeLanguage” field - */ - public FcpNodeInformation(String fcpVersion, String version, String node, boolean testnet, int compressionCodecs, String connectionIdentifier, String nodeLanguage) { - this.fcpVersion = fcpVersion; - this.version = version; - this.node = node; - this.testnet = testnet; - this.compressionCodecs = compressionCodecs; - this.connectionIdentifier = connectionIdentifier; - this.nodeLanguage = nodeLanguage; - } - - /** - * Returns the “FCPVersion” field. - * - * @return The “FCPVersion” field - */ - public String getFcpVersion() { - return fcpVersion; - } - - /** - * Returns the “Version” field. - * - * @return The “Version” field - */ - public String getVersion() { - return version; - } - - /** - * Returns the “Node” field. - * - * @return The “Node” field - */ - public String getNode() { - return node; - } - - /** - * Returns the “Testnet” field. - * - * @return The “Testnet” field - */ - public boolean isTestnet() { - return testnet; - } - - /** - * Returns the “CompressionCodecs” field. - * - * @return The “CompressionCodecs” field - */ - public int getCompressionCodecs() { - return compressionCodecs; - } - - /** - * Returns the “ConnectionIdentifier” field. - * - * @return The “ConnectionIdentifier” field - */ - public String getConnectionIdentifier() { - return connectionIdentifier; - } - - /** - * Returns the “NodeLanguage” field. - * - * @return The “NodeLanguage” field - */ - public String getNodeLanguage() { - return nodeLanguage; - } - -} diff --git a/src/net/pterodactylus/util/fcp/client/NodeHelloCallback.java b/src/net/pterodactylus/util/fcp/client/NodeHelloCallback.java deleted file mode 100644 index ee0b893..0000000 --- a/src/net/pterodactylus/util/fcp/client/NodeHelloCallback.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * jSite2 - NodeHelloCallback.java - - * Copyright © 2008 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 net.pterodactylus.util.fcp.client; - - -/** - * TODO - * @author David Roden <droden@gmail.com> - * @version $Id$ - */ -public interface NodeHelloCallback { - - public void nodeHello(FcpNodeInformation fcpNodeInformation); - public void closeConnectionDuplicateClientName(); - -} diff --git a/src/net/pterodactylus/util/fcp/message/BaseMessage.java b/src/net/pterodactylus/util/fcp/message/BaseMessage.java new file mode 100644 index 0000000..03613a6 --- /dev/null +++ b/src/net/pterodactylus/util/fcp/message/BaseMessage.java @@ -0,0 +1,50 @@ +/** + * © 2008 INA Service GmbH + */ +package net.pterodactylus.util.fcp.message; + +import net.pterodactylus.util.fcp.FcpMessage; + +/** + * A basic message abstraction that wraps a received FCP message. + * + * @author David Roden + * @version $Id$ + */ +public class BaseMessage { + + /** The received message, wrapped here. */ + private final FcpMessage receivedMessage; + + /** + * Creates a new base message that wraps the given message. + * + * @param receivedMessage + * The FCP message that was received + */ + public BaseMessage(FcpMessage receivedMessage) { + this.receivedMessage = receivedMessage; + } + + /** + * Returns the name of the message. + * + * @return The name of the message + */ + public String getName() { + return receivedMessage.getName(); + } + + /** + * Returns the content of the field. + * + * @param field + * The name of the field + * @return The content of the field, or null if there is no + * such field + */ + public String getField(String field) { + return receivedMessage.getField(field); + } + +} diff --git a/src/net/pterodactylus/util/fcp/message/ClientHello.java b/src/net/pterodactylus/util/fcp/message/ClientHello.java new file mode 100644 index 0000000..fe68321 --- /dev/null +++ b/src/net/pterodactylus/util/fcp/message/ClientHello.java @@ -0,0 +1,48 @@ +/** + * © 2008 INA Service GmbH + */ +package net.pterodactylus.util.fcp.message; + +import net.pterodactylus.util.fcp.FcpConnection; +import net.pterodactylus.util.fcp.FcpMessage; + +/** + * A “ClientHello” message that must be sent to the node first thing + * after calling {@link FcpConnection#connect()}. + * + * @author David Roden + * @version $Id$ + */ +public class ClientHello extends FcpMessage { + + /** + * Creates a new “ClientHello” message with the given client name. The + * client name has to be unique to the node otherwise you will get a + * {@link CloseConnectionDuplicateClientName} response from the node! + * + * @param clientName + * The unique client name + */ + public ClientHello(String clientName) { + this(clientName, "2.0"); + } + + /** + * Creates a new “ClientHello” message with the given client name. The + * client name has to be unique to the node otherwise you will get a + * {@link CloseConnectionDuplicateClientName} response from the node! + * + * The expected FCP version is currently ignored by the node. + * + * @param clientName + * The unique client name + * @param expectedVersion + * The FCP version that the node is expected to talk + */ + public ClientHello(String clientName, String expectedVersion) { + super("ClientHello"); + setField("Name", clientName); + setField("ExpectedVersion", expectedVersion); + } + +} diff --git a/src/net/pterodactylus/util/fcp/message/CloseConnectionDuplicateClientName.java b/src/net/pterodactylus/util/fcp/message/CloseConnectionDuplicateClientName.java new file mode 100644 index 0000000..6d7aa64 --- /dev/null +++ b/src/net/pterodactylus/util/fcp/message/CloseConnectionDuplicateClientName.java @@ -0,0 +1,27 @@ +/** + * © 2008 INA Service GmbH + */ +package net.pterodactylus.util.fcp.message; + +import net.pterodactylus.util.fcp.FcpMessage; + +/** + * A “CloseConnectionDuplicateClientName” message. + * + * @author David Roden + * @version $Id$ + */ +public class CloseConnectionDuplicateClientName extends BaseMessage { + + /** + * Creates a new CloseConnectionDuplicateClientName message that wraps the + * given message. + * + * @param receivedMessage + * The received message + */ + public CloseConnectionDuplicateClientName(FcpMessage receivedMessage) { + super(receivedMessage); + } + +} diff --git a/src/net/pterodactylus/util/fcp/message/GenerateSSK.java b/src/net/pterodactylus/util/fcp/message/GenerateSSK.java new file mode 100644 index 0000000..f6f2929 --- /dev/null +++ b/src/net/pterodactylus/util/fcp/message/GenerateSSK.java @@ -0,0 +1,36 @@ +/** + * © 2008 INA Service GmbH + */ +package net.pterodactylus.util.fcp.message; + +import net.pterodactylus.util.fcp.FcpMessage; +import net.pterodactylus.util.fcp.FcpUtils; + +/** + * A “GenerateSSK” message. This message tells the node to generate a new SSK + * key pair. + * + * @author David Roden + * @version $Id$ + */ +public class GenerateSSK extends FcpMessage { + + /** + * Creates a new “GenerateSSK” message. + */ + public GenerateSSK() { + this(FcpUtils.getUniqueIdentifier()); + } + + /** + * Creates a new “GenerateSSK” message with the given client identifier. + * + * @param clientIdentifier + * The client identifier + */ + public GenerateSSK(String clientIdentifier) { + super("GenerateSSK"); + setField("Identifier", clientIdentifier); + } + +} diff --git a/src/net/pterodactylus/util/fcp/message/NodeHello.java b/src/net/pterodactylus/util/fcp/message/NodeHello.java new file mode 100644 index 0000000..e704127 --- /dev/null +++ b/src/net/pterodactylus/util/fcp/message/NodeHello.java @@ -0,0 +1,207 @@ +/** + * © 2008 INA Service GmbH + */ +package net.pterodactylus.util.fcp.message; + +import net.pterodactylus.util.fcp.FcpMessage; + +/** + * Some convenience methods for parsing a “NodeHello” message from the node. + * + * @author David Roden + * @version $Id$ + */ +public class NodeHello extends BaseMessage { + + /** + * @param receivedMessage + * The received FCP message + */ + public NodeHello(FcpMessage receivedMessage) { + super(receivedMessage); + } + + /** + * Returns the build of the node. This may not be a number but also a string + * like “@custom@” in case you built the node yourself. + * + * @return The build of the node + */ + public String getBuild() { + return getField("Build"); + } + + /** + * Returns the build number of the node. This may not be a number but also a + * string like “@custom@” in case you built the node yourself. + * + * @return The build number of the node, or -1 if the build + * number could not be determined + */ + public int getBuildNumber() { + String build = getBuild(); + try { + return Integer.valueOf(build); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + return -1; + } + + /** + * Returns the number of compression codecs. + * + * @return The number of compression codecs + */ + public String getCompressionCodecs() { + return getField("CompressionCodecs"); + } + + /** + * Returns the number of compression codecs. + * + * @return The number of compression codecs, or -1 if the + * number of compression codecs could not be determined + */ + public int getCompressionCodecsNumber() { + String compressionCodecs = getCompressionCodecs(); + try { + return Integer.valueOf(compressionCodecs); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + return -1; + } + + /** + * Returns the unique connection identifier. + * + * @return The connection identifier + */ + public String getConnectionIdentifier() { + return getField("ConnectionIdentifier"); + } + + /** + * Returns the build of the external library file. + * + * @return The build of the external library file + */ + public String getExtBuild() { + return getField("ExtBuild"); + } + + /** + * Returns the build number of the external library file. + * + * @return The build number of the external library file, or -1 + * if the build number could not be determined + */ + public int getExtBuildNumber() { + String extBuild = getExtBuild(); + try { + return Integer.valueOf(extBuild); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + return -1; + } + + /** + * Returns the revision of the external library file. + * + * @return The revision of the external library file + */ + public String getExtRevision() { + return getField("ExtRevision"); + } + + /** + * Returns the revision number of the external library file. + * + * @return The revision number of the external library file, or + * -1 if the revision number could not be determined + */ + public int getExtRevisionNumber() { + String extRevision = getExtRevision(); + try { + return Integer.valueOf(extRevision); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + return -1; + } + + /** + * Returns the FCP version the node speaks. + * + * @return The FCP version the node speaks + */ + public String getFCPVersion() { + return getField("FCPVersion"); + } + + /** + * Returns the make of the node, e.g. “Fred” (freenet reference + * implementation). + * + * @return The make of the node + */ + public String getNode() { + return getField("Node"); + } + + /** + * Returns the language of the node as 2-letter code, e.g. “en” or “de”. + * + * @return The language of the node + */ + public String getNodeLanguage() { + return getField("NodeLanguage"); + } + + /** + * Returns the revision of the node. + * + * @return The revision of the node + */ + public String getRevision() { + return getField("Revision"); + } + + /** + * Returns the revision number of the node. + * + * @return The revision number of the node, or -1 if the + * revision number coult not be determined + */ + public int getRevisionNumber() { + String revision = getRevision(); + try { + return Integer.valueOf(revision); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + return -1; + } + + /** + * Returns whether the node is currently is testnet mode. + * + * @return true if the node is currently in testnet mode, + * false otherwise + */ + public boolean getTestnet() { + return Boolean.valueOf(getField("Testnet")); + } + + /** + * Returns the version of the node. + * + * @return The version of the node + */ + public String getVersion() { + return getField("Version"); + } + +} diff --git a/src/net/pterodactylus/util/fcp/message/package-info.java b/src/net/pterodactylus/util/fcp/message/package-info.java new file mode 100644 index 0000000..5426433 --- /dev/null +++ b/src/net/pterodactylus/util/fcp/message/package-info.java @@ -0,0 +1,4 @@ +/** + * Package that holds all the message types that are used in the communication with a Freenet Node. + */ +package net.pterodactylus.util.fcp.message; \ No newline at end of file -- 2.7.4