[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] [puppetor/gsoc2008] kill tabs in sourcecode as well as whitespace at the end of a line
a first step towards a consistent code style for puppetor. I will try
hard to follow it in the future :-)
---
src/org/torproject/puppetor/ClientApplication.java | 152 +-
src/org/torproject/puppetor/ClientEventType.java | 86 +-
src/org/torproject/puppetor/DirectoryNode.java | 54 +-
src/org/torproject/puppetor/Event.java | 54 +-
src/org/torproject/puppetor/EventListener.java | 16 +-
src/org/torproject/puppetor/EventManager.java | 402 ++--
src/org/torproject/puppetor/EventType.java | 14 +-
src/org/torproject/puppetor/HiddenService.java | 84 +-
.../puppetor/HiddenServiceEventType.java | 402 ++--
src/org/torproject/puppetor/Network.java | 1266 ++++++------
src/org/torproject/puppetor/NetworkFactory.java | 102 +-
src/org/torproject/puppetor/NodeEventType.java | 94 +-
src/org/torproject/puppetor/NodeState.java | 40 +-
src/org/torproject/puppetor/ProxyNode.java | 412 ++--
src/org/torproject/puppetor/PuppeTorException.java | 78 +-
src/org/torproject/puppetor/RouterNode.java | 68 +-
src/org/torproject/puppetor/ServerApplication.java | 72 +-
src/org/torproject/puppetor/ServerEventType.java | 48 +-
.../examples/AccessingPublicWebServerOverTor.java | 186 +-
...ccessingHiddenServiceOverPrivateTorNetwork.java | 206 +-
...AccessingHiddenServiceOverPublicTorNetwork.java | 238 ++--
...AdvertisingHiddenServiceToPublicTorNetwork.java | 168 +-
.../puppetor/impl/ClientApplicationImpl.java | 854 ++++----
.../puppetor/impl/DirectoryNodeImpl.java | 794 ++++----
src/org/torproject/puppetor/impl/EventImpl.java | 202 +-
.../torproject/puppetor/impl/EventManagerImpl.java | 1378 +++++++-------
.../puppetor/impl/HiddenServiceImpl.java | 282 ++--
src/org/torproject/puppetor/impl/NetworkImpl.java | 2084 ++++++++++----------
.../torproject/puppetor/impl/ProxyNodeImpl.java | 1396 +++++++-------
.../torproject/puppetor/impl/RouterNodeImpl.java | 746 ++++----
.../puppetor/impl/ServerApplicationImpl.java | 648 +++---
.../puppetor/rmi/AbstractMasterFactory.java | 101 +-
.../puppetor/rmi/AbstractSlaveFactory.java | 120 +-
src/org/torproject/puppetor/rmi/LocalMaster.java | 36 +-
.../torproject/puppetor/rmi/MasterConnector.java | 22 +-
src/org/torproject/puppetor/rmi/Network.java | 102 +-
.../puppetor/rmi/NetworkDescription.java | 6 +-
src/org/torproject/puppetor/rmi/RemoteMaster.java | 40 +-
src/org/torproject/puppetor/rmi/Slave.java | 58 +-
src/org/torproject/puppetor/rmi/Task.java | 44 +-
.../rmi/TaskExecutionNotSuccessfulException.java | 18 +-
src/org/torproject/puppetor/rmi/TaskResult.java | 46 +-
src/org/torproject/puppetor/rmi/Test.java | 34 +-
src/org/torproject/puppetor/rmi/TestExecutor.java | 162 +-
src/org/torproject/puppetor/rmi/TestResult.java | 2 +-
src/org/torproject/puppetor/rmi/TorInstance.java | 84 +-
.../rmi/execute/PuppeTorMasterProgram.java | 306 ++--
.../puppetor/rmi/execute/PuppeTorSlaveProgram.java | 349 ++--
.../puppetor/rmi/impl/AbstractTaskImpl.java | 88 +-
.../puppetor/rmi/impl/AbstractTestImpl.java | 64 +-
.../torproject/puppetor/rmi/impl/MasterImpl.java | 150 +-
.../puppetor/rmi/impl/MasterImplFactory.java | 62 +-
.../puppetor/rmi/impl/NetworkDescriptionImpl.java | 56 +-
.../torproject/puppetor/rmi/impl/NetworkImpl.java | 204 +-
.../torproject/puppetor/rmi/impl/SlaveImpl.java | 210 +-
.../puppetor/rmi/impl/SlaveImplFactory.java | 18 +-
.../puppetor/rmi/impl/TaskResultImpl.java | 76 +-
.../puppetor/rmi/impl/TestExecutorImpl.java | 998 +++++-----
.../puppetor/rmi/impl/TorInstanceImpl.java | 298 ++--
.../puppetor/rmi/tasks/AccessGoogleTask.java | 98 +-
.../puppetor/rmi/tasks/AddHiddenServiceTask.java | 156 +-
.../puppetor/rmi/tasks/BuildCircuitsTask.java | 44 +-
.../puppetor/rmi/tasks/ConfigureAsPrivateTask.java | 60 +-
.../rmi/tasks/CreateDirectoryAuthorityTask.java | 58 +-
.../puppetor/rmi/tasks/CreateNetworkTask.java | 28 +-
.../puppetor/rmi/tasks/CreateProxyTask.java | 60 +-
.../puppetor/rmi/tasks/CreateRouterTask.java | 60 +-
.../puppetor/rmi/tasks/ShutdownNodesTask.java | 38 +-
.../puppetor/rmi/tasks/StartNodesTask.java | 46 +-
.../puppetor/rmi/tasks/TerminateTask.java | 28 +-
.../tests/AccessGoogleOverPublicTorNetwork.java | 42 +-
...singHiddenServiceOverPrivateTorNetworkTest.java | 44 +-
.../puppetor/rmi/tests/TestRegistration.java | 40 +-
73 files changed, 8590 insertions(+), 8592 deletions(-)
diff --git a/src/org/torproject/puppetor/ClientApplication.java b/src/org/torproject/puppetor/ClientApplication.java
index a1b27a0..cb5ca63 100644
--- a/src/org/torproject/puppetor/ClientApplication.java
+++ b/src/org/torproject/puppetor/ClientApplication.java
@@ -16,85 +16,85 @@ package org.torproject.puppetor;
*/
public interface ClientApplication {
- /**
- * <p>
- * Performs one or more HTTP requests to a previously provided address and
- * port. All requests are performed by a thread in the background, so that
- * this method returns immediately. That thread will try for
- * <code>retries</code> times to make the request with a timeout of
- * <code>timeoutForEachRetry</code> milliseconds each. If an attempt is
- * not successful, the thread nevertheless waits for the timeout to expire
- * before performing the next attempt. If <code>stopOnSuccess</code> is
- * set to <code>true</code>, the thread will quit performing requests
- * immediately after the first successful request.
- * </p>
- *
- * <p>
- * For each sent request the application fires a
- * <event>ClientEventType.CLIENT_SENDING_REQUEST</code> event. On receiving
- * a reply it fires an event of type <code>ClientEventType.CLIENT_REPLY_RECEIVED</code>,
- * if a request is not successful or times out, a <code>ClientEventType.CLIENT_GAVE_UP_REQUEST</code>
- * event is fired. After all requests have been performed (either
- * successfully, or not) an event of type <code>ClientEventType.CLIENT_REQUESTS_PERFORMED</code>
- * is fired.
- * </p>
- *
- * TODO may this method only be invoked once?!
- *
- * @param retries
- * The number of retries that this client will perform. Must be
- * <code>1</code> or greater.
- * @param timeoutForEachRetry
- * The timeout for each request. If a request is not successful,
- * the thread nevertheless waits for the timeout to expire. Must
- * not be negative.
- * @param stopOnSuccess
- * If set to <code>true</code>, the client quits performing
- * requests after the first successful request, if <code>false</code>
- * it continues until all <code>retries</code> have been
- * processed.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract void startRequests(int retries, long timeoutForEachRetry,
- boolean stopOnSuccess);
+ /**
+ * <p>
+ * Performs one or more HTTP requests to a previously provided address and
+ * port. All requests are performed by a thread in the background, so that
+ * this method returns immediately. That thread will try for
+ * <code>retries</code> times to make the request with a timeout of
+ * <code>timeoutForEachRetry</code> milliseconds each. If an attempt is
+ * not successful, the thread nevertheless waits for the timeout to expire
+ * before performing the next attempt. If <code>stopOnSuccess</code> is
+ * set to <code>true</code>, the thread will quit performing requests
+ * immediately after the first successful request.
+ * </p>
+ *
+ * <p>
+ * For each sent request the application fires a
+ * <event>ClientEventType.CLIENT_SENDING_REQUEST</code> event. On receiving
+ * a reply it fires an event of type <code>ClientEventType.CLIENT_REPLY_RECEIVED</code>,
+ * if a request is not successful or times out, a <code>ClientEventType.CLIENT_GAVE_UP_REQUEST</code>
+ * event is fired. After all requests have been performed (either
+ * successfully, or not) an event of type <code>ClientEventType.CLIENT_REQUESTS_PERFORMED</code>
+ * is fired.
+ * </p>
+ *
+ * TODO may this method only be invoked once?!
+ *
+ * @param retries
+ * The number of retries that this client will perform. Must be
+ * <code>1</code> or greater.
+ * @param timeoutForEachRetry
+ * The timeout for each request. If a request is not successful,
+ * the thread nevertheless waits for the timeout to expire. Must
+ * not be negative.
+ * @param stopOnSuccess
+ * If set to <code>true</code>, the client quits performing
+ * requests after the first successful request, if <code>false</code>
+ * it continues until all <code>retries</code> have been
+ * processed.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract void startRequests(int retries, long timeoutForEachRetry,
+ boolean stopOnSuccess);
- /**
- * Stops all requests that are currently running.
- *
- * @throws IllegalStateException
- * Thrown if no requests have been started before.
- */
- public abstract void stopRequest();
+ /**
+ * Stops all requests that are currently running.
+ *
+ * @throws IllegalStateException
+ * Thrown if no requests have been started before.
+ */
+ public abstract void stopRequest();
- /**
- * Returns the name of this client.
- *
- * @return The name of this client.
- */
- public abstract String getClientApplicationName();
+ /**
+ * Returns the name of this client.
+ *
+ * @return The name of this client.
+ */
+ public abstract String getClientApplicationName();
- /**
- * Returns the SOCKS port of the local Tor node to which requests are sent.
- *
- * @return The SOCKS port of the local Tor node to which requests are sent.
- */
- public abstract int getSocksPort();
+ /**
+ * Returns the SOCKS port of the local Tor node to which requests are sent.
+ *
+ * @return The SOCKS port of the local Tor node to which requests are sent.
+ */
+ public abstract int getSocksPort();
- /**
- * Returns the target name for the requests sent by this client; can be
- * either a server name/address or an onion address.
- *
- * @return The target name for the requests sent by this client.
- */
- public abstract String getTargetName();
+ /**
+ * Returns the target name for the requests sent by this client; can be
+ * either a server name/address or an onion address.
+ *
+ * @return The target name for the requests sent by this client.
+ */
+ public abstract String getTargetName();
- /**
- * Returns the target port for the requests sent by this client; can be
- * either a server port or a virtual port of a hidden service.
- *
- * @return The target port for the requests sent by this client.
- */
- public abstract int getTargetPort();
+ /**
+ * Returns the target port for the requests sent by this client; can be
+ * either a server port or a virtual port of a hidden service.
+ *
+ * @return The target port for the requests sent by this client.
+ */
+ public abstract int getTargetPort();
}
diff --git a/src/org/torproject/puppetor/ClientEventType.java b/src/org/torproject/puppetor/ClientEventType.java
index 0b5c81e..a689713 100644
--- a/src/org/torproject/puppetor/ClientEventType.java
+++ b/src/org/torproject/puppetor/ClientEventType.java
@@ -12,53 +12,53 @@ package org.torproject.puppetor;
@SuppressWarnings("serial")
public class ClientEventType implements EventType {
- /**
- * String identifying the type of the event type.
- */
- String typeString;
+ /**
+ * String identifying the type of the event type.
+ */
+ String typeString;
- /**
- * Creates a new event type with the given type string.
- *
- * @param typeString
- * String identifying the type of the event type.
- */
- public ClientEventType(final String typeString) {
- this.typeString = typeString;
- }
+ /**
+ * Creates a new event type with the given type string.
+ *
+ * @param typeString
+ * String identifying the type of the event type.
+ */
+ public ClientEventType(final String typeString) {
+ this.typeString = typeString;
+ }
- public String getTypeName() {
- return typeString;
- }
+ public String getTypeName() {
+ return typeString;
+ }
- /**
- * The client application is sending a request; this event is fired
- * internally and not parsed from a log statement from Tor.
- */
- public static final ClientEventType CLIENT_SENDING_REQUEST =
- new ClientEventType("CLIENT_SENDING_REQUEST");
+ /**
+ * The client application is sending a request; this event is fired
+ * internally and not parsed from a log statement from Tor.
+ */
+ public static final ClientEventType CLIENT_SENDING_REQUEST =
+ new ClientEventType("CLIENT_SENDING_REQUEST");
- /**
- * The client application has received a reply to a previously sent request;
- * this event is fired internally and not parsed from a log statement from
- * Tor.
- */
- public static final ClientEventType CLIENT_REPLY_RECEIVED =
- new ClientEventType("CLIENT_REPLY_RECEIVED");
+ /**
+ * The client application has received a reply to a previously sent request;
+ * this event is fired internally and not parsed from a log statement from
+ * Tor.
+ */
+ public static final ClientEventType CLIENT_REPLY_RECEIVED =
+ new ClientEventType("CLIENT_REPLY_RECEIVED");
- /**
- * The client application has given up waiting for the reply to a previously
- * sent request; this event is fired internally and not parsed from a log
- * statement from Tor.
- */
- public static final ClientEventType CLIENT_GAVE_UP_REQUEST =
- new ClientEventType("CLIENT_GAVE_UP_REQUEST");
+ /**
+ * The client application has given up waiting for the reply to a previously
+ * sent request; this event is fired internally and not parsed from a log
+ * statement from Tor.
+ */
+ public static final ClientEventType CLIENT_GAVE_UP_REQUEST =
+ new ClientEventType("CLIENT_GAVE_UP_REQUEST");
- /**
- * The client application has completed a series of requests, whether they
- * were successful or not; this event is fired internally and not parsed
- * from a log statement from Tor.
- */
- public static final ClientEventType CLIENT_REQUESTS_PERFORMED =
- new ClientEventType("CLIENT_REQUESTS_PERFORMED");
+ /**
+ * The client application has completed a series of requests, whether they
+ * were successful or not; this event is fired internally and not parsed
+ * from a log statement from Tor.
+ */
+ public static final ClientEventType CLIENT_REQUESTS_PERFORMED =
+ new ClientEventType("CLIENT_REQUESTS_PERFORMED");
}
diff --git a/src/org/torproject/puppetor/DirectoryNode.java b/src/org/torproject/puppetor/DirectoryNode.java
index 41fa6a2..5d71f37 100644
--- a/src/org/torproject/puppetor/DirectoryNode.java
+++ b/src/org/torproject/puppetor/DirectoryNode.java
@@ -18,32 +18,32 @@ import java.util.Set;
*/
public interface DirectoryNode extends RouterNode {
- /**
- * Combines the fingerprint of this node to a <code>DirServer</code>
- * string that can be used to configure this or other nodes to use this node
- * as directory server.
- *
- * @return <code>DirServer</code> string to configure a node to use this
- * node as directory server.
- * @throws PuppeTorException
- * Thrown if a problem occurs when determining the fingerprint
- * of this node.
- */
- public abstract String getDirServerString() throws PuppeTorException;
+ /**
+ * Combines the fingerprint of this node to a <code>DirServer</code>
+ * string that can be used to configure this or other nodes to use this node
+ * as directory server.
+ *
+ * @return <code>DirServer</code> string to configure a node to use this
+ * node as directory server.
+ * @throws PuppeTorException
+ * Thrown if a problem occurs when determining the fingerprint
+ * of this node.
+ */
+ public abstract String getDirServerString() throws PuppeTorException;
- /**
- * Adds the given (possibly empty) set of onion router fingerprints to the
- * set of approved routers to confirm to directory clients, that the given
- * routers can be trusted. Changes are only stored locally and not written
- * to the <code>approved-routers</code> file to disk which will be done
- * when writing the configuration of this node.
- *
- * @param approvedRouters
- * The set of approved routers to be added. Each provided string
- * must be formatted as
- * <code>nickname 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed as parameter.
- */
- public void addApprovedRouters(Set<String> approvedRouters);
+ /**
+ * Adds the given (possibly empty) set of onion router fingerprints to the
+ * set of approved routers to confirm to directory clients, that the given
+ * routers can be trusted. Changes are only stored locally and not written
+ * to the <code>approved-routers</code> file to disk which will be done
+ * when writing the configuration of this node.
+ *
+ * @param approvedRouters
+ * The set of approved routers to be added. Each provided string
+ * must be formatted as
+ * <code>nickname 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed as parameter.
+ */
+ public void addApprovedRouters(Set<String> approvedRouters);
}
diff --git a/src/org/torproject/puppetor/Event.java b/src/org/torproject/puppetor/Event.java
index 03626b1..4b54af0 100644
--- a/src/org/torproject/puppetor/Event.java
+++ b/src/org/torproject/puppetor/Event.java
@@ -21,34 +21,34 @@ import java.io.Serializable;
*/
public interface Event extends Serializable {
- /**
- * Returns the name of the source of this event, which can be a Tor process
- * or a client/server application running as thread in the background.
- *
- * @return The event source.
- */
- public abstract String getSource();
+ /**
+ * Returns the name of the source of this event, which can be a Tor process
+ * or a client/server application running as thread in the background.
+ *
+ * @return The event source.
+ */
+ public abstract String getSource();
- /**
- * Returns the event type.
- *
- * @return The event type.
- */
- public abstract EventType getType();
+ /**
+ * Returns the event type.
+ *
+ * @return The event type.
+ */
+ public abstract EventType getType();
- /**
- * Returns the original message that lead to firing this event.
- *
- * @return The original message.
- */
- public abstract String getMessage();
+ /**
+ * Returns the original message that lead to firing this event.
+ *
+ * @return The original message.
+ */
+ public abstract String getMessage();
- /**
- * Returns the occurrence time of this event, which is either the parsed
- * time from a Tor log statement, or the current system time when a
- * client/server application fired this event.
- *
- * @return The occurrence time.
- */
- public abstract long getOccurrenceTime();
+ /**
+ * Returns the occurrence time of this event, which is either the parsed
+ * time from a Tor log statement, or the current system time when a
+ * client/server application fired this event.
+ *
+ * @return The occurrence time.
+ */
+ public abstract long getOccurrenceTime();
}
diff --git a/src/org/torproject/puppetor/EventListener.java b/src/org/torproject/puppetor/EventListener.java
index 099cfec..90d6a66 100644
--- a/src/org/torproject/puppetor/EventListener.java
+++ b/src/org/torproject/puppetor/EventListener.java
@@ -13,13 +13,13 @@ package org.torproject.puppetor;
*/
public interface EventListener {
- /**
- * Is invoked when an asynchronous event is fired by the source (or one of
- * the sources) for which this listener was registered.
- *
- * @param event
- * The event that was fired.
- */
- public void handleEvent(Event event);
+ /**
+ * Is invoked when an asynchronous event is fired by the source (or one of
+ * the sources) for which this listener was registered.
+ *
+ * @param event
+ * The event that was fired.
+ */
+ public void handleEvent(Event event);
}
diff --git a/src/org/torproject/puppetor/EventManager.java b/src/org/torproject/puppetor/EventManager.java
index eafb9c1..81a6e53 100644
--- a/src/org/torproject/puppetor/EventManager.java
+++ b/src/org/torproject/puppetor/EventManager.java
@@ -18,214 +18,214 @@ import java.util.List;
*/
public interface EventManager {
- /**
- * Registers the given <code>listener</code> as event listener for events
- * originating from the given <code>source</code>. This method returns a
- * list of all previously fired events by this source, so that each event
- * fired by this source is either included in the returned list or
- * signalized in a later invocation on the event listener, but not in both.
- * This prevents race conditions by eliminating the gap between registration
- * of an event handler and asking if an event has been fired before
- * registering.
- *
- * @param source
- * The name of the source of events that the listener is
- * interested in. May not be <code>null</code> and must be the
- * name of a previously created node, client, or server.
- * @param listener
- * The listener that wants to be notified about events from the
- * given <code>source</code>. If the <code>listener</code>
- * is already registered for the same <code>source</code>,
- * nothing happens, i.e. the <code>listener</code> will not
- * receive multiple invocations for the same event. May not be
- * <code>null</code>.
- * @return A list of all previously fired events for the given
- * <code>source</code>. If no event has been fired before, an
- * empty list is returned instead of <code>null</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed for either of the
- * parameters or if the <code>source</code> is unknown.
- */
- public abstract List<Event> addEventListener(String source,
- EventListener listener);
+ /**
+ * Registers the given <code>listener</code> as event listener for events
+ * originating from the given <code>source</code>. This method returns a
+ * list of all previously fired events by this source, so that each event
+ * fired by this source is either included in the returned list or
+ * signalized in a later invocation on the event listener, but not in both.
+ * This prevents race conditions by eliminating the gap between registration
+ * of an event handler and asking if an event has been fired before
+ * registering.
+ *
+ * @param source
+ * The name of the source of events that the listener is
+ * interested in. May not be <code>null</code> and must be the
+ * name of a previously created node, client, or server.
+ * @param listener
+ * The listener that wants to be notified about events from the
+ * given <code>source</code>. If the <code>listener</code>
+ * is already registered for the same <code>source</code>,
+ * nothing happens, i.e. the <code>listener</code> will not
+ * receive multiple invocations for the same event. May not be
+ * <code>null</code>.
+ * @return A list of all previously fired events for the given
+ * <code>source</code>. If no event has been fired before, an
+ * empty list is returned instead of <code>null</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed for either of the
+ * parameters or if the <code>source</code> is unknown.
+ */
+ public abstract List<Event> addEventListener(String source,
+ EventListener listener);
- /**
- * Registers the given <code>listener</code> as event listener for future
- * events originating from any source.
- *
- * @param listener
- * The listener that wants to be notified about events from the
- * given <code>source</code>. If the <code>listener</code>
- * is already registered for all sources, nothing happens, i.e.
- * the <code>listener</code> will not receive multiple
- * invocations for the same event. May not be <code>null</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed for the parameter.
- */
- public abstract void addEventListener(EventListener listener);
+ /**
+ * Registers the given <code>listener</code> as event listener for future
+ * events originating from any source.
+ *
+ * @param listener
+ * The listener that wants to be notified about events from the
+ * given <code>source</code>. If the <code>listener</code>
+ * is already registered for all sources, nothing happens, i.e.
+ * the <code>listener</code> will not receive multiple
+ * invocations for the same event. May not be <code>null</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed for the parameter.
+ */
+ public abstract void addEventListener(EventListener listener);
- /**
- * Returns the list of all previously observed events from the given
- * <code>source</code>.
- *
- * @param source
- * The source of the events that the invoking thread is
- * interested in. May not be <code>null</code> and must be the
- * name of a previously created node, client, or server.
- * @return List of all previously observed events from the given
- * <code>source</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed as parameter or if
- * the <code>source</code> is unknown.
- */
- public abstract List<Event> getEventHistory(String source);
+ /**
+ * Returns the list of all previously observed events from the given
+ * <code>source</code>.
+ *
+ * @param source
+ * The source of the events that the invoking thread is
+ * interested in. May not be <code>null</code> and must be the
+ * name of a previously created node, client, or server.
+ * @return List of all previously observed events from the given
+ * <code>source</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed as parameter or if
+ * the <code>source</code> is unknown.
+ */
+ public abstract List<Event> getEventHistory(String source);
- /**
- * Returns whether the given <code>eventType</code> has been observed from
- * the given <code>source</code> before, or not.
- *
- * @param source
- * The source of the event that the invoking thread is interested
- * in. May not be <code>null</code> and must be the name of a
- * previously created node, client, or server.
- * @param eventType
- * The event type that the invoking thread is interested in. May
- * not be <code>null</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed for either of the
- * parameters or if <code>source</code> is unknown.
- * @return <code>true</code> if the event has been observed from the
- * source before, <code>false</code> otherwise.
- */
- public abstract boolean hasEventOccured(String source, EventType eventType);
+ /**
+ * Returns whether the given <code>eventType</code> has been observed from
+ * the given <code>source</code> before, or not.
+ *
+ * @param source
+ * The source of the event that the invoking thread is interested
+ * in. May not be <code>null</code> and must be the name of a
+ * previously created node, client, or server.
+ * @param eventType
+ * The event type that the invoking thread is interested in. May
+ * not be <code>null</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed for either of the
+ * parameters or if <code>source</code> is unknown.
+ * @return <code>true</code> if the event has been observed from the
+ * source before, <code>false</code> otherwise.
+ */
+ public abstract boolean hasEventOccured(String source, EventType eventType);
- /**
- * Removes the given <code>listener</code> as event listener from all
- * previously registered sources. If this listener is not registered for any
- * source, nothing happens.
- *
- * @param listener
- * The listener that shall be removed from the list of registered
- * listeners. May not be <code>null</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed as parameter.
- */
- public abstract void removeEventListener(EventListener listener);
+ /**
+ * Removes the given <code>listener</code> as event listener from all
+ * previously registered sources. If this listener is not registered for any
+ * source, nothing happens.
+ *
+ * @param listener
+ * The listener that shall be removed from the list of registered
+ * listeners. May not be <code>null</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed as parameter.
+ */
+ public abstract void removeEventListener(EventListener listener);
- /**
- * Checks if the given <code>eventType</code> has been observed from the
- * given <code>source</code> before; if not, blocks the invoking thread
- * until the next event of this type is fired from that source. Note that
- * this method does not restrict waiting to a timeout, so that it could
- * potentially block forever!
- *
- * @param source
- * The source of the event that the invoking thread is willing to
- * wait for. May not be <code>null</code> and must be the name
- * of a previously created node, client, or server.
- * @param eventType
- * The event type that the invoking thread is willing to wait for
- * from the given <code>source</code>. May not be
- * <code>null</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed for either of the
- * parameters or if the <code>source</code> is unknown.
- */
- public abstract void waitForAnyOccurence(String source, EventType eventType);
+ /**
+ * Checks if the given <code>eventType</code> has been observed from the
+ * given <code>source</code> before; if not, blocks the invoking thread
+ * until the next event of this type is fired from that source. Note that
+ * this method does not restrict waiting to a timeout, so that it could
+ * potentially block forever!
+ *
+ * @param source
+ * The source of the event that the invoking thread is willing to
+ * wait for. May not be <code>null</code> and must be the name
+ * of a previously created node, client, or server.
+ * @param eventType
+ * The event type that the invoking thread is willing to wait for
+ * from the given <code>source</code>. May not be
+ * <code>null</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed for either of the
+ * parameters or if the <code>source</code> is unknown.
+ */
+ public abstract void waitForAnyOccurence(String source, EventType eventType);
- /**
- * Checks if the given <code>eventType</code> has been observed from the
- * given <code>source</code> before; if not, blocks the invoking thread
- * until the next event of this type is fired from that source or the given
- * timeout of <code>maximumTimeToWaitInMillis</code> milliseconds has
- * expired.
- *
- * @param source
- * The source of the event that the invoking thread is willing to
- * wait for. May not be <code>null</code> and must be the name
- * of a previously created node, client, or server.
- * @param eventType
- * The event type that the invoking thread is willing to wait for
- * from the given <code>source</code>. May not be
- * <code>null</code>.
- * @param maximumTimeToWaitInMillis
- * The maximum time to wait in milliseconds. A positive value or
- * zero restricts waiting to this time. If this value is
- * negative, we will wait potentially forever.
- * @return <code>true</code> if an event of the given type has been fired
- * by the <code>source</code> within the given timeout,
- * <code>false</code> otherwise.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is passed for either of the
- * parameters or if the <code>source</code> is unknown.
- */
- public abstract boolean waitForAnyOccurence(String source,
- EventType eventType, long maximumTimeToWaitInMillis);
+ /**
+ * Checks if the given <code>eventType</code> has been observed from the
+ * given <code>source</code> before; if not, blocks the invoking thread
+ * until the next event of this type is fired from that source or the given
+ * timeout of <code>maximumTimeToWaitInMillis</code> milliseconds has
+ * expired.
+ *
+ * @param source
+ * The source of the event that the invoking thread is willing to
+ * wait for. May not be <code>null</code> and must be the name
+ * of a previously created node, client, or server.
+ * @param eventType
+ * The event type that the invoking thread is willing to wait for
+ * from the given <code>source</code>. May not be
+ * <code>null</code>.
+ * @param maximumTimeToWaitInMillis
+ * The maximum time to wait in milliseconds. A positive value or
+ * zero restricts waiting to this time. If this value is
+ * negative, we will wait potentially forever.
+ * @return <code>true</code> if an event of the given type has been fired
+ * by the <code>source</code> within the given timeout,
+ * <code>false</code> otherwise.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is passed for either of the
+ * parameters or if the <code>source</code> is unknown.
+ */
+ public abstract boolean waitForAnyOccurence(String source,
+ EventType eventType, long maximumTimeToWaitInMillis);
- /**
- * Blocks the invoking thread until the next <code>event</code> is fired
- * from the given <code>source</code>. This method only waits for the
- * next occurence of an event, regardless of previous occurrences. Note that
- * this method does not restrict waiting to a timeout, so that it could
- * potentially block forever!
- *
- * @param source
- * The source of the event that the invoking thread is willing to
- * wait for. May not be <code>null</code> and must be the name
- * of a previously created node, client, or server.
- * @param eventType
- * The event type that the invoking thread is willing to wait for
- * from the given <code>source</code>. May not be
- * <code>null</code>.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed for either of the
- * parameters or if the <code>source</code> is unknown.
- */
- public abstract void waitForNextOccurence(String source, EventType eventType);
+ /**
+ * Blocks the invoking thread until the next <code>event</code> is fired
+ * from the given <code>source</code>. This method only waits for the
+ * next occurence of an event, regardless of previous occurrences. Note that
+ * this method does not restrict waiting to a timeout, so that it could
+ * potentially block forever!
+ *
+ * @param source
+ * The source of the event that the invoking thread is willing to
+ * wait for. May not be <code>null</code> and must be the name
+ * of a previously created node, client, or server.
+ * @param eventType
+ * The event type that the invoking thread is willing to wait for
+ * from the given <code>source</code>. May not be
+ * <code>null</code>.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> is passed for either of the
+ * parameters or if the <code>source</code> is unknown.
+ */
+ public abstract void waitForNextOccurence(String source, EventType eventType);
- /**
- * Blocks the invoking thread until the next <code>event</code> is fired
- * from the given <code>source</code> or the given timeout of
- * <code>maximumTimeToWaitInMillis</code> milliseconds has expired. This
- * method only waits for the next occurence of an event, regardless of
- * previous occurrences.
- *
- * @param source
- * The source of the event that the invoking thread is willing to
- * wait for. May not be <code>null</code> and must be the name
- * of a previously created node, client, or server.
- * @param eventType
- * The event type that the invoking thread is willing to wait for
- * from the given <code>source</code>. May not be
- * <code>null</code>.
- * @param maximumTimeToWaitInMillis
- * The maximum time to wait in milliseconds. A positive value or
- * zero restricts waiting to this time. If this value is
- * negative, we will wait potentially forever.
- * @return <code>true</code> if an event of the given type has been fired
- * by the <code>source</code> within the given timeout,
- * <code>false</code> otherwise.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is passed for either of the
- * parameters or if the <code>source</code> is unknown.
- */
- public abstract boolean waitForNextOccurence(String source,
- EventType eventType, long maximumTimeToWaitInMillis);
+ /**
+ * Blocks the invoking thread until the next <code>event</code> is fired
+ * from the given <code>source</code> or the given timeout of
+ * <code>maximumTimeToWaitInMillis</code> milliseconds has expired. This
+ * method only waits for the next occurence of an event, regardless of
+ * previous occurrences.
+ *
+ * @param source
+ * The source of the event that the invoking thread is willing to
+ * wait for. May not be <code>null</code> and must be the name
+ * of a previously created node, client, or server.
+ * @param eventType
+ * The event type that the invoking thread is willing to wait for
+ * from the given <code>source</code>. May not be
+ * <code>null</code>.
+ * @param maximumTimeToWaitInMillis
+ * The maximum time to wait in milliseconds. A positive value or
+ * zero restricts waiting to this time. If this value is
+ * negative, we will wait potentially forever.
+ * @return <code>true</code> if an event of the given type has been fired
+ * by the <code>source</code> within the given timeout,
+ * <code>false</code> otherwise.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is passed for either of the
+ * parameters or if the <code>source</code> is unknown.
+ */
+ public abstract boolean waitForNextOccurence(String source,
+ EventType eventType, long maximumTimeToWaitInMillis);
- /**
- * Registers a new event type by passing a pattern string that can be
- * applied to a regular expression when parsing Tor log statements. This is
- * useful for log statements that are only included in modified Tor
- * versions. Therefore, the event type may be an instance of a self-defined
- * class that implements <code>EventType</code>.
- *
- * @param patternString
- * The pattern string that will be used for parsing Tor log
- * statements; the syntax corresponds to java.util.regex.Pattern.
- * @param eventType
- * The event type of the event that will be fired when a log
- * statement was parsed that includes the given pattern.
- */
- public abstract void registerEventTypePattern(String patternString,
- EventType eventType);
+ /**
+ * Registers a new event type by passing a pattern string that can be
+ * applied to a regular expression when parsing Tor log statements. This is
+ * useful for log statements that are only included in modified Tor
+ * versions. Therefore, the event type may be an instance of a self-defined
+ * class that implements <code>EventType</code>.
+ *
+ * @param patternString
+ * The pattern string that will be used for parsing Tor log
+ * statements; the syntax corresponds to java.util.regex.Pattern.
+ * @param eventType
+ * The event type of the event that will be fired when a log
+ * statement was parsed that includes the given pattern.
+ */
+ public abstract void registerEventTypePattern(String patternString,
+ EventType eventType);
}
diff --git a/src/org/torproject/puppetor/EventType.java b/src/org/torproject/puppetor/EventType.java
index 4923984..ebfd6b0 100644
--- a/src/org/torproject/puppetor/EventType.java
+++ b/src/org/torproject/puppetor/EventType.java
@@ -16,11 +16,11 @@ import java.io.Serializable;
*/
public interface EventType extends Serializable {
- /**
- * Returns a string representation of the event type name for display
- * purposes.
- *
- * @return String representation of the event type name.
- */
- public abstract String getTypeName();
+ /**
+ * Returns a string representation of the event type name for display
+ * purposes.
+ *
+ * @return String representation of the event type name.
+ */
+ public abstract String getTypeName();
}
diff --git a/src/org/torproject/puppetor/HiddenService.java b/src/org/torproject/puppetor/HiddenService.java
index 26975fb..4a4381d 100644
--- a/src/org/torproject/puppetor/HiddenService.java
+++ b/src/org/torproject/puppetor/HiddenService.java
@@ -13,49 +13,49 @@ package org.torproject.puppetor;
*/
public interface HiddenService {
- /**
- * Determines the onion address for a previously added hidden service with
- * name <code>serviceName</code>. Requires that the node has been
- * started, i.e. is in state <code>NodeState.RUNNING</code>, and is
- * configured to provide this hidden service.
- *
- * @return The onion address string consisting of 16 base32 chars plus
- * ".onion" for hidden service versions 0 and 1 or 16 base32 chars
- * plus "." plus 24 base32 chars plus ".onion" for hidden service
- * version 2.
- * @throws IllegalArgumentException
- * Thrown if <code>null</code> or a zero-length string is
- * passed as parameter.
- * @throws IllegalStateException
- * Thrown if the node at which this hidden service is configured
- * is not in state <code>NodeState.RUNNING</code>.
- * @throws PuppeTorException
- * Thrown if the onion address of this hidden service could not
- * be read, which is also the case when the node's configuration
- * has not been written and the node has not been HUP'ed after
- * configuring the hidden service.
- */
- public abstract String determineOnionAddress() throws PuppeTorException;
+ /**
+ * Determines the onion address for a previously added hidden service with
+ * name <code>serviceName</code>. Requires that the node has been
+ * started, i.e. is in state <code>NodeState.RUNNING</code>, and is
+ * configured to provide this hidden service.
+ *
+ * @return The onion address string consisting of 16 base32 chars plus
+ * ".onion" for hidden service versions 0 and 1 or 16 base32 chars
+ * plus "." plus 24 base32 chars plus ".onion" for hidden service
+ * version 2.
+ * @throws IllegalArgumentException
+ * Thrown if <code>null</code> or a zero-length string is
+ * passed as parameter.
+ * @throws IllegalStateException
+ * Thrown if the node at which this hidden service is configured
+ * is not in state <code>NodeState.RUNNING</code>.
+ * @throws PuppeTorException
+ * Thrown if the onion address of this hidden service could not
+ * be read, which is also the case when the node's configuration
+ * has not been written and the node has not been HUP'ed after
+ * configuring the hidden service.
+ */
+ public abstract String determineOnionAddress() throws PuppeTorException;
- /**
- * Returns the name of the hidden service.
- *
- * @return The name of the hidden service.
- */
- public String getServiceName();
+ /**
+ * Returns the name of the hidden service.
+ *
+ * @return The name of the hidden service.
+ */
+ public String getServiceName();
- /**
- * Returns the port on which the service listens for requests.
- *
- * @return The port on which the service listens for requests.
- */
- public int getServicePort();
+ /**
+ * Returns the port on which the service listens for requests.
+ *
+ * @return The port on which the service listens for requests.
+ */
+ public int getServicePort();
- /**
- * Returns the virtual port that this hidden service runs on as it is
- * announced to clients.
- *
- * @return The virtual port of this hidden service.
- */
- public int getVirtualPort();
+ /**
+ * Returns the virtual port that this hidden service runs on as it is
+ * announced to clients.
+ *
+ * @return The virtual port of this hidden service.
+ */
+ public int getVirtualPort();
}
diff --git a/src/org/torproject/puppetor/HiddenServiceEventType.java b/src/org/torproject/puppetor/HiddenServiceEventType.java
index 5d29f1f..50b7211 100644
--- a/src/org/torproject/puppetor/HiddenServiceEventType.java
+++ b/src/org/torproject/puppetor/HiddenServiceEventType.java
@@ -12,204 +12,204 @@ package org.torproject.puppetor;
@SuppressWarnings("serial")
public class HiddenServiceEventType implements EventType {
- /**
- * String identifying the type of the event type.
- */
- String typeString;
-
- /**
- * Creates a new event type with the given type string.
- *
- * @param typeString
- * String identifying the type of the event type.
- */
- public HiddenServiceEventType(final String typeString) {
- this.typeString = typeString;
- }
-
- public String getTypeName() {
- return typeString;
- }
-
- /**
- * Alice has received an onion request; this event is parsed from a log
- * statement in connection_ap_handshake_rewrite_and_attach().
- */
- public static final HiddenServiceEventType ALICE_ONION_REQUEST_RECEIVED =
- new HiddenServiceEventType("ALICE_ONION_REQUEST_RECEIVED");
-
- /**
- * Alice sends a fetch request for a hidden service descriptor to a
- * directory server; this event is parsed from a log statement in
- * rend_client_refetch_renddesc().
- */
- public static final HiddenServiceEventType ALICE_SENDING_FETCH_DESC =
- new HiddenServiceEventType("ALICE_SENDING_FETCH_DESC");
-
- /**
- * Alice receives a reply to a previous fetch request for a hidden service
- * descriptors from a directory server; this event is parsed from a log
- * statement in connection_dir_client_reached_eof().
- */
- public static final HiddenServiceEventType ALICE_DESC_FETCHED_RECEIVED =
- new HiddenServiceEventType("ALICE_DESC_FETCHED_RECEIVED");
-
- /**
- * Alice has built a circuit to a rendezvous point and sends an
- * ESTABLISH_RENDEZVOUS cell; this event is parsed from a log statement in
- * rend_client_send_establish_rendezvous().
- */
- public static final HiddenServiceEventType ALICE_BUILT_REND_CIRC_SENDING_ESTABLISH_RENDEZVOUS =
- new HiddenServiceEventType(
- "ALICE_BUILT_REND_CIRC_SENDING_ESTABLISH_RENDEZVOUS");
-
- /**
- * Alice receives a RENDEZVOUS_ESTABLISHED cell from a rendezvous point;
- * this event is parsed from a log statement in
- * rend_client_rendezvous_acked().
- */
- public static final HiddenServiceEventType ALICE_RENDEZVOUS_ESTABLISHED_RECEIVED =
- new HiddenServiceEventType("ALICE_RENDEZVOUS_ESTABLISHED_RECEIVED");
-
- /**
- * Alice has built a circuit to an introduction point (which does not
- * automatically lead to sending an INTRODUCE1 cell, because the rendezvous
- * circuit might not be ready); this event is parsed from a log statement in
- * rend_client_introcirc_has_opened().
- */
- public static final HiddenServiceEventType ALICE_BUILT_INTRO_CIRC =
- new HiddenServiceEventType("ALICE_BUILT_INTRO_CIRC");
-
- /**
- * Alice sends an INTRODUCE1 cell to an introduction point; this event is
- * parsed from a log statement in rend_client_send_introduction().
- */
- public static final HiddenServiceEventType ALICE_SENDING_INTRODUCE1 =
- new HiddenServiceEventType("ALICE_SENDING_INTRODUCE1");
-
- /**
- * Alice has received an INTRODUCE_ACK cell as an acknowledgement to a
- * previously sent INTRODUCE1 cell; this event is parsed from a log
- * statement in rend_client_introduction_acked().
- */
- public static final HiddenServiceEventType ALICE_INTRODUCE_ACK_RECEIVED =
- new HiddenServiceEventType("ALICE_INTRODUCE_ACK_RECEIVED");
-
- /**
- * Alice has received a RENDEZVOUS2 cell and can now open an application
- * connection to the client; this event is parsed from a log statement in
- * rend_client_receive_rendezvous().
- */
- public static final HiddenServiceEventType ALICE_RENDEZVOUS2_RECEIVED_APP_CONN_OPENED =
- new HiddenServiceEventType(
- "ALICE_RENDEZVOUS2_RECEIVED_APP_CONN_OPENED");
-
- /**
- * Bob has built a circuit to an introduction point and sends an
- * ESTABLISH_INTRO cell; this event is parsed from a log statement in
- * rend_service_intro_has_opened().
- */
- public static final HiddenServiceEventType BOB_BUILT_INTRO_CIRC_SENDING_ESTABLISH_INTRO =
- new HiddenServiceEventType(
- "BOB_BUILT_INTRO_CIRC_SENDING_ESTABLISH_INTRO");
-
- /**
- * Bob has received an INTRO_ESTABLISHED cell, i.e. a node has confirmed to
- * work as introduction point; this event is parsed from a log statement in
- * rend_service_intro_established().
- */
- public static final HiddenServiceEventType BOB_INTRO_ESTABLISHED_RECEIVED =
- new HiddenServiceEventType("BOB_INTRO_ESTABLISHED_RECEIVED");
-
- /**
- * Bob posts a hidden service descriptor to the directory servers; this
- * event is parsed from a log statement in upload_service_descriptor().
- */
- public static final HiddenServiceEventType BOB_SENDING_PUBLISH_DESC =
- new HiddenServiceEventType("BOB_SENDING_PUBLISH_DESC");
-
- /**
- * Bob received a response from a directory server to a previous publish
- * request; this event is parsed from a log statement in
- * connection_dir_client_reached_eof().
- */
- public static final HiddenServiceEventType BOB_DESC_PUBLISHED_RECEIVED =
- new HiddenServiceEventType("BOB_DESC_PUBLISHED_RECEIVED");
-
- /**
- * Bob has received an INTRODUCE2 cell, i.e. a node wants to establish a
- * connection, and will now try to establish a circuit to the client's
- * rendezvous point; this event is parsed from a log statement in
- * rend_service_introduce().
- */
- public static final HiddenServiceEventType BOB_INTRODUCE2_RECEIVED =
- new HiddenServiceEventType("BOB_INTRODUCE2_RECEIVED");
-
- /**
- * Bob has built a circuit to a rendezvous point and sends a RENDEZVOUS1
- * cell; this event is parsed from a log statement in
- * rend_service_rendezvous_has_opened().
- */
- public static final HiddenServiceEventType BOB_BUILT_REND_CIRC_SENDING_RENDEZVOUS1 =
- new HiddenServiceEventType(
- "BOB_BUILT_REND_CIRC_SENDING_RENDEZVOUS1");
-
- /**
- * Bob opens a connection to the actual hidden server; this event is parsed
- * from a log statement in connection_exit_begin_conn().
- */
- public static final HiddenServiceEventType BOB_APP_CONN_OPENED =
- new HiddenServiceEventType("BOB_APP_CONN_OPENED");
-
- /**
- * The directory server has received a descriptor post request; this event
- * is parsed from a log statement in directory_handle_command_post().
- */
- public static final HiddenServiceEventType DIR_PUBLISH_DESC_RECEIVED =
- new HiddenServiceEventType("DIR_PUBLISH_DESC_RECEIVED");
-
- /**
- * The directory server has received a descriptor fetch request; this event
- * is parsed from a log statement in directory_handle_command_get().
- */
- public static final HiddenServiceEventType DIR_FETCH_DESC_RECEIVED =
- new HiddenServiceEventType("DIR_FETCH_DESC_RECEIVED");
-
- /**
- * The node received an ESTABLISH_INTRO cell, i.e. was requested to work as
- * introduction point, and replies with an INTRO_ESTABLISHED cell; this
- * event is parsed from a log statement in rend_mid_establish_intro().
- */
- public static final HiddenServiceEventType IPO_RECEIVED_ESTABLISH_INTRO_SENDING_INTRO_ESTABLISHED =
- new HiddenServiceEventType(
- "IPO_RECEIVED_ESTABLISH_INTRO_SENDING_INTRO_ESTABLISHED");
-
- /**
- * The introduction point received an INTRODUCE1 cell and reacts by sending
- * an INTRODUCE2 cell to Bob and an INTRODUCE_ACK cell to Alice; this event
- * is parsed from a log statement in rend_mid_introduce().
- */
- public static final HiddenServiceEventType IPO_RECEIVED_INTRODUCE1_SENDING_INTRODUCE2_AND_INTRODUCE_ACK =
- new HiddenServiceEventType(
- "IPO_RECEIVED_INTRODUCE1_SENDING_INTRODUCE2_AND_INTRODUCE_ACK");
-
- /**
- * The node received an ESTABLISH_RENDEZVOUS cell, i.e. was requested to
- * work as rendezvous point, and replies with a RENDEZVOUS_ESTABLISHED cell;
- * this event is parsed from a log statement in
- * rend_mid_establish_rendezvous().
- */
- public static final HiddenServiceEventType RPO_RECEIVED_ESTABLISH_RENDEZVOUS_SENDING_RENDEZVOUS_ESTABLISHED =
- new HiddenServiceEventType(
- "RPO_RECEIVED_ESTABLISH_RENDEZVOUS_SENDING_RENDEZVOUS_ESTABLISHED");
-
- /**
- * The rendezvous point received a RENDEZVOUS1 cell and reacts by sending a
- * RENDEZVOUS2 cell to Alice; this event is parsed from a log statement in
- * rend_mid_rendezvous().
- */
- public static final HiddenServiceEventType RPO_RECEIVING_RENDEZVOUS1_SENDING_RENDEZVOUS2 =
- new HiddenServiceEventType(
- "RPO_RECEIVING_RENDEZVOUS1_SENDING_RENDEZVOUS2");
-
-}
\ No newline at end of file
+ /**
+ * String identifying the type of the event type.
+ */
+ String typeString;
+
+ /**
+ * Creates a new event type with the given type string.
+ *
+ * @param typeString
+ * String identifying the type of the event type.
+ */
+ public HiddenServiceEventType(final String typeString) {
+ this.typeString = typeString;
+ }
+
+ public String getTypeName() {
+ return typeString;
+ }
+
+ /**
+ * Alice has received an onion request; this event is parsed from a log
+ * statement in connection_ap_handshake_rewrite_and_attach().
+ */
+ public static final HiddenServiceEventType ALICE_ONION_REQUEST_RECEIVED =
+ new HiddenServiceEventType("ALICE_ONION_REQUEST_RECEIVED");
+
+ /**
+ * Alice sends a fetch request for a hidden service descriptor to a
+ * directory server; this event is parsed from a log statement in
+ * rend_client_refetch_renddesc().
+ */
+ public static final HiddenServiceEventType ALICE_SENDING_FETCH_DESC =
+ new HiddenServiceEventType("ALICE_SENDING_FETCH_DESC");
+
+ /**
+ * Alice receives a reply to a previous fetch request for a hidden service
+ * descriptors from a directory server; this event is parsed from a log
+ * statement in connection_dir_client_reached_eof().
+ */
+ public static final HiddenServiceEventType ALICE_DESC_FETCHED_RECEIVED =
+ new HiddenServiceEventType("ALICE_DESC_FETCHED_RECEIVED");
+
+ /**
+ * Alice has built a circuit to a rendezvous point and sends an
+ * ESTABLISH_RENDEZVOUS cell; this event is parsed from a log statement in
+ * rend_client_send_establish_rendezvous().
+ */
+ public static final HiddenServiceEventType ALICE_BUILT_REND_CIRC_SENDING_ESTABLISH_RENDEZVOUS =
+ new HiddenServiceEventType(
+ "ALICE_BUILT_REND_CIRC_SENDING_ESTABLISH_RENDEZVOUS");
+
+ /**
+ * Alice receives a RENDEZVOUS_ESTABLISHED cell from a rendezvous point;
+ * this event is parsed from a log statement in
+ * rend_client_rendezvous_acked().
+ */
+ public static final HiddenServiceEventType ALICE_RENDEZVOUS_ESTABLISHED_RECEIVED =
+ new HiddenServiceEventType("ALICE_RENDEZVOUS_ESTABLISHED_RECEIVED");
+
+ /**
+ * Alice has built a circuit to an introduction point (which does not
+ * automatically lead to sending an INTRODUCE1 cell, because the rendezvous
+ * circuit might not be ready); this event is parsed from a log statement in
+ * rend_client_introcirc_has_opened().
+ */
+ public static final HiddenServiceEventType ALICE_BUILT_INTRO_CIRC =
+ new HiddenServiceEventType("ALICE_BUILT_INTRO_CIRC");
+
+ /**
+ * Alice sends an INTRODUCE1 cell to an introduction point; this event is
+ * parsed from a log statement in rend_client_send_introduction().
+ */
+ public static final HiddenServiceEventType ALICE_SENDING_INTRODUCE1 =
+ new HiddenServiceEventType("ALICE_SENDING_INTRODUCE1");
+
+ /**
+ * Alice has received an INTRODUCE_ACK cell as an acknowledgement to a
+ * previously sent INTRODUCE1 cell; this event is parsed from a log
+ * statement in rend_client_introduction_acked().
+ */
+ public static final HiddenServiceEventType ALICE_INTRODUCE_ACK_RECEIVED =
+ new HiddenServiceEventType("ALICE_INTRODUCE_ACK_RECEIVED");
+
+ /**
+ * Alice has received a RENDEZVOUS2 cell and can now open an application
+ * connection to the client; this event is parsed from a log statement in
+ * rend_client_receive_rendezvous().
+ */
+ public static final HiddenServiceEventType ALICE_RENDEZVOUS2_RECEIVED_APP_CONN_OPENED =
+ new HiddenServiceEventType(
+ "ALICE_RENDEZVOUS2_RECEIVED_APP_CONN_OPENED");
+
+ /**
+ * Bob has built a circuit to an introduction point and sends an
+ * ESTABLISH_INTRO cell; this event is parsed from a log statement in
+ * rend_service_intro_has_opened().
+ */
+ public static final HiddenServiceEventType BOB_BUILT_INTRO_CIRC_SENDING_ESTABLISH_INTRO =
+ new HiddenServiceEventType(
+ "BOB_BUILT_INTRO_CIRC_SENDING_ESTABLISH_INTRO");
+
+ /**
+ * Bob has received an INTRO_ESTABLISHED cell, i.e. a node has confirmed to
+ * work as introduction point; this event is parsed from a log statement in
+ * rend_service_intro_established().
+ */
+ public static final HiddenServiceEventType BOB_INTRO_ESTABLISHED_RECEIVED =
+ new HiddenServiceEventType("BOB_INTRO_ESTABLISHED_RECEIVED");
+
+ /**
+ * Bob posts a hidden service descriptor to the directory servers; this
+ * event is parsed from a log statement in upload_service_descriptor().
+ */
+ public static final HiddenServiceEventType BOB_SENDING_PUBLISH_DESC =
+ new HiddenServiceEventType("BOB_SENDING_PUBLISH_DESC");
+
+ /**
+ * Bob received a response from a directory server to a previous publish
+ * request; this event is parsed from a log statement in
+ * connection_dir_client_reached_eof().
+ */
+ public static final HiddenServiceEventType BOB_DESC_PUBLISHED_RECEIVED =
+ new HiddenServiceEventType("BOB_DESC_PUBLISHED_RECEIVED");
+
+ /**
+ * Bob has received an INTRODUCE2 cell, i.e. a node wants to establish a
+ * connection, and will now try to establish a circuit to the client's
+ * rendezvous point; this event is parsed from a log statement in
+ * rend_service_introduce().
+ */
+ public static final HiddenServiceEventType BOB_INTRODUCE2_RECEIVED =
+ new HiddenServiceEventType("BOB_INTRODUCE2_RECEIVED");
+
+ /**
+ * Bob has built a circuit to a rendezvous point and sends a RENDEZVOUS1
+ * cell; this event is parsed from a log statement in
+ * rend_service_rendezvous_has_opened().
+ */
+ public static final HiddenServiceEventType BOB_BUILT_REND_CIRC_SENDING_RENDEZVOUS1 =
+ new HiddenServiceEventType(
+ "BOB_BUILT_REND_CIRC_SENDING_RENDEZVOUS1");
+
+ /**
+ * Bob opens a connection to the actual hidden server; this event is parsed
+ * from a log statement in connection_exit_begin_conn().
+ */
+ public static final HiddenServiceEventType BOB_APP_CONN_OPENED =
+ new HiddenServiceEventType("BOB_APP_CONN_OPENED");
+
+ /**
+ * The directory server has received a descriptor post request; this event
+ * is parsed from a log statement in directory_handle_command_post().
+ */
+ public static final HiddenServiceEventType DIR_PUBLISH_DESC_RECEIVED =
+ new HiddenServiceEventType("DIR_PUBLISH_DESC_RECEIVED");
+
+ /**
+ * The directory server has received a descriptor fetch request; this event
+ * is parsed from a log statement in directory_handle_command_get().
+ */
+ public static final HiddenServiceEventType DIR_FETCH_DESC_RECEIVED =
+ new HiddenServiceEventType("DIR_FETCH_DESC_RECEIVED");
+
+ /**
+ * The node received an ESTABLISH_INTRO cell, i.e. was requested to work as
+ * introduction point, and replies with an INTRO_ESTABLISHED cell; this
+ * event is parsed from a log statement in rend_mid_establish_intro().
+ */
+ public static final HiddenServiceEventType IPO_RECEIVED_ESTABLISH_INTRO_SENDING_INTRO_ESTABLISHED =
+ new HiddenServiceEventType(
+ "IPO_RECEIVED_ESTABLISH_INTRO_SENDING_INTRO_ESTABLISHED");
+
+ /**
+ * The introduction point received an INTRODUCE1 cell and reacts by sending
+ * an INTRODUCE2 cell to Bob and an INTRODUCE_ACK cell to Alice; this event
+ * is parsed from a log statement in rend_mid_introduce().
+ */
+ public static final HiddenServiceEventType IPO_RECEIVED_INTRODUCE1_SENDING_INTRODUCE2_AND_INTRODUCE_ACK =
+ new HiddenServiceEventType(
+ "IPO_RECEIVED_INTRODUCE1_SENDING_INTRODUCE2_AND_INTRODUCE_ACK");
+
+ /**
+ * The node received an ESTABLISH_RENDEZVOUS cell, i.e. was requested to
+ * work as rendezvous point, and replies with a RENDEZVOUS_ESTABLISHED cell;
+ * this event is parsed from a log statement in
+ * rend_mid_establish_rendezvous().
+ */
+ public static final HiddenServiceEventType RPO_RECEIVED_ESTABLISH_RENDEZVOUS_SENDING_RENDEZVOUS_ESTABLISHED =
+ new HiddenServiceEventType(
+ "RPO_RECEIVED_ESTABLISH_RENDEZVOUS_SENDING_RENDEZVOUS_ESTABLISHED");
+
+ /**
+ * The rendezvous point received a RENDEZVOUS1 cell and reacts by sending a
+ * RENDEZVOUS2 cell to Alice; this event is parsed from a log statement in
+ * rend_mid_rendezvous().
+ */
+ public static final HiddenServiceEventType RPO_RECEIVING_RENDEZVOUS1_SENDING_RENDEZVOUS2 =
+ new HiddenServiceEventType(
+ "RPO_RECEIVING_RENDEZVOUS1_SENDING_RENDEZVOUS2");
+
+}
diff --git a/src/org/torproject/puppetor/Network.java b/src/org/torproject/puppetor/Network.java
index 743c67c..ea8456d 100644
--- a/src/org/torproject/puppetor/Network.java
+++ b/src/org/torproject/puppetor/Network.java
@@ -20,638 +20,638 @@ import java.util.Map;
*/
public interface Network {
- /**
- * <p>
- * Configures this network as private Tor network by exchanging directory
- * strings and router fingerprints between the nodes of this network.
- * Afterwards, the nodes will be able to run a private Tor network,
- * separated from public directory servers and onion routers.
- * </p>
- *
- * <p>
- * The configuration is done in two steps:
- * <ol>
- * <li>Directory strings of directory nodes are added to the configurations
- * of all nodes in the other network.</li>
- * <li>Router fingerprints of all router and directory nodes are added to
- * the <code>approved-routers</code> files of the directory nodes.</li>
- * </ol>
- * </p>
- *
- * <p>
- * This operation may be invoked in any state of the contained nodes.
- * However, a network that does not have directory nodes of its own but
- * relies on directory nodes of a merged network <b>should not be started
- * before being configured as private network!</b> Otherwise it would
- * connect to the public Tor network before being merged with the other
- * private Tor network. However, it may also be invoked at a later time,
- * e.g. to admit new nodes.
- * </p>
- *
- * <p>
- * This operation does not write any configurations to disk and neither
- * starts a nodes nor sends HUP signals to running nodes. These operations
- * are left to the application, so that they have more control over the
- * network behavior.
- * </p>
- *
- * <p>
- * Applications need to ensure that there are enough directory nodes (2) and
- * router nodes (3) in the network to allow normal operation.
- * </p>
- *
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while determining the nodes'
- * fingerprints.
- */
- public abstract void configureAsPrivateNetwork() throws PuppeTorException;
-
- /**
- * XXX document properly -SH
- */
- public void configureAsPartOfPrivateNetwork(
- List<String> authorizedDirectoriesFingerprints);
-
-
- /**
- * Creates a new client application, but does not yet perform a request.
- *
- * @param clientApplicationName
- * The name for this client application, which is used for
- * logging purposes and as event source. May neither be
- * <code>null</code> or a zero-length string. The name needs to
- * be unique in this network.
- * @param targetAddress
- * The target for requests sent by this client application. Can
- * be a publicly available URL or an onion address. May neither
- * be <code>null</code> or a zero-length string.
- * @param targetPort
- * The TCP port for requests sent by this client application. If
- * the target address is an onion address, this port is the
- * virtual port that the hidden service has announced. May not be
- * negative or greater than 65535.
- * @param socksPort
- * The TCP port on which a local Tor process is waiting for
- * incoming SOCKS requests. May not be negative or greater than
- * 65535.
- * @return Reference to the created client application.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract ClientApplication createClient(
- String clientApplicationName, String targetAddress, int targetPort,
- int socksPort);
-
- /**
- * Creates a new directory node with automatically assigned ports and adds
- * it to the network, but does not yet write its configuration to disk or
- * start the corresponding Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @return Reference to the created directory node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given as node name.
- */
- public abstract DirectoryNode createDirectory(String nodeName);
-
- /**
- * Creates a new directory node with automatically assigned ports that will
- * listen on the given IP address and adds it to the network, but does not
- * yet write its configuration to disk or start the corresponding Tor
- * process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @param serverIpAddress
- * The IP address on which the node will listen. Must be a valid
- * IP v4 address in dotted decimal notation. May not be
- * <code>null</code>.
- * @return Reference to the created directory node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given as node name.
- */
- public abstract DirectoryNode createDirectory(String nodeName,
- String serverIpAddress);
-
- /**
- * Creates a new directory node and adds it to the network, but does not yet
- * write its configuration to disk or start the corresponding Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @param controlPort
- * The TCP port on which the corresponding Tor process will wait
- * for a controller. May not be negative or greater than 65535.
- * @param socksPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming SOCKS requests. May not be negative or greater
- * than 65535.
- * @param orPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming requests from other onion routers. May not be
- * negative or greater than 65535.
- * @param dirPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming directory requests. May not be negative or
- * greater than 65535.
- * @return Reference to the created directory node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract DirectoryNode createDirectory(String nodeName,
- int controlPort, int socksPort, int orPort, int dirPort);
-
- /**
- * Creates a new directory node that will listen on the given IP address and
- * adds it to the network, but does not yet write its configuration to disk
- * or start the corresponding Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @param controlPort
- * The TCP port on which the corresponding Tor process will wait
- * for a controller. May not be negative or greater than 65535.
- * @param socksPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming SOCKS requests. May not be negative or greater
- * than 65535.
- * @param orPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming requests from other onion routers. May not be
- * negative or greater than 65535.
- * @param dirPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming directory requests. May not be negative or
- * greater than 65535.
- * @param serverIpAddress
- * The IP address on which the node will listen. Must be a valid
- * IP v4 address in dotted decimal notation. May not be
- * <code>null</code>.
- * @return Reference to the created directory node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract DirectoryNode createDirectory(String nodeName,
- int controlPort, int socksPort, int orPort, int dirPort,
- String serverIpAddress);
-
- /**
- * Creates a new <code>ProxyNode</code> with automatically assigned ports
- * and adds it to the network, but does not yet write its configuration to
- * disk or start the corresponding Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, and as event source. May
- * neither be <code>null</code> or have zero or more than 19
- * alpha-numeric characters. The node name needs to be unique in
- * this network.
- * @return Reference to the created proxy node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given as node name.
- */
- public abstract ProxyNode createProxy(String nodeName);
-
- /**
- * Creates a new <code>ProxyNode</code> and adds it to the network, but
- * does not yet write its configuration to disk or start the corresponding
- * Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, and as event source. May
- * neither be <code>null</code> or have zero or more than 19
- * alpha-numeric characters. The node name needs to be unique in
- * this network.
- * @param controlPort
- * The TCP port on which the corresponding Tor process will wait
- * for a controller. May not be negative or greater than 65535.
- * @param socksPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming SOCKS requests. May not be negative or greater
- * than 65535.
- * @return Reference to the created proxy node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract ProxyNode createProxy(String nodeName, int controlPort,
- int socksPort);
-
- /**
- * Creates a new <code>RouterNode</code> with automatically assigned ports
- * and adds it to the network, but does not yet write its configuration to
- * disk or start the corresponding Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @return Reference to the created router node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given as node name.
- */
- public abstract RouterNode createRouter(String nodeName);
-
- /**
- * Creates a new <code>RouterNode</code> and adds it to the network, but
- * does not yet write its configuration to disk or start the corresponding
- * Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @param controlPort
- * The TCP port on which the corresponding Tor process will wait
- * for a controller. May not be negative or greater than 65535.
- * @param socksPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming SOCKS requests. May not be negative or greater
- * than 65535.
- * @param orPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming requests from other onion routers. May not be
- * negative or greater than 65535.
- * @param dirPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming directory requests which in fact are requests for
- * the mirrored directory. May not be negative or greater than
- * 65535.
- * @return Reference to the created router node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract RouterNode createRouter(String nodeName, int controlPort,
- int socksPort, int orPort, int dirPort);
-
- /**
- * Creates a new <code>RouterNode</code> with automatically assigned ports
- * that will listen on the given IP address and adds it to the network, but
- * does not yet write its configuration to disk or start the corresponding
- * Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @param serverIpAddress
- * The IP address on which the node will listen. Must be a valid
- * IP v4 address in dotted decimal notation. May not be
- * <code>null</code>.
- * @return Reference to the created router node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given as node name.
- */
- public abstract RouterNode createRouter(String nodeName,
- String serverIpAddress);
-
- /**
- * Creates a new <code>RouterNode</code> that will listen on the given IP
- * address and adds it to the network, but does not yet write its
- * configuration to disk or start the corresponding Tor process.
- *
- * @param nodeName
- * The name for this node, which is used as name for the working
- * directory, for logging purposes, as node nickname, and as
- * event source. May neither be <code>null</code> or have zero
- * or more than 19 alpha-numeric characters. The node name needs
- * to be unique in this network.
- * @param controlPort
- * The TCP port on which the corresponding Tor process will wait
- * for a controller. May not be negative or greater than 65535.
- * @param socksPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming SOCKS requests. May not be negative or greater
- * than 65535.
- * @param orPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming requests from other onion routers. May not be
- * negative or greater than 65535.
- * @param dirPort
- * The TCP port on which the corresponding Tor process will wait
- * for incoming directory requests which in fact are requests for
- * the mirrored directory. May not be negative or greater than
- * 65535.
- * @param serverIpAddress
- * The IP address on which the node will listen. Must be a valid
- * IP v4 address in dotted decimal notation. May not be
- * <code>null</code>.
- * @return Reference to the created router node.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract RouterNode createRouter(String nodeName, int controlPort,
- int socksPort, int orPort, int dirPort, String serverIpAddress);
-
- /**
- * Creates a new <code>ServerApplication</code> with automatically
- * assigned ports, but does not start listening for incoming requests.
- *
- * @param serverApplicationName
- * The name for this server application, which is used for
- * logging purposes and as event source. May neither be
- * <code>null</code> or a zero-length string. The name needs to
- * be unique in this network.
- * @return Reference to the created server application.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given as server application
- * name.
- */
- public abstract ServerApplication createServer(String serverApplicationName);
-
- /**
- * Creates a new <code>ServerApplication</code>, but does not start
- * listening for incoming requests.
- *
- * @param serverApplicationName
- * The name for this server application, which is used for
- * logging purposes and as event source. May neither be
- * <code>null</code> or a zero-length string. The name needs to
- * be unique in this network.
- * @param serverPort
- * The TCP port on which the server will wait for incoming
- * requests. May not be negative or greater than 65535.
- * @return Reference to the created server application.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract ServerApplication createServer(
- String serverApplicationName, int serverPort);
-
- /**
- * Returns a reference on the (single) event manager for this network.
- *
- * @return Reference on the (single) event manager for this network.
- */
- public abstract EventManager getEventManager();
-
- /**
- * Returns (a copy of) the map containing the names of all directory nodes
- * as keys and the corresponding directory nodes as values.
- *
- * @return Map containing all directory nodes.
- */
- public abstract Map<String, DirectoryNode> getAllDirectoryNodes();
-
- /**
- * Returns (a copy of) the map containing the names of all router nodes
- * (only those that are not acting as directory nodes at the same time) as
- * keys and the corresponding router nodes as values.
- *
- * @return Map containing all router nodes.
- */
- public abstract Map<String, RouterNode> getAllRouterNodes();
-
- /**
- * Returns (a copy of) the map containing the names of all proxy nodes (only
- * those that are not acting as router or directory nodes at the same time)
- * as keys and the corresponding proxy nodes as values.
- *
- * @return Map containing all proxy nodes.
- */
- public abstract Map<String, ProxyNode> getAllProxyNodes();
-
- /**
- * Returns (a copy of) the map containing the names of all nodes as keys and
- * the corresponding proxy nodes as values.
- *
- * @return Map containing all nodes.
- */
- public abstract Map<String, ProxyNode> getAllNodes();
-
- /**
- * Returns the node with name <code>nodeName</code> or <code>null</code>
- * if no such node exists.
- *
- * @param nodeName
- * The node name to look up.
- * @return The node with name <code>nodeName</code>.
- */
- public abstract ProxyNode getNode(String nodeName);
-
- /**
- * <p>
- * Sends a HUP signal to all nodes in the network in regular intervals and
- * blocks the invoking thread until all nodes have reported to have
- * successfully opened a circuit.
- * </p>
- *
- * <p>
- * First, the method waits for <code>hupInterval</code> milliseconds for
- * the nodes to have successfully opened a circuit. If they do not succeed
- * within this time, a HUP signal is sent to all nodes and the method waits
- * for another <code>hupInterval</code> milliseconds. In total, the method
- * sends at most <code>tries</code> HUP signals before giving up and
- * returning with <code>false</code>. Thus, the maximum waiting time is
- * <code>(tries + 1)</code> times <code>hupInterval</code>. As soon as
- * all nodes have successfully opened circuits, the method returns with
- * <code>true</code>. This operation can only be invoked, if all nodes in
- * the network are in state <code>NodeState.RUNNING</code>.
- * </p>
- *
- * @param tries
- * The maximum number of HUP signals that are sent to the Tor
- * processes. Negative values are not allowed. A value of zero
- * means to wait only for the given time of
- * <code>hupInterval</code> milliseconds without sending a HUP
- * signal. Typical values depend on the network being a public or
- * private Tor network and range about 3 to 5 tries.
- * @param hupInterval
- * The time in milliseconds that the method will wait between
- * sending HUP signals. Negative values are not allowed.
- * Typically, values should not be smaller than 5 seconds to
- * permit Tor to stabilize.
- * @throws IllegalStateException
- * Thrown if at least one node is not in state
- * <code>NodeState.RUNNING</code>.
- * @throws IllegalArgumentException
- * Thrown if a negative value is given for either
- * <code>tries</code> or <code>hupInterval</code>.
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while sending HUP signals.
- * @return <code>true</code> if all nodes have reported to have
- * successfully opened a circuit, <code>false</code> otherwise.
- */
- public abstract boolean hupUntilUp(int tries, long hupInterval)
- throws PuppeTorException;
-
- /**
- * Sends a HUP signal to all nodes in the network once. This operation can
- * only be invoked, if all nodes in the network are in state
- * <code>NodeState.RUNNING</code>.
- *
- * @throws IllegalStateException
- * Thrown if at least one node is not in state
- * <code>NodeState.RUNNING</code>.
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while sending HUP signals.
- */
- public abstract void hupAllNodes() throws PuppeTorException;
-
- /**
- * Sends a HUP signal to all directory nodes in the network once. This
- * operation can only be invoked, if all directory nodes in the network are
- * in state <code>NodeState.RUNNING</code>.
- *
- * @throws IllegalStateException
- * Thrown if at least one directory node is not in state
- * <code>NodeState.RUNNING</code>.
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while sending HUP signals.
- */
- public abstract void hupAllDirectories() throws PuppeTorException;
-
- /**
- * Attempts to shut down all running nodes. The method blocks until all
- * shutdown requests have been sent and either returns, or throws the first
- * exception that has been observed when shutting down nodes. The method can
- * be assumed to return very quickly. If there are no running nodes in this
- * network, this operation has no effect.
- *
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while shutting down the
- * nodes.
- */
- public abstract void shutdownNodes() throws PuppeTorException;
-
- /**
- * Attempts to start all nodes within a given timeout of
- * <code>maximumTimeToWaitInMillis</code> milliseconds. The method returns
- * as soon as all nodes have started and opened their control port so that
- * we can connect to them. It returns a boolean that states whether the
- * operation was either successful or has timed out. This operation can only
- * be invoked, if all nodes in the network have written their configuration,
- * i.e. are not in state <code>NodeState.CONFIGURING</code> anymore.
- *
- * @param maximumTimeToWaitInMillis
- * The maximum time to wait in milliseconds. A positive value or
- * zero restricts waiting to this time. Negative values are not
- * allowed. Typical values are in the range of a few seconds.
- * @return <code>true</code> if all nodes could be started successfully,
- * <code>false</code> if a timeout has occured.
- * @throws IllegalStateException
- * Thrown if at least one node in the network is still in state
- * <code>NodeState.CONFIGURING</code>.
- * @throws IllegalArgumentException
- * Thrown if a negative value is given for
- * <code>maximumTimeToWaitInMillis</code>.
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while starting the nodes.
- */
- public abstract boolean startNodes(long maximumTimeToWaitInMillis)
- throws PuppeTorException;
-
- /**
- * Writes the configurations for all nodes in the network to disk, including
- * <code>torrc</code> and <code>approved-routers</code> files. This
- * method is assumed to return very quickly. In case of a private network,
- * <code>configureAsPrivateNetwork</code> should be invoked in advance to
- * this method!
- *
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while writing to the nodes'
- * working directories.
- */
- public abstract void writeConfigurations() throws PuppeTorException;
-
- /**
- * Returns the working directory of this network configuration which is in
- * <code>test-env/networkName/</code>.
- *
- * @return Working directory of this network.
- */
- public abstract File getWorkingDirectory();
-
- /**
- * Returns all configuration strings of the template of a node class that
- * will be added to future instances of this node class and its subclasses.
- * Note that the result only contains those configuration strings that are
- * added by this node class to possible superclasses and that parameterized
- * configuration strings, e.g. port configurations, are not included.
- *
- * @param nodeClass
- * The class which will be configured with the returned template
- * configuration; may not be <code>null</code>.
- * @return The template configuration for the given node class.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for the parameter.
- */
- public abstract List<String> getTemplateConfiguration(
- Class<? extends ProxyNode> nodeClass);
-
- /**
- * Adds a configuration string to the template of a node class, so that it
- * will be added to future instances of this node class and its subclasses.
- *
- * @param nodeClass
- * The class of nodes of which future instances will have the
- * given configuration string; may not be <code>null</code>.
- * @param templateConfigurationString
- * The configuration string to add; may neither be
- * <code>null</code> nor a zero-length string, and must consist
- * of configuration key and value.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract void addTemplateConfiguration(
- Class<? extends ProxyNode> nodeClass,
- String templateConfigurationString);
-
- /**
- * Removes a configuration string from the template of a node class, so that
- * it will not be added to future instances of this node class and its
- * subclasses.
- *
- * @param nodeClass
- * The class of nodes of which future instances will have the
- * given configuration string; may not be <code>null</code>.
- * @param templateConfigurationKey
- * The configuration key to remove; may neither be
- * <code>null</code> nor a zero-length key.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract void removeTemplateConfiguration(
- Class<? extends ProxyNode> nodeClass,
- String templateConfigurationKey);
-
- /**
- * Returns the name of this network.
- *
- * @return The name of this network.
- */
- public abstract String getNetworkName();
+ /**
+ * <p>
+ * Configures this network as private Tor network by exchanging directory
+ * strings and router fingerprints between the nodes of this network.
+ * Afterwards, the nodes will be able to run a private Tor network,
+ * separated from public directory servers and onion routers.
+ * </p>
+ *
+ * <p>
+ * The configuration is done in two steps:
+ * <ol>
+ * <li>Directory strings of directory nodes are added to the configurations
+ * of all nodes in the other network.</li>
+ * <li>Router fingerprints of all router and directory nodes are added to
+ * the <code>approved-routers</code> files of the directory nodes.</li>
+ * </ol>
+ * </p>
+ *
+ * <p>
+ * This operation may be invoked in any state of the contained nodes.
+ * However, a network that does not have directory nodes of its own but
+ * relies on directory nodes of a merged network <b>should not be started
+ * before being configured as private network!</b> Otherwise it would
+ * connect to the public Tor network before being merged with the other
+ * private Tor network. However, it may also be invoked at a later time,
+ * e.g. to admit new nodes.
+ * </p>
+ *
+ * <p>
+ * This operation does not write any configurations to disk and neither
+ * starts a nodes nor sends HUP signals to running nodes. These operations
+ * are left to the application, so that they have more control over the
+ * network behavior.
+ * </p>
+ *
+ * <p>
+ * Applications need to ensure that there are enough directory nodes (2) and
+ * router nodes (3) in the network to allow normal operation.
+ * </p>
+ *
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while determining the nodes'
+ * fingerprints.
+ */
+ public abstract void configureAsPrivateNetwork() throws PuppeTorException;
+
+ /**
+ * XXX document properly -SH
+ */
+ public void configureAsPartOfPrivateNetwork(
+ List<String> authorizedDirectoriesFingerprints);
+
+
+ /**
+ * Creates a new client application, but does not yet perform a request.
+ *
+ * @param clientApplicationName
+ * The name for this client application, which is used for
+ * logging purposes and as event source. May neither be
+ * <code>null</code> or a zero-length string. The name needs to
+ * be unique in this network.
+ * @param targetAddress
+ * The target for requests sent by this client application. Can
+ * be a publicly available URL or an onion address. May neither
+ * be <code>null</code> or a zero-length string.
+ * @param targetPort
+ * The TCP port for requests sent by this client application. If
+ * the target address is an onion address, this port is the
+ * virtual port that the hidden service has announced. May not be
+ * negative or greater than 65535.
+ * @param socksPort
+ * The TCP port on which a local Tor process is waiting for
+ * incoming SOCKS requests. May not be negative or greater than
+ * 65535.
+ * @return Reference to the created client application.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract ClientApplication createClient(
+ String clientApplicationName, String targetAddress, int targetPort,
+ int socksPort);
+
+ /**
+ * Creates a new directory node with automatically assigned ports and adds
+ * it to the network, but does not yet write its configuration to disk or
+ * start the corresponding Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @return Reference to the created directory node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given as node name.
+ */
+ public abstract DirectoryNode createDirectory(String nodeName);
+
+ /**
+ * Creates a new directory node with automatically assigned ports that will
+ * listen on the given IP address and adds it to the network, but does not
+ * yet write its configuration to disk or start the corresponding Tor
+ * process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @param serverIpAddress
+ * The IP address on which the node will listen. Must be a valid
+ * IP v4 address in dotted decimal notation. May not be
+ * <code>null</code>.
+ * @return Reference to the created directory node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given as node name.
+ */
+ public abstract DirectoryNode createDirectory(String nodeName,
+ String serverIpAddress);
+
+ /**
+ * Creates a new directory node and adds it to the network, but does not yet
+ * write its configuration to disk or start the corresponding Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @param controlPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for a controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming SOCKS requests. May not be negative or greater
+ * than 65535.
+ * @param orPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming requests from other onion routers. May not be
+ * negative or greater than 65535.
+ * @param dirPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming directory requests. May not be negative or
+ * greater than 65535.
+ * @return Reference to the created directory node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract DirectoryNode createDirectory(String nodeName,
+ int controlPort, int socksPort, int orPort, int dirPort);
+
+ /**
+ * Creates a new directory node that will listen on the given IP address and
+ * adds it to the network, but does not yet write its configuration to disk
+ * or start the corresponding Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @param controlPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for a controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming SOCKS requests. May not be negative or greater
+ * than 65535.
+ * @param orPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming requests from other onion routers. May not be
+ * negative or greater than 65535.
+ * @param dirPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming directory requests. May not be negative or
+ * greater than 65535.
+ * @param serverIpAddress
+ * The IP address on which the node will listen. Must be a valid
+ * IP v4 address in dotted decimal notation. May not be
+ * <code>null</code>.
+ * @return Reference to the created directory node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract DirectoryNode createDirectory(String nodeName,
+ int controlPort, int socksPort, int orPort, int dirPort,
+ String serverIpAddress);
+
+ /**
+ * Creates a new <code>ProxyNode</code> with automatically assigned ports
+ * and adds it to the network, but does not yet write its configuration to
+ * disk or start the corresponding Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, and as event source. May
+ * neither be <code>null</code> or have zero or more than 19
+ * alpha-numeric characters. The node name needs to be unique in
+ * this network.
+ * @return Reference to the created proxy node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given as node name.
+ */
+ public abstract ProxyNode createProxy(String nodeName);
+
+ /**
+ * Creates a new <code>ProxyNode</code> and adds it to the network, but
+ * does not yet write its configuration to disk or start the corresponding
+ * Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, and as event source. May
+ * neither be <code>null</code> or have zero or more than 19
+ * alpha-numeric characters. The node name needs to be unique in
+ * this network.
+ * @param controlPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for a controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming SOCKS requests. May not be negative or greater
+ * than 65535.
+ * @return Reference to the created proxy node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract ProxyNode createProxy(String nodeName, int controlPort,
+ int socksPort);
+
+ /**
+ * Creates a new <code>RouterNode</code> with automatically assigned ports
+ * and adds it to the network, but does not yet write its configuration to
+ * disk or start the corresponding Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @return Reference to the created router node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given as node name.
+ */
+ public abstract RouterNode createRouter(String nodeName);
+
+ /**
+ * Creates a new <code>RouterNode</code> and adds it to the network, but
+ * does not yet write its configuration to disk or start the corresponding
+ * Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @param controlPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for a controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming SOCKS requests. May not be negative or greater
+ * than 65535.
+ * @param orPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming requests from other onion routers. May not be
+ * negative or greater than 65535.
+ * @param dirPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming directory requests which in fact are requests for
+ * the mirrored directory. May not be negative or greater than
+ * 65535.
+ * @return Reference to the created router node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract RouterNode createRouter(String nodeName, int controlPort,
+ int socksPort, int orPort, int dirPort);
+
+ /**
+ * Creates a new <code>RouterNode</code> with automatically assigned ports
+ * that will listen on the given IP address and adds it to the network, but
+ * does not yet write its configuration to disk or start the corresponding
+ * Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @param serverIpAddress
+ * The IP address on which the node will listen. Must be a valid
+ * IP v4 address in dotted decimal notation. May not be
+ * <code>null</code>.
+ * @return Reference to the created router node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given as node name.
+ */
+ public abstract RouterNode createRouter(String nodeName,
+ String serverIpAddress);
+
+ /**
+ * Creates a new <code>RouterNode</code> that will listen on the given IP
+ * address and adds it to the network, but does not yet write its
+ * configuration to disk or start the corresponding Tor process.
+ *
+ * @param nodeName
+ * The name for this node, which is used as name for the working
+ * directory, for logging purposes, as node nickname, and as
+ * event source. May neither be <code>null</code> or have zero
+ * or more than 19 alpha-numeric characters. The node name needs
+ * to be unique in this network.
+ * @param controlPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for a controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming SOCKS requests. May not be negative or greater
+ * than 65535.
+ * @param orPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming requests from other onion routers. May not be
+ * negative or greater than 65535.
+ * @param dirPort
+ * The TCP port on which the corresponding Tor process will wait
+ * for incoming directory requests which in fact are requests for
+ * the mirrored directory. May not be negative or greater than
+ * 65535.
+ * @param serverIpAddress
+ * The IP address on which the node will listen. Must be a valid
+ * IP v4 address in dotted decimal notation. May not be
+ * <code>null</code>.
+ * @return Reference to the created router node.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract RouterNode createRouter(String nodeName, int controlPort,
+ int socksPort, int orPort, int dirPort, String serverIpAddress);
+
+ /**
+ * Creates a new <code>ServerApplication</code> with automatically
+ * assigned ports, but does not start listening for incoming requests.
+ *
+ * @param serverApplicationName
+ * The name for this server application, which is used for
+ * logging purposes and as event source. May neither be
+ * <code>null</code> or a zero-length string. The name needs to
+ * be unique in this network.
+ * @return Reference to the created server application.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given as server application
+ * name.
+ */
+ public abstract ServerApplication createServer(String serverApplicationName);
+
+ /**
+ * Creates a new <code>ServerApplication</code>, but does not start
+ * listening for incoming requests.
+ *
+ * @param serverApplicationName
+ * The name for this server application, which is used for
+ * logging purposes and as event source. May neither be
+ * <code>null</code> or a zero-length string. The name needs to
+ * be unique in this network.
+ * @param serverPort
+ * The TCP port on which the server will wait for incoming
+ * requests. May not be negative or greater than 65535.
+ * @return Reference to the created server application.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract ServerApplication createServer(
+ String serverApplicationName, int serverPort);
+
+ /**
+ * Returns a reference on the (single) event manager for this network.
+ *
+ * @return Reference on the (single) event manager for this network.
+ */
+ public abstract EventManager getEventManager();
+
+ /**
+ * Returns (a copy of) the map containing the names of all directory nodes
+ * as keys and the corresponding directory nodes as values.
+ *
+ * @return Map containing all directory nodes.
+ */
+ public abstract Map<String, DirectoryNode> getAllDirectoryNodes();
+
+ /**
+ * Returns (a copy of) the map containing the names of all router nodes
+ * (only those that are not acting as directory nodes at the same time) as
+ * keys and the corresponding router nodes as values.
+ *
+ * @return Map containing all router nodes.
+ */
+ public abstract Map<String, RouterNode> getAllRouterNodes();
+
+ /**
+ * Returns (a copy of) the map containing the names of all proxy nodes (only
+ * those that are not acting as router or directory nodes at the same time)
+ * as keys and the corresponding proxy nodes as values.
+ *
+ * @return Map containing all proxy nodes.
+ */
+ public abstract Map<String, ProxyNode> getAllProxyNodes();
+
+ /**
+ * Returns (a copy of) the map containing the names of all nodes as keys and
+ * the corresponding proxy nodes as values.
+ *
+ * @return Map containing all nodes.
+ */
+ public abstract Map<String, ProxyNode> getAllNodes();
+
+ /**
+ * Returns the node with name <code>nodeName</code> or <code>null</code>
+ * if no such node exists.
+ *
+ * @param nodeName
+ * The node name to look up.
+ * @return The node with name <code>nodeName</code>.
+ */
+ public abstract ProxyNode getNode(String nodeName);
+
+ /**
+ * <p>
+ * Sends a HUP signal to all nodes in the network in regular intervals and
+ * blocks the invoking thread until all nodes have reported to have
+ * successfully opened a circuit.
+ * </p>
+ *
+ * <p>
+ * First, the method waits for <code>hupInterval</code> milliseconds for
+ * the nodes to have successfully opened a circuit. If they do not succeed
+ * within this time, a HUP signal is sent to all nodes and the method waits
+ * for another <code>hupInterval</code> milliseconds. In total, the method
+ * sends at most <code>tries</code> HUP signals before giving up and
+ * returning with <code>false</code>. Thus, the maximum waiting time is
+ * <code>(tries + 1)</code> times <code>hupInterval</code>. As soon as
+ * all nodes have successfully opened circuits, the method returns with
+ * <code>true</code>. This operation can only be invoked, if all nodes in
+ * the network are in state <code>NodeState.RUNNING</code>.
+ * </p>
+ *
+ * @param tries
+ * The maximum number of HUP signals that are sent to the Tor
+ * processes. Negative values are not allowed. A value of zero
+ * means to wait only for the given time of
+ * <code>hupInterval</code> milliseconds without sending a HUP
+ * signal. Typical values depend on the network being a public or
+ * private Tor network and range about 3 to 5 tries.
+ * @param hupInterval
+ * The time in milliseconds that the method will wait between
+ * sending HUP signals. Negative values are not allowed.
+ * Typically, values should not be smaller than 5 seconds to
+ * permit Tor to stabilize.
+ * @throws IllegalStateException
+ * Thrown if at least one node is not in state
+ * <code>NodeState.RUNNING</code>.
+ * @throws IllegalArgumentException
+ * Thrown if a negative value is given for either
+ * <code>tries</code> or <code>hupInterval</code>.
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while sending HUP signals.
+ * @return <code>true</code> if all nodes have reported to have
+ * successfully opened a circuit, <code>false</code> otherwise.
+ */
+ public abstract boolean hupUntilUp(int tries, long hupInterval)
+ throws PuppeTorException;
+
+ /**
+ * Sends a HUP signal to all nodes in the network once. This operation can
+ * only be invoked, if all nodes in the network are in state
+ * <code>NodeState.RUNNING</code>.
+ *
+ * @throws IllegalStateException
+ * Thrown if at least one node is not in state
+ * <code>NodeState.RUNNING</code>.
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while sending HUP signals.
+ */
+ public abstract void hupAllNodes() throws PuppeTorException;
+
+ /**
+ * Sends a HUP signal to all directory nodes in the network once. This
+ * operation can only be invoked, if all directory nodes in the network are
+ * in state <code>NodeState.RUNNING</code>.
+ *
+ * @throws IllegalStateException
+ * Thrown if at least one directory node is not in state
+ * <code>NodeState.RUNNING</code>.
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while sending HUP signals.
+ */
+ public abstract void hupAllDirectories() throws PuppeTorException;
+
+ /**
+ * Attempts to shut down all running nodes. The method blocks until all
+ * shutdown requests have been sent and either returns, or throws the first
+ * exception that has been observed when shutting down nodes. The method can
+ * be assumed to return very quickly. If there are no running nodes in this
+ * network, this operation has no effect.
+ *
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while shutting down the
+ * nodes.
+ */
+ public abstract void shutdownNodes() throws PuppeTorException;
+
+ /**
+ * Attempts to start all nodes within a given timeout of
+ * <code>maximumTimeToWaitInMillis</code> milliseconds. The method returns
+ * as soon as all nodes have started and opened their control port so that
+ * we can connect to them. It returns a boolean that states whether the
+ * operation was either successful or has timed out. This operation can only
+ * be invoked, if all nodes in the network have written their configuration,
+ * i.e. are not in state <code>NodeState.CONFIGURING</code> anymore.
+ *
+ * @param maximumTimeToWaitInMillis
+ * The maximum time to wait in milliseconds. A positive value or
+ * zero restricts waiting to this time. Negative values are not
+ * allowed. Typical values are in the range of a few seconds.
+ * @return <code>true</code> if all nodes could be started successfully,
+ * <code>false</code> if a timeout has occured.
+ * @throws IllegalStateException
+ * Thrown if at least one node in the network is still in state
+ * <code>NodeState.CONFIGURING</code>.
+ * @throws IllegalArgumentException
+ * Thrown if a negative value is given for
+ * <code>maximumTimeToWaitInMillis</code>.
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while starting the nodes.
+ */
+ public abstract boolean startNodes(long maximumTimeToWaitInMillis)
+ throws PuppeTorException;
+
+ /**
+ * Writes the configurations for all nodes in the network to disk, including
+ * <code>torrc</code> and <code>approved-routers</code> files. This
+ * method is assumed to return very quickly. In case of a private network,
+ * <code>configureAsPrivateNetwork</code> should be invoked in advance to
+ * this method!
+ *
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while writing to the nodes'
+ * working directories.
+ */
+ public abstract void writeConfigurations() throws PuppeTorException;
+
+ /**
+ * Returns the working directory of this network configuration which is in
+ * <code>test-env/networkName/</code>.
+ *
+ * @return Working directory of this network.
+ */
+ public abstract File getWorkingDirectory();
+
+ /**
+ * Returns all configuration strings of the template of a node class that
+ * will be added to future instances of this node class and its subclasses.
+ * Note that the result only contains those configuration strings that are
+ * added by this node class to possible superclasses and that parameterized
+ * configuration strings, e.g. port configurations, are not included.
+ *
+ * @param nodeClass
+ * The class which will be configured with the returned template
+ * configuration; may not be <code>null</code>.
+ * @return The template configuration for the given node class.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for the parameter.
+ */
+ public abstract List<String> getTemplateConfiguration(
+ Class<? extends ProxyNode> nodeClass);
+
+ /**
+ * Adds a configuration string to the template of a node class, so that it
+ * will be added to future instances of this node class and its subclasses.
+ *
+ * @param nodeClass
+ * The class of nodes of which future instances will have the
+ * given configuration string; may not be <code>null</code>.
+ * @param templateConfigurationString
+ * The configuration string to add; may neither be
+ * <code>null</code> nor a zero-length string, and must consist
+ * of configuration key and value.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract void addTemplateConfiguration(
+ Class<? extends ProxyNode> nodeClass,
+ String templateConfigurationString);
+
+ /**
+ * Removes a configuration string from the template of a node class, so that
+ * it will not be added to future instances of this node class and its
+ * subclasses.
+ *
+ * @param nodeClass
+ * The class of nodes of which future instances will have the
+ * given configuration string; may not be <code>null</code>.
+ * @param templateConfigurationKey
+ * The configuration key to remove; may neither be
+ * <code>null</code> nor a zero-length key.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract void removeTemplateConfiguration(
+ Class<? extends ProxyNode> nodeClass,
+ String templateConfigurationKey);
+
+ /**
+ * Returns the name of this network.
+ *
+ * @return The name of this network.
+ */
+ public abstract String getNetworkName();
}
diff --git a/src/org/torproject/puppetor/NetworkFactory.java b/src/org/torproject/puppetor/NetworkFactory.java
index 2b93ed3..ac59fa0 100644
--- a/src/org/torproject/puppetor/NetworkFactory.java
+++ b/src/org/torproject/puppetor/NetworkFactory.java
@@ -26,58 +26,58 @@ import org.torproject.puppetor.impl.NetworkImpl;
*/
public abstract class NetworkFactory {
- final private static ConcurrentMap<String, Network> networks =
- new ConcurrentHashMap<String, Network>();
+ final private static ConcurrentMap<String, Network> networks =
+ new ConcurrentHashMap<String, Network>();
- /**
- * Creates a new network that is required for a test run. The new network is
- * initially unpopulated and creates its own working directory at
- * test-env/randomTestID/. The network automatically assigns port numbers to
- * newly created nodes starting at <code>7000</code>.
- *
- * @param networkName
- * Name of this network configuration.
- * @return A new network instance.
- */
- public static Network createNetwork(final String networkName) {
- final Network network = new NetworkImpl(networkName);
- networks.put(networkName, network);
- return network;
- }
+ /**
+ * Creates a new network that is required for a test run. The new network is
+ * initially unpopulated and creates its own working directory at
+ * test-env/randomTestID/. The network automatically assigns port numbers to
+ * newly created nodes starting at <code>7000</code>.
+ *
+ * @param networkName
+ * Name of this network configuration.
+ * @return A new network instance.
+ */
+ public static Network createNetwork(final String networkName) {
+ final Network network = new NetworkImpl(networkName);
+ networks.put(networkName, network);
+ return network;
+ }
- /**
- * Creates a new network that is required for a test run. The new network is
- * initially unpopulated and creates its own working directory at
- * test-env/randomTestID/. The network automatically assigns port numbers to
- * newly created nodes starting at <code>startPort</code>.
- *
- * @param networkName
- * Name of this network configuration.
- * @param startPort
- * The initial value for automatically assigned port numbers of
- * nodes created by this <code>Network</code>; must be a value
- * between <code>1024</code> and <code>65535</code>.
- * Applications need to ensure that there are enough ports left
- * to the maximum number port <code>65535</code> for all
- * created nodes.
- * @return A new network instance.
- */
- public static Network createNetwork(final String networkName,
- final int startPort) {
- final Network network = new NetworkImpl(networkName, startPort);
- networks.put(networkName, network);
- return network;
- }
+ /**
+ * Creates a new network that is required for a test run. The new network is
+ * initially unpopulated and creates its own working directory at
+ * test-env/randomTestID/. The network automatically assigns port numbers to
+ * newly created nodes starting at <code>startPort</code>.
+ *
+ * @param networkName
+ * Name of this network configuration.
+ * @param startPort
+ * The initial value for automatically assigned port numbers of
+ * nodes created by this <code>Network</code>; must be a value
+ * between <code>1024</code> and <code>65535</code>.
+ * Applications need to ensure that there are enough ports left
+ * to the maximum number port <code>65535</code> for all
+ * created nodes.
+ * @return A new network instance.
+ */
+ public static Network createNetwork(final String networkName,
+ final int startPort) {
+ final Network network = new NetworkImpl(networkName, startPort);
+ networks.put(networkName, network);
+ return network;
+ }
- /**
- *
- */
- public static Network getNetworkByName(final String networkName) {
- final Network network = networks.get(networkName);
- if (network == null) {
- throw new IllegalStateException("BUG: The network with name "
- + networkName + " must exist and be non-null!");
- }
- return network;
- }
+ /**
+ *
+ */
+ public static Network getNetworkByName(final String networkName) {
+ final Network network = networks.get(networkName);
+ if (network == null) {
+ throw new IllegalStateException("BUG: The network with name "
+ + networkName + " must exist and be non-null!");
+ }
+ return network;
+ }
}
diff --git a/src/org/torproject/puppetor/NodeEventType.java b/src/org/torproject/puppetor/NodeEventType.java
index 7b65bd4..600096e 100644
--- a/src/org/torproject/puppetor/NodeEventType.java
+++ b/src/org/torproject/puppetor/NodeEventType.java
@@ -11,50 +11,50 @@ package org.torproject.puppetor;
@SuppressWarnings("serial")
public class NodeEventType implements EventType {
- /**
- * String identifying the type of the event type.
- */
- String typeString;
-
- /**
- * Creates a new event type with the given type string.
- *
- * @param typeString
- * String identifying the type of the event type.
- */
- public NodeEventType(final String typeString) {
- this.typeString = typeString;
- }
-
- public String getTypeName() {
- return typeString;
- }
-
- /**
- * The node was started and we managed to connect to its control port; this
- * event is fired internally and not parsed from a log statement from Tor.
- */
- public static final NodeEventType NODE_STARTED =
- new NodeEventType("NODE_STARTED");
-
- /**
- * The node has opened its control port; this event is parsed from a log
- * statement in connection_create_listener().
- */
- public static final NodeEventType NODE_CONTROL_PORT_OPENED =
- new NodeEventType("NODE_CONTROL_PORT_OPENED");
-
- /**
- * The node which has successfully opened a circuit; this event is parsed
- * from a log statement in circuit_send_next_onion_skin().
- */
- public static final NodeEventType NODE_CIRCUIT_OPENED =
- new NodeEventType("NODE_CIRCUIT_OPENED");
-
- /**
- * The node was stopped; this event is fired internally and not parsed from
- * a log statement from Tor.
- */
- public static final NodeEventType NODE_STOPPED =
- new NodeEventType("NODE_STOPPED");
-}
\ No newline at end of file
+ /**
+ * String identifying the type of the event type.
+ */
+ String typeString;
+
+ /**
+ * Creates a new event type with the given type string.
+ *
+ * @param typeString
+ * String identifying the type of the event type.
+ */
+ public NodeEventType(final String typeString) {
+ this.typeString = typeString;
+ }
+
+ public String getTypeName() {
+ return typeString;
+ }
+
+ /**
+ * The node was started and we managed to connect to its control port; this
+ * event is fired internally and not parsed from a log statement from Tor.
+ */
+ public static final NodeEventType NODE_STARTED =
+ new NodeEventType("NODE_STARTED");
+
+ /**
+ * The node has opened its control port; this event is parsed from a log
+ * statement in connection_create_listener().
+ */
+ public static final NodeEventType NODE_CONTROL_PORT_OPENED =
+ new NodeEventType("NODE_CONTROL_PORT_OPENED");
+
+ /**
+ * The node which has successfully opened a circuit; this event is parsed
+ * from a log statement in circuit_send_next_onion_skin().
+ */
+ public static final NodeEventType NODE_CIRCUIT_OPENED =
+ new NodeEventType("NODE_CIRCUIT_OPENED");
+
+ /**
+ * The node was stopped; this event is fired internally and not parsed from
+ * a log statement from Tor.
+ */
+ public static final NodeEventType NODE_STOPPED =
+ new NodeEventType("NODE_STOPPED");
+}
diff --git a/src/org/torproject/puppetor/NodeState.java b/src/org/torproject/puppetor/NodeState.java
index 720b44f..aa9b86a 100644
--- a/src/org/torproject/puppetor/NodeState.java
+++ b/src/org/torproject/puppetor/NodeState.java
@@ -18,27 +18,27 @@ package org.torproject.puppetor;
*/
public enum NodeState {
- /**
- * The configuration of this node has not been written to disk. This is the
- * initial state of a <code>ProxyNode</code> or one of its subclasses.
- */
- CONFIGURING,
+ /**
+ * The configuration of this node has not been written to disk. This is the
+ * initial state of a <code>ProxyNode</code> or one of its subclasses.
+ */
+ CONFIGURING,
- /**
- * The configuration of this node has been written to disk, but the Tor
- * process has not been started, yet. This state could be useful to review
- * the configuration that has been written to disk.
- */
- CONFIGURATION_WRITTEN,
+ /**
+ * The configuration of this node has been written to disk, but the Tor
+ * process has not been started, yet. This state could be useful to review
+ * the configuration that has been written to disk.
+ */
+ CONFIGURATION_WRITTEN,
- /**
- * The node has been started and is running.
- */
- RUNNING,
+ /**
+ * The node has been started and is running.
+ */
+ RUNNING,
- /**
- * The node had been started and shut down. It cannot be started at a later
- * time anymore.
- */
- SHUT_DOWN
+ /**
+ * The node had been started and shut down. It cannot be started at a later
+ * time anymore.
+ */
+ SHUT_DOWN
}
diff --git a/src/org/torproject/puppetor/ProxyNode.java b/src/org/torproject/puppetor/ProxyNode.java
index 78ac209..8aa9530 100644
--- a/src/org/torproject/puppetor/ProxyNode.java
+++ b/src/org/torproject/puppetor/ProxyNode.java
@@ -44,226 +44,226 @@ import java.util.List;
*/
public interface ProxyNode {
- /**
- * Adds the entries for a hidden service to the configuration of this node.
- *
- * @param serviceName
- * Name of the hidden service that will be used as name for the
- * hidden service directory. May neither be <code>null</code>
- * or a zero-length string.
- * @param servicePort
- * The TCP port on which the service will be available for
- * requests. This can, but need not be different from the virtual
- * port that is announced to clients. May not be negative or
- * greater than 65535.
- * @param virtualPort
- * The virtual TCP port that this hidden service runs on as it is
- * announced to clients. May not be negative or greater than
- * 65535.
- * @return <code>HiddenService</code> object containing the configuration
- * of the created hidden service.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract HiddenService addHiddenService(String serviceName,
- int servicePort, int virtualPort);
+ /**
+ * Adds the entries for a hidden service to the configuration of this node.
+ *
+ * @param serviceName
+ * Name of the hidden service that will be used as name for the
+ * hidden service directory. May neither be <code>null</code>
+ * or a zero-length string.
+ * @param servicePort
+ * The TCP port on which the service will be available for
+ * requests. This can, but need not be different from the virtual
+ * port that is announced to clients. May not be negative or
+ * greater than 65535.
+ * @param virtualPort
+ * The virtual TCP port that this hidden service runs on as it is
+ * announced to clients. May not be negative or greater than
+ * 65535.
+ * @return <code>HiddenService</code> object containing the configuration
+ * of the created hidden service.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract HiddenService addHiddenService(String serviceName,
+ int servicePort, int virtualPort);
- /**
- * Adds the entries for a hidden service with virtual port 80 to the
- * configuration of this node.
- *
- * @param serviceName
- * Name of the hidden service that will be used as name for the
- * hidden service directory. May neither be <code>null</code>
- * or a zero-length string.
- * @param servicePort
- * The TCP port on which the service will be available for
- * requests. This can, but need not be different from the virtual
- * port that is announced to clients. May not be negative or
- * greater than 65535.
- * @return <code>HiddenService</code> object containing the configuration
- * of the created hidden service.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- public abstract HiddenService addHiddenService(String serviceName,
- int servicePort);
+ /**
+ * Adds the entries for a hidden service with virtual port 80 to the
+ * configuration of this node.
+ *
+ * @param serviceName
+ * Name of the hidden service that will be used as name for the
+ * hidden service directory. May neither be <code>null</code>
+ * or a zero-length string.
+ * @param servicePort
+ * The TCP port on which the service will be available for
+ * requests. This can, but need not be different from the virtual
+ * port that is announced to clients. May not be negative or
+ * greater than 65535.
+ * @return <code>HiddenService</code> object containing the configuration
+ * of the created hidden service.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ public abstract HiddenService addHiddenService(String serviceName,
+ int servicePort);
- /**
- * Adds the entries for a hidden service with an automatically assigned
- * service port and virtual port 80 to the configuration of this node.
- *
- * service port automatically assigned virtual port 80
- *
- * @param serviceName
- * Name of the hidden service that will be used as name for the
- * hidden service directory. May neither be <code>null</code>
- * or a zero-length string.
- * @return <code>HiddenService</code> object containing the configuration
- * of the created hidden service.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for the parameter.
- */
- public abstract HiddenService addHiddenService(String serviceName);
+ /**
+ * Adds the entries for a hidden service with an automatically assigned
+ * service port and virtual port 80 to the configuration of this node.
+ *
+ * service port automatically assigned virtual port 80
+ *
+ * @param serviceName
+ * Name of the hidden service that will be used as name for the
+ * hidden service directory. May neither be <code>null</code>
+ * or a zero-length string.
+ * @return <code>HiddenService</code> object containing the configuration
+ * of the created hidden service.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for the parameter.
+ */
+ public abstract HiddenService addHiddenService(String serviceName);
- /**
- * Adds the given configuration string, consisting of "<configuration key>
- * <configuration value>", to the configuration of this node.
- *
- * @param configurationString
- * The configuration string to be added.
- * @throws IllegalArgumentException
- * Thrown if the given configuration string is either
- * <code>null</code>, a zero-length string, or does not
- * consist of configuration key and value.
- */
- public abstract void addConfiguration(String configurationString);
+ /**
+ * Adds the given configuration string, consisting of "<configuration key>
+ * <configuration value>", to the configuration of this node.
+ *
+ * @param configurationString
+ * The configuration string to be added.
+ * @throws IllegalArgumentException
+ * Thrown if the given configuration string is either
+ * <code>null</code>, a zero-length string, or does not
+ * consist of configuration key and value.
+ */
+ public abstract void addConfiguration(String configurationString);
- /**
- * Adds the given configuration strings, each consisting of "<configuration
- * key> <configuration value>", to the configuration of this node.
- *
- * @param configurationStrings
- * A list of the configuration strings to be added.
- * @throws IllegalArgumentException
- * Thrown if the given list is <code>null</code>, or any of
- * the contained strings is either <code>null</code>, a
- * zero-length string, or does not consist of configuration key
- * and value.
- */
- public abstract void addConfigurations(List<String> configurationStrings);
+ /**
+ * Adds the given configuration strings, each consisting of "<configuration
+ * key> <configuration value>", to the configuration of this node.
+ *
+ * @param configurationStrings
+ * A list of the configuration strings to be added.
+ * @throws IllegalArgumentException
+ * Thrown if the given list is <code>null</code>, or any of
+ * the contained strings is either <code>null</code>, a
+ * zero-length string, or does not consist of configuration key
+ * and value.
+ */
+ public abstract void addConfigurations(List<String> configurationStrings);
- /**
- * Replaces the first configuration string, consisting of "<configuration
- * key> <configuration value>", that contains the same configuration key as
- * <code>configurationString</code> by this new configuration string; if
- * multiple occurrences of the given configuration key are found, only the
- * first occurrence is replaced; if no configuration can be found, the
- * configuration string is appended.
- *
- * @param configurationString
- * The replacing configuration string.
- * @throws IllegalArgumentException
- * Thrown if the given configuration string is either
- * <code>null</code>, a zero-length string, or does not
- * consist of configuration key and value.
- */
- public abstract void replaceConfiguration(String configurationString);
+ /**
+ * Replaces the first configuration string, consisting of "<configuration
+ * key> <configuration value>", that contains the same configuration key as
+ * <code>configurationString</code> by this new configuration string; if
+ * multiple occurrences of the given configuration key are found, only the
+ * first occurrence is replaced; if no configuration can be found, the
+ * configuration string is appended.
+ *
+ * @param configurationString
+ * The replacing configuration string.
+ * @throws IllegalArgumentException
+ * Thrown if the given configuration string is either
+ * <code>null</code>, a zero-length string, or does not
+ * consist of configuration key and value.
+ */
+ public abstract void replaceConfiguration(String configurationString);
- /**
- * Removes all configuration strings containing the given configuration key
- * in "<configuration key> <configuration value>", regardless of their
- * configuration value.
- *
- * @param configurationKey
- * The configuration key to remove.
- * @throws IllegalArgumentException
- * Thrown if the given configuration key is either
- * <code>null</code> or a zero-length key.
- */
- public abstract void removeConfiguration(String configurationKey);
+ /**
+ * Removes all configuration strings containing the given configuration key
+ * in "<configuration key> <configuration value>", regardless of their
+ * configuration value.
+ *
+ * @param configurationKey
+ * The configuration key to remove.
+ * @throws IllegalArgumentException
+ * Thrown if the given configuration key is either
+ * <code>null</code> or a zero-length key.
+ */
+ public abstract void removeConfiguration(String configurationKey);
- /**
- * Returns the name of this node.
- *
- * @return The name of this node.
- */
- public abstract String getNodeName();
+ /**
+ * Returns the name of this node.
+ *
+ * @return The name of this node.
+ */
+ public abstract String getNodeName();
- /**
- * Returns the state of this node.
- *
- * @return The state of this node.
- */
- public abstract NodeState getNodeState();
+ /**
+ * Returns the state of this node.
+ *
+ * @return The state of this node.
+ */
+ public abstract NodeState getNodeState();
- /**
- * Sends a HUP command to the process via its control port to restart it;
- * can only be done if the node has already been started, i.e. is in state
- * <code>NodeState.RUNNING</code>!
- *
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while sending the HUP signal.
- * @throws IllegalStateException
- * Thrown if node is not in state <code>NodeState.RUNNING</code>.
- */
- public abstract void hup() throws PuppeTorException;
+ /**
+ * Sends a HUP command to the process via its control port to restart it;
+ * can only be done if the node has already been started, i.e. is in state
+ * <code>NodeState.RUNNING</code>!
+ *
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while sending the HUP signal.
+ * @throws IllegalStateException
+ * Thrown if node is not in state <code>NodeState.RUNNING</code>.
+ */
+ public abstract void hup() throws PuppeTorException;
- /**
- * Shuts down the Tor process corresponding to this node immediately. This
- * is done by sending the <code>SHUTDOWN</code> signal twice, so that
- * those nodes extending <code>ProxyNode</code> which have opened their OR
- * port shutdown immediately, too.
- *
- * @throws IllegalStateException
- * Thrown if this node is not in state
- * <code>NodeState.RUNNING</code>.
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while sending the
- * <code>SHUTDOWN</code> signal.
- */
- public abstract void shutdown() throws PuppeTorException;
+ /**
+ * Shuts down the Tor process corresponding to this node immediately. This
+ * is done by sending the <code>SHUTDOWN</code> signal twice, so that
+ * those nodes extending <code>ProxyNode</code> which have opened their OR
+ * port shutdown immediately, too.
+ *
+ * @throws IllegalStateException
+ * Thrown if this node is not in state
+ * <code>NodeState.RUNNING</code>.
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while sending the
+ * <code>SHUTDOWN</code> signal.
+ */
+ public abstract void shutdown() throws PuppeTorException;
- /**
- * Starts the Tor process for this node and connects to the control port as
- * soon as it is opened. <b>In order for this method to succeed it is
- * absolutely necessary, that logging on the console is not changed in the
- * configuration of this node to a higher level than NOTICE, because the
- * output is parsed to see when the control port is opened.</b>
- *
- * @param maximumTimeToWaitInMillis
- * Maximum time in milliseconds we will wait for the Tor process
- * to be started and the control port being opened. If this value
- * is negative or zero, we will wait potentially forever.
- * @return <code>true</code> if the node could be started successfully,
- * <code>false</code> otherwise.
- * @throws IllegalStateException
- * Thrown if node is not in state
- * <code>NodeState.CONFIGURATION_WRITTEN</code>, i.e. if
- * either configuration has not been written or the process has
- * already been started.
- * @throws PuppeTorException
- * Thrown if either the process could not be started, or the
- * connection to the control port could not be established.
- */
- public abstract boolean startNode(long maximumTimeToWaitInMillis)
- throws PuppeTorException;
+ /**
+ * Starts the Tor process for this node and connects to the control port as
+ * soon as it is opened. <b>In order for this method to succeed it is
+ * absolutely necessary, that logging on the console is not changed in the
+ * configuration of this node to a higher level than NOTICE, because the
+ * output is parsed to see when the control port is opened.</b>
+ *
+ * @param maximumTimeToWaitInMillis
+ * Maximum time in milliseconds we will wait for the Tor process
+ * to be started and the control port being opened. If this value
+ * is negative or zero, we will wait potentially forever.
+ * @return <code>true</code> if the node could be started successfully,
+ * <code>false</code> otherwise.
+ * @throws IllegalStateException
+ * Thrown if node is not in state
+ * <code>NodeState.CONFIGURATION_WRITTEN</code>, i.e. if
+ * either configuration has not been written or the process has
+ * already been started.
+ * @throws PuppeTorException
+ * Thrown if either the process could not be started, or the
+ * connection to the control port could not be established.
+ */
+ public abstract boolean startNode(long maximumTimeToWaitInMillis)
+ throws PuppeTorException;
- /**
- * Writes the configuration of this node to the <code>torrc</code> file in
- * its working directory and changes the state to
- * <code>NodeState.CONFIGURATION_WRITTEN</code>, if it was in state
- * <code>NodeState.CONFIGURING</code> before.
- *
- * @throws PuppeTorException
- * Thrown if the configuration file <code>torrc</code> cannot
- * be written to disk.
- */
- public abstract void writeConfiguration() throws PuppeTorException;
+ /**
+ * Writes the configuration of this node to the <code>torrc</code> file in
+ * its working directory and changes the state to
+ * <code>NodeState.CONFIGURATION_WRITTEN</code>, if it was in state
+ * <code>NodeState.CONFIGURING</code> before.
+ *
+ * @throws PuppeTorException
+ * Thrown if the configuration file <code>torrc</code> cannot
+ * be written to disk.
+ */
+ public abstract void writeConfiguration() throws PuppeTorException;
- /**
- * Returns the SOCKS port of this node.
- *
- * @return The SOCKS port of this node.
- */
- public abstract int getSocksPort();
+ /**
+ * Returns the SOCKS port of this node.
+ *
+ * @return The SOCKS port of this node.
+ */
+ public abstract int getSocksPort();
- /**
- * Returns the control port of this node.
- *
- * @return The control port of this node.
- */
- public abstract int getControlPort();
+ /**
+ * Returns the control port of this node.
+ *
+ * @return The control port of this node.
+ */
+ public abstract int getControlPort();
- /**
- * Returns (a copy of) the list of strings containing the configuration of
- * this node.
- *
- * @return (A copy of) the list of strings containing the configuration of
- * this node.
- */
- public abstract List<String> getConfiguration();
+ /**
+ * Returns (a copy of) the list of strings containing the configuration of
+ * this node.
+ *
+ * @return (A copy of) the list of strings containing the configuration of
+ * this node.
+ */
+ public abstract List<String> getConfiguration();
}
diff --git a/src/org/torproject/puppetor/PuppeTorException.java b/src/org/torproject/puppetor/PuppeTorException.java
index ff4ef72..741f177 100644
--- a/src/org/torproject/puppetor/PuppeTorException.java
+++ b/src/org/torproject/puppetor/PuppeTorException.java
@@ -20,46 +20,46 @@ package org.torproject.puppetor;
@SuppressWarnings("serial")
public class PuppeTorException extends Exception {
- /**
- * Creates a <code>PuppeTorException</code> without detail message or
- * cause.
- */
- public PuppeTorException() {
- super();
- }
+ /**
+ * Creates a <code>PuppeTorException</code> without detail message or
+ * cause.
+ */
+ public PuppeTorException() {
+ super();
+ }
- /**
- * Creates a <code>PuppeTorException</code> with the given detail
- * <code>message</code> and <code>cause</code>.
- *
- * @param message
- * The detail message of this exception.
- * @param cause
- * The cause for this exception.
- */
- public PuppeTorException(final String message, final Throwable cause) {
- super(message, cause);
- }
+ /**
+ * Creates a <code>PuppeTorException</code> with the given detail
+ * <code>message</code> and <code>cause</code>.
+ *
+ * @param message
+ * The detail message of this exception.
+ * @param cause
+ * The cause for this exception.
+ */
+ public PuppeTorException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
- /**
- * Creates a <code>PuppeTorException</code> with the given detail
- * <code>message</code>, but without a <code>cause</code>.
- *
- * @param message
- * The detail message of this exception.
- */
- public PuppeTorException(final String message) {
- super(message);
- }
+ /**
+ * Creates a <code>PuppeTorException</code> with the given detail
+ * <code>message</code>, but without a <code>cause</code>.
+ *
+ * @param message
+ * The detail message of this exception.
+ */
+ public PuppeTorException(final String message) {
+ super(message);
+ }
- /**
- * Creates a <code>PuppeTorException</code> with the given
- * <code>cause</code>, but without a detail message.
- *
- * @param cause
- * The cause for this exception.
- */
- public PuppeTorException(final Throwable cause) {
- super(cause);
- }
+ /**
+ * Creates a <code>PuppeTorException</code> with the given
+ * <code>cause</code>, but without a detail message.
+ *
+ * @param cause
+ * The cause for this exception.
+ */
+ public PuppeTorException(final Throwable cause) {
+ super(cause);
+ }
}
diff --git a/src/org/torproject/puppetor/RouterNode.java b/src/org/torproject/puppetor/RouterNode.java
index ea42a87..170409b 100644
--- a/src/org/torproject/puppetor/RouterNode.java
+++ b/src/org/torproject/puppetor/RouterNode.java
@@ -16,40 +16,40 @@ package org.torproject.puppetor;
*/
public interface RouterNode extends ProxyNode {
- /**
- * Returns the dir port of this node.
- *
- * @return The dir port of this node.
- */
- public abstract int getDirPort();
+ /**
+ * Returns the dir port of this node.
+ *
+ * @return The dir port of this node.
+ */
+ public abstract int getDirPort();
- /**
- * Returns the onion port of this node.
- *
- * @return The onion port of this node.
- */
- public abstract int getOrPort();
+ /**
+ * Returns the onion port of this node.
+ *
+ * @return The onion port of this node.
+ */
+ public abstract int getOrPort();
- /**
- * <p>
- * Returns the fingerprint string of this node, formatted like
- * <code>nickname 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000</code>.
- * </p>
- *
- * <p>
- * The fingerprint is determined by a background thread that is started as
- * soon as the node is instantiated. If this background thread has not
- * finished when this method is invoked, the invoking thread will be blocked
- * until the fingerprint is available (or determining it has failed,
- * whereupon an exception will be thrown).
- * </p>
- *
- * @return The fingerprint of this node.
- * @throws PuppeTorException
- * Thrown if either the temporary <code>torrc.temp</code>
- * configuration file cannot be written, the Tor process cannot
- * be started temporarily, or the fingerprint file cannot be
- * read.
- */
- public abstract String getFingerprint() throws PuppeTorException;
+ /**
+ * <p>
+ * Returns the fingerprint string of this node, formatted like
+ * <code>nickname 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000</code>.
+ * </p>
+ *
+ * <p>
+ * The fingerprint is determined by a background thread that is started as
+ * soon as the node is instantiated. If this background thread has not
+ * finished when this method is invoked, the invoking thread will be blocked
+ * until the fingerprint is available (or determining it has failed,
+ * whereupon an exception will be thrown).
+ * </p>
+ *
+ * @return The fingerprint of this node.
+ * @throws PuppeTorException
+ * Thrown if either the temporary <code>torrc.temp</code>
+ * configuration file cannot be written, the Tor process cannot
+ * be started temporarily, or the fingerprint file cannot be
+ * read.
+ */
+ public abstract String getFingerprint() throws PuppeTorException;
}
diff --git a/src/org/torproject/puppetor/ServerApplication.java b/src/org/torproject/puppetor/ServerApplication.java
index 2859d97..16bbcab 100644
--- a/src/org/torproject/puppetor/ServerApplication.java
+++ b/src/org/torproject/puppetor/ServerApplication.java
@@ -15,44 +15,44 @@ package org.torproject.puppetor;
*/
public interface ServerApplication {
- /**
- * Starts listening for incoming <code>HTTP GET</code> requests from
- * clients. Any incoming request is answered by an empty
- * <code>HTTP OK</code> reply. This method may only be invoked when the
- * server is currently not in listening state!
- *
- * @throws IllegalStateException
- * Thrown if the server is currently not in listening state.
- */
- public abstract void startListening();
+ /**
+ * Starts listening for incoming <code>HTTP GET</code> requests from
+ * clients. Any incoming request is answered by an empty
+ * <code>HTTP OK</code> reply. This method may only be invoked when the
+ * server is currently not in listening state!
+ *
+ * @throws IllegalStateException
+ * Thrown if the server is currently not in listening state.
+ */
+ public abstract void startListening();
- /**
- * Stops listening for requests. This method may only be invoked when the
- * server is currently in listening state!
- *
- * @throws IllegalStateException
- * Thrown if the server is currently in listening state.
- */
- public abstract void stopListening();
+ /**
+ * Stops listening for requests. This method may only be invoked when the
+ * server is currently in listening state!
+ *
+ * @throws IllegalStateException
+ * Thrown if the server is currently in listening state.
+ */
+ public abstract void stopListening();
- /**
- * Returns whether this server is currently in listening state.
- *
- * @return The listening state of this server.
- */
- public abstract boolean isListening();
+ /**
+ * Returns whether this server is currently in listening state.
+ *
+ * @return The listening state of this server.
+ */
+ public abstract boolean isListening();
- /**
- * Returns the name of this server.
- *
- * @return The name of this server.
- */
- public abstract String getServerApplicationName();
+ /**
+ * Returns the name of this server.
+ *
+ * @return The name of this server.
+ */
+ public abstract String getServerApplicationName();
- /**
- * Returns the port on which this server listens.
- *
- * @return The port on which this server listens.
- */
- public abstract int getServerPort();
+ /**
+ * Returns the port on which this server listens.
+ *
+ * @return The port on which this server listens.
+ */
+ public abstract int getServerPort();
}
diff --git a/src/org/torproject/puppetor/ServerEventType.java b/src/org/torproject/puppetor/ServerEventType.java
index e98fd95..7f524d7 100644
--- a/src/org/torproject/puppetor/ServerEventType.java
+++ b/src/org/torproject/puppetor/ServerEventType.java
@@ -12,30 +12,30 @@ package org.torproject.puppetor;
@SuppressWarnings("serial")
public class ServerEventType implements EventType {
- /**
- * String identifying the type of the event type.
- */
- String typeString;
+ /**
+ * String identifying the type of the event type.
+ */
+ String typeString;
- /**
- * Creates a new event type with the given type string.
- *
- * @param typeString
- * String identifying the type of the event type.
- */
- public ServerEventType(final String typeString) {
- this.typeString = typeString;
- }
+ /**
+ * Creates a new event type with the given type string.
+ *
+ * @param typeString
+ * String identifying the type of the event type.
+ */
+ public ServerEventType(final String typeString) {
+ this.typeString = typeString;
+ }
- public String getTypeName() {
- return typeString;
- }
+ public String getTypeName() {
+ return typeString;
+ }
- /**
- * The server application has received a request and sent a reply to it;
- * this event is fired internally and not parsed from a log statement from
- * Tor.
- */
- public static final ServerEventType SERVER_RECEIVING_REQUEST_SENDING_REPLY =
- new ServerEventType("SERVER_RECEIVING_REQUEST_SENDING_REPLY");
-}
\ No newline at end of file
+ /**
+ * The server application has received a request and sent a reply to it;
+ * this event is fired internally and not parsed from a log statement from
+ * Tor.
+ */
+ public static final ServerEventType SERVER_RECEIVING_REQUEST_SENDING_REPLY =
+ new ServerEventType("SERVER_RECEIVING_REQUEST_SENDING_REPLY");
+}
diff --git a/src/org/torproject/puppetor/examples/AccessingPublicWebServerOverTor.java b/src/org/torproject/puppetor/examples/AccessingPublicWebServerOverTor.java
index 0d0d633..c9928e0 100644
--- a/src/org/torproject/puppetor/examples/AccessingPublicWebServerOverTor.java
+++ b/src/org/torproject/puppetor/examples/AccessingPublicWebServerOverTor.java
@@ -23,97 +23,97 @@ import org.torproject.puppetor.PuppeTorException;
*/
public class AccessingPublicWebServerOverTor {
- /**
- * Sets up and runs the test.
- *
- * @param args
- * Command-line arguments (ignored).
- * @throws PuppeTorException
- * Thrown if there is a problem with the JVM-external Tor
- * processes that we cannot handle.
- */
- public static void main(final String[] args) throws PuppeTorException {
-
- // though we only need a single proxy, we always need to create a
- // network to initialize a test case.
- final Network network = NetworkFactory.createNetwork("example1");
-
- // create a single proxy node with name "proxy"
- final ProxyNode proxy = network.createProxy("proxy");
-
- // write configuration of proxy node
- network.writeConfigurations();
-
- // start proxy node and wait until it has opened a circuit with a
- // timeout of 5 seconds
- if (!network.startNodes(5000)) {
-
- // failed to start the proxy
- System.out.println("Failed to start the node!");
- return;
- }
- System.out.println("Successfully started the node!");
-
- // hup until proxy has built circuits (5 retries, 10 seconds timeout
- // each)
- if (!network.hupUntilUp(5, 10000)) {
-
- // failed to build circuits
- System.out.println("Failed to build circuits!");
- System.exit(0);
- }
- System.out.println("Successfully built circuits!");
-
- // create client application
- final ClientApplication client =
- network.createClient("client", "www.google.com", 80, proxy
- .getSocksPort());
-
- // create event listener to listen for client application events
- final EventListener clientEventListener = new EventListener() {
-
- // remember time when request was sent
- private long before;
-
- public void handleEvent(Event event) {
- if (event.getType() == ClientEventType.CLIENT_SENDING_REQUEST) {
- before = System.currentTimeMillis();
- } else if (event.getType() == ClientEventType.CLIENT_REPLY_RECEIVED) {
- System.out.println("Request took "
- + (System.currentTimeMillis() - before)
- + " milliseconds");
- }
- }
- };
-
- // obtain reference to event manager to be able to respond to events
- final EventManager manager = network.getEventManager();
-
- // register event handler for client application events
- manager.addEventListener(client.getClientApplicationName(),
- clientEventListener);
-
- // perform at most three request with a timeout of 20 seconds each
- client.startRequests(3, 20000, true);
-
- // block this thread as long as client requests are running
- manager.waitForAnyOccurence(client.getClientApplicationName(),
- ClientEventType.CLIENT_REQUESTS_PERFORMED);
-
- // wait a second before shutting down the proxy
- try {
- Thread.sleep(1000);
- } catch (final InterruptedException e) {}
-
- // shut down proxy
- network.shutdownNodes();
-
- // wait another second before exiting the application
- try {
- Thread.sleep(1000);
- } catch (final InterruptedException e) {}
-
- // Shut down the JVM
- System.out.println("Goodbye.");
- }
+ /**
+ * Sets up and runs the test.
+ *
+ * @param args
+ * Command-line arguments (ignored).
+ * @throws PuppeTorException
+ * Thrown if there is a problem with the JVM-external Tor
+ * processes that we cannot handle.
+ */
+ public static void main(final String[] args) throws PuppeTorException {
+
+ // though we only need a single proxy, we always need to create a
+ // network to initialize a test case.
+ final Network network = NetworkFactory.createNetwork("example1");
+
+ // create a single proxy node with name "proxy"
+ final ProxyNode proxy = network.createProxy("proxy");
+
+ // write configuration of proxy node
+ network.writeConfigurations();
+
+ // start proxy node and wait until it has opened a circuit with a
+ // timeout of 5 seconds
+ if (!network.startNodes(5000)) {
+
+ // failed to start the proxy
+ System.out.println("Failed to start the node!");
+ return;
+ }
+ System.out.println("Successfully started the node!");
+
+ // hup until proxy has built circuits (5 retries, 10 seconds timeout
+ // each)
+ if (!network.hupUntilUp(5, 10000)) {
+
+ // failed to build circuits
+ System.out.println("Failed to build circuits!");
+ System.exit(0);
+ }
+ System.out.println("Successfully built circuits!");
+
+ // create client application
+ final ClientApplication client =
+ network.createClient("client", "www.google.com", 80, proxy
+ .getSocksPort());
+
+ // create event listener to listen for client application events
+ final EventListener clientEventListener = new EventListener() {
+
+ // remember time when request was sent
+ private long before;
+
+ public void handleEvent(Event event) {
+ if (event.getType() == ClientEventType.CLIENT_SENDING_REQUEST) {
+ before = System.currentTimeMillis();
+ } else if (event.getType() == ClientEventType.CLIENT_REPLY_RECEIVED) {
+ System.out.println("Request took "
+ + (System.currentTimeMillis() - before)
+ + " milliseconds");
+ }
+ }
+ };
+
+ // obtain reference to event manager to be able to respond to events
+ final EventManager manager = network.getEventManager();
+
+ // register event handler for client application events
+ manager.addEventListener(client.getClientApplicationName(),
+ clientEventListener);
+
+ // perform at most three request with a timeout of 20 seconds each
+ client.startRequests(3, 20000, true);
+
+ // block this thread as long as client requests are running
+ manager.waitForAnyOccurence(client.getClientApplicationName(),
+ ClientEventType.CLIENT_REQUESTS_PERFORMED);
+
+ // wait a second before shutting down the proxy
+ try {
+ Thread.sleep(1000);
+ } catch (final InterruptedException e) {}
+
+ // shut down proxy
+ network.shutdownNodes();
+
+ // wait another second before exiting the application
+ try {
+ Thread.sleep(1000);
+ } catch (final InterruptedException e) {}
+
+ // Shut down the JVM
+ System.out.println("Goodbye.");
+ }
}
diff --git a/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java b/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java
index d2d7016..e123ee7 100644
--- a/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java
+++ b/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java
@@ -26,107 +26,107 @@ import org.torproject.puppetor.ServerApplication;
*/
public class AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork {
- /**
- * Sets up and runs the test.
- *
- * @param args
- * Command-line arguments (ignored).
- * @throws PuppeTorException
- * Thrown if there is a problem with the JVM-external Tor
- * processes that we cannot handle.
- */
- public static void main(final String[] args) throws PuppeTorException {
-
- // create a network to initialize the test case
- final Network network = NetworkFactory.createNetwork("example4");
-
- // create three router nodes
- final RouterNode router1 = network.createRouter("router1");
- network.createRouter("router2");
- final RouterNode router3 = network.createRouter("router3");
-
- // create only one directory node
- network.createDirectory("dir1");
-
- // add hidden service
- final HiddenService hidServ1 = router1.addHiddenService("hidServ");
-
- // configure nodes of this network to be part of a private network
- network.configureAsPrivateNetwork();
-
- // write node configurations
- network.writeConfigurations();
-
- // start nodes and wait until they have opened a circuit with a timeout
- // of 5 seconds
- if (!network.startNodes(5000)) {
-
- // failed to start the nodes
- System.out.println("Failed to start nodes!");
- System.exit(0);
- }
- System.out.println("Successfully started nodes!");
-
- // hup until nodes have built circuits (60 retries, 10 seconds timeout
- // each)
- if (!network.hupUntilUp(60, 10000)) {
-
- // failed to build circuits
- System.out.println("Failed to build circuits!");
- System.exit(0);
- }
- System.out.println("Successfully built circuits!");
-
- // obtain reference to event manager to be able to respond to events
- final EventManager manager = network.getEventManager();
-
- // wait for 1 hour that the proxy has published its first RSD
- if (!manager.waitForAnyOccurence(router1.getNodeName(),
- HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED,
- 1L * 60L * 60L * 1000L)) {
- // failed to publish an RSD
- System.out.println("Failed to publish an RSD!");
- System.exit(0);
- }
- System.out.println("Successfully published an RSD!");
-
- // create server application
- final ServerApplication server =
- network.createServer("server", hidServ1.getServicePort());
-
- // create client application
- final ClientApplication client =
- network.createClient("client",
- hidServ1.determineOnionAddress(), hidServ1
- .getVirtualPort(), router3.getSocksPort());
-
- // register event listener
- final EventListener clientAndServerEventListener = new EventListener() {
- public void handleEvent(Event event) {
- System.out.println("Handling event: " + event.getMessage());
- }
- };
- manager.addEventListener(client.getClientApplicationName(),
- clientAndServerEventListener);
- manager.addEventListener(server.getServerApplicationName(),
- clientAndServerEventListener);
-
- // start server
- server.startListening();
- System.out.println("Started server");
-
- // perform at most five request with a timeout of 45 seconds each
- client.startRequests(5, 45000, true);
-
- // wait for request to be performed
- manager.waitForAnyOccurence(client.getClientApplicationName(),
- ClientEventType.CLIENT_REQUESTS_PERFORMED);
-
- // shut down nodes
- network.shutdownNodes();
-
- // Shut down the JVM
- System.out.println("Goodbye.");
- System.exit(0);
- }
+ /**
+ * Sets up and runs the test.
+ *
+ * @param args
+ * Command-line arguments (ignored).
+ * @throws PuppeTorException
+ * Thrown if there is a problem with the JVM-external Tor
+ * processes that we cannot handle.
+ */
+ public static void main(final String[] args) throws PuppeTorException {
+
+ // create a network to initialize the test case
+ final Network network = NetworkFactory.createNetwork("example4");
+
+ // create three router nodes
+ final RouterNode router1 = network.createRouter("router1");
+ network.createRouter("router2");
+ final RouterNode router3 = network.createRouter("router3");
+
+ // create only one directory node
+ network.createDirectory("dir1");
+
+ // add hidden service
+ final HiddenService hidServ1 = router1.addHiddenService("hidServ");
+
+ // configure nodes of this network to be part of a private network
+ network.configureAsPrivateNetwork();
+
+ // write node configurations
+ network.writeConfigurations();
+
+ // start nodes and wait until they have opened a circuit with a timeout
+ // of 5 seconds
+ if (!network.startNodes(5000)) {
+
+ // failed to start the nodes
+ System.out.println("Failed to start nodes!");
+ System.exit(0);
+ }
+ System.out.println("Successfully started nodes!");
+
+ // hup until nodes have built circuits (60 retries, 10 seconds timeout
+ // each)
+ if (!network.hupUntilUp(60, 10000)) {
+
+ // failed to build circuits
+ System.out.println("Failed to build circuits!");
+ System.exit(0);
+ }
+ System.out.println("Successfully built circuits!");
+
+ // obtain reference to event manager to be able to respond to events
+ final EventManager manager = network.getEventManager();
+
+ // wait for 1 hour that the proxy has published its first RSD
+ if (!manager.waitForAnyOccurence(router1.getNodeName(),
+ HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED,
+ 1L * 60L * 60L * 1000L)) {
+ // failed to publish an RSD
+ System.out.println("Failed to publish an RSD!");
+ System.exit(0);
+ }
+ System.out.println("Successfully published an RSD!");
+
+ // create server application
+ final ServerApplication server =
+ network.createServer("server", hidServ1.getServicePort());
+
+ // create client application
+ final ClientApplication client =
+ network.createClient("client",
+ hidServ1.determineOnionAddress(), hidServ1
+ .getVirtualPort(), router3.getSocksPort());
+
+ // register event listener
+ final EventListener clientAndServerEventListener = new EventListener() {
+ public void handleEvent(Event event) {
+ System.out.println("Handling event: " + event.getMessage());
+ }
+ };
+ manager.addEventListener(client.getClientApplicationName(),
+ clientAndServerEventListener);
+ manager.addEventListener(server.getServerApplicationName(),
+ clientAndServerEventListener);
+
+ // start server
+ server.startListening();
+ System.out.println("Started server");
+
+ // perform at most five request with a timeout of 45 seconds each
+ client.startRequests(5, 45000, true);
+
+ // wait for request to be performed
+ manager.waitForAnyOccurence(client.getClientApplicationName(),
+ ClientEventType.CLIENT_REQUESTS_PERFORMED);
+
+ // shut down nodes
+ network.shutdownNodes();
+
+ // Shut down the JVM
+ System.out.println("Goodbye.");
+ System.exit(0);
+ }
}
diff --git a/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java b/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java
index 87675c3..4e65f68 100644
--- a/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java
+++ b/src/org/torproject/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java
@@ -27,123 +27,123 @@ import org.torproject.puppetor.ServerEventType;
*/
public class AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork {
- /**
- * Sets up and runs the test.
- *
- * @param args
- * Command-line arguments (ignored).
- * @throws PuppeTorException
- * Thrown if there is a problem with the JVM-external Tor
- * processes that we cannot handle.
- */
- public static void main(final String[] args) throws PuppeTorException {
-
- // create a network to initialize the test case
- final Network network = NetworkFactory.createNetwork("example3");
-
- // create two proxy nodes
- final ProxyNode proxy1 = network.createProxy("proxy1");
- final ProxyNode proxy2 = network.createProxy("proxy2");
-
- // add hidden service to the configuration of proxy1
- final HiddenService hidServ1 = proxy1.addHiddenService("hidServ");
-
- // write configuration of proxy nodes
- network.writeConfigurations();
-
- // start nodes and wait until they have opened a circuit with a timeout
- // of 5 seconds
- if (!network.startNodes(5000)) {
-
- // failed to start the proxy
- System.out.println("Failed to start nodes!");
- System.exit(0);
- }
- System.out.println("Successfully started nodes!");
-
- // hup until nodes have built circuits (5 retries, 10 seconds timeout
- // each)
- if (!network.hupUntilUp(5, 10000)) {
-
- // failed to build circuits
- System.out.println("Failed to build circuits!");
- System.exit(0);
- }
- System.out.println("Successfully built circuits!");
-
- // obtain reference to event manager to be able to respond to events
- final EventManager manager = network.getEventManager();
-
- // wait for 3 minutes that the proxy has published its first RSD
- if (!manager.waitForAnyOccurence(proxy1.getNodeName(),
- HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED,
- 3L * 60L * 1000L)) {
-
- // failed to publish an RSD
- System.out.println("Failed to publish an RSD!");
- System.exit(0);
- }
- System.out.println("Successfully published an RSD!");
-
- // create server application
- final ServerApplication server =
- network.createServer("server", hidServ1.getServicePort());
-
- // create client application
- final ClientApplication client =
- network.createClient("client",
- hidServ1.determineOnionAddress(), hidServ1
- .getVirtualPort(), proxy2.getSocksPort());
-
- // create event listener to listen for client and server application
- // events
- final EventListener clientAndServerEventListener = new EventListener() {
-
- private long requestReceivedAtServer;
-
- // remember time when request was sent and when it was received
- private long requestSentFromClient;
-
- public void handleEvent(Event event) {
- if (event.getType() == ClientEventType.CLIENT_SENDING_REQUEST) {
- requestSentFromClient = event.getOccurrenceTime();
- } else if (event.getType() == ServerEventType.SERVER_RECEIVING_REQUEST_SENDING_REPLY) {
- requestReceivedAtServer = event.getOccurrenceTime();
- System.out.println("Request took "
- + (requestReceivedAtServer - requestSentFromClient)
- + " milliseconds from client to server!");
- } else if (event.getType() == ClientEventType.CLIENT_REPLY_RECEIVED) {
- System.out
- .println("Request took "
- + (event.getOccurrenceTime() - requestSentFromClient)
- + " milliseconds for the round-trip and "
- + (event.getOccurrenceTime() - requestReceivedAtServer)
- + " milliseconds from server to client!");
- }
- }
- };
-
- // register event handler for client and server application events
- manager.addEventListener(client.getClientApplicationName(),
- clientAndServerEventListener);
- manager.addEventListener(server.getServerApplicationName(),
- clientAndServerEventListener);
-
- // start server
- server.startListening();
-
- // perform at most five request with a timeout of 45 seconds each
- client.startRequests(5, 45000, true);
-
- // block this thread as long as client requests are running
- manager.waitForAnyOccurence(client.getClientApplicationName(),
- ClientEventType.CLIENT_REQUESTS_PERFORMED);
-
- // shut down proxy
- network.shutdownNodes();
-
- // Shut down the JVM
- System.out.println("Goodbye.");
- System.exit(0);
- }
+ /**
+ * Sets up and runs the test.
+ *
+ * @param args
+ * Command-line arguments (ignored).
+ * @throws PuppeTorException
+ * Thrown if there is a problem with the JVM-external Tor
+ * processes that we cannot handle.
+ */
+ public static void main(final String[] args) throws PuppeTorException {
+
+ // create a network to initialize the test case
+ final Network network = NetworkFactory.createNetwork("example3");
+
+ // create two proxy nodes
+ final ProxyNode proxy1 = network.createProxy("proxy1");
+ final ProxyNode proxy2 = network.createProxy("proxy2");
+
+ // add hidden service to the configuration of proxy1
+ final HiddenService hidServ1 = proxy1.addHiddenService("hidServ");
+
+ // write configuration of proxy nodes
+ network.writeConfigurations();
+
+ // start nodes and wait until they have opened a circuit with a timeout
+ // of 5 seconds
+ if (!network.startNodes(5000)) {
+
+ // failed to start the proxy
+ System.out.println("Failed to start nodes!");
+ System.exit(0);
+ }
+ System.out.println("Successfully started nodes!");
+
+ // hup until nodes have built circuits (5 retries, 10 seconds timeout
+ // each)
+ if (!network.hupUntilUp(5, 10000)) {
+
+ // failed to build circuits
+ System.out.println("Failed to build circuits!");
+ System.exit(0);
+ }
+ System.out.println("Successfully built circuits!");
+
+ // obtain reference to event manager to be able to respond to events
+ final EventManager manager = network.getEventManager();
+
+ // wait for 3 minutes that the proxy has published its first RSD
+ if (!manager.waitForAnyOccurence(proxy1.getNodeName(),
+ HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED,
+ 3L * 60L * 1000L)) {
+
+ // failed to publish an RSD
+ System.out.println("Failed to publish an RSD!");
+ System.exit(0);
+ }
+ System.out.println("Successfully published an RSD!");
+
+ // create server application
+ final ServerApplication server =
+ network.createServer("server", hidServ1.getServicePort());
+
+ // create client application
+ final ClientApplication client =
+ network.createClient("client",
+ hidServ1.determineOnionAddress(), hidServ1
+ .getVirtualPort(), proxy2.getSocksPort());
+
+ // create event listener to listen for client and server application
+ // events
+ final EventListener clientAndServerEventListener = new EventListener() {
+
+ private long requestReceivedAtServer;
+
+ // remember time when request was sent and when it was received
+ private long requestSentFromClient;
+
+ public void handleEvent(Event event) {
+ if (event.getType() == ClientEventType.CLIENT_SENDING_REQUEST) {
+ requestSentFromClient = event.getOccurrenceTime();
+ } else if (event.getType() == ServerEventType.SERVER_RECEIVING_REQUEST_SENDING_REPLY) {
+ requestReceivedAtServer = event.getOccurrenceTime();
+ System.out.println("Request took "
+ + (requestReceivedAtServer - requestSentFromClient)
+ + " milliseconds from client to server!");
+ } else if (event.getType() == ClientEventType.CLIENT_REPLY_RECEIVED) {
+ System.out
+ .println("Request took "
+ + (event.getOccurrenceTime() - requestSentFromClient)
+ + " milliseconds for the round-trip and "
+ + (event.getOccurrenceTime() - requestReceivedAtServer)
+ + " milliseconds from server to client!");
+ }
+ }
+ };
+
+ // register event handler for client and server application events
+ manager.addEventListener(client.getClientApplicationName(),
+ clientAndServerEventListener);
+ manager.addEventListener(server.getServerApplicationName(),
+ clientAndServerEventListener);
+
+ // start server
+ server.startListening();
+
+ // perform at most five request with a timeout of 45 seconds each
+ client.startRequests(5, 45000, true);
+
+ // block this thread as long as client requests are running
+ manager.waitForAnyOccurence(client.getClientApplicationName(),
+ ClientEventType.CLIENT_REQUESTS_PERFORMED);
+
+ // shut down proxy
+ network.shutdownNodes();
+
+ // Shut down the JVM
+ System.out.println("Goodbye.");
+ System.exit(0);
+ }
}
diff --git a/src/org/torproject/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java b/src/org/torproject/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java
index 2f9773a..8040f25 100644
--- a/src/org/torproject/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java
+++ b/src/org/torproject/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java
@@ -23,88 +23,88 @@ import org.torproject.puppetor.PuppeTorException;
*/
public class AdvertisingHiddenServiceToPublicTorNetwork {
- /**
- * Sets up and runs the test.
- *
- * @param args
- * Command-line arguments (ignored).
- * @throws PuppeTorException
- * Thrown if there is a problem with the JVM-external Tor
- * processes that we cannot handle.
- */
- public static void main(final String[] args) throws PuppeTorException {
- // create a network to initialize the test case
- final Network network = NetworkFactory.createNetwork("example2");
-
- // create a single proxy node
- final ProxyNode proxy = network.createProxy("proxy");
-
- // add hidden service to the configuration
- proxy.addHiddenService("hidServ");
-
- // write configuration of proxy node
- network.writeConfigurations();
-
- // create event listener to listen for events from our proxy
- final EventListener proxyEventListener = new EventListener() {
-
- // remember time when request was sent
- private long circuitOpened = -1;
-
- public void handleEvent(Event event) {
- if (event.getType() == NodeEventType.NODE_CIRCUIT_OPENED) {
- if (circuitOpened == -1) {
- circuitOpened = System.currentTimeMillis();
- }
- } else if (event.getType() == HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED) {
- System.out.println("RSD published "
- + (System.currentTimeMillis() - circuitOpened)
- + " milliseconds after first circuit was opened");
- }
- }
- };
-
- // obtain reference to event manager to be able to respond to events
- final EventManager manager = network.getEventManager();
-
- // register event handler for proxy events
- manager.addEventListener(proxy.getNodeName(), proxyEventListener);
-
- // start proxy node and wait until it has opened a circuit with a
- // timeout of 5 seconds
- if (!network.startNodes(5000)) {
-
- // failed to start the proxy
- System.out.println("Failed to start the node!");
- System.exit(0);
- }
- System.out.println("Successfully started the node!");
-
- // hup until proxy has built circuits (5 retries, 10 seconds timeout
- // each)
- if (!network.hupUntilUp(5, 10000)) {
-
- // failed to build circuits
- System.out.println("Failed to build circuits!");
- System.exit(0);
- }
- System.out.println("Successfully built circuits!");
-
- // let it run for 2 minutes and observe when RSDs are published...
- System.out
- .println("Waiting for 2 minutes and observing RSD publications...");
-
- try {
- Thread.sleep(2L * 60L * 1000L);
- } catch (final InterruptedException e) {
- // do nothing
- }
-
- // shut down proxy
- network.shutdownNodes();
-
- // Shut down the JVM
- System.out.println("Goodbye.");
- System.exit(0);
- }
+ /**
+ * Sets up and runs the test.
+ *
+ * @param args
+ * Command-line arguments (ignored).
+ * @throws PuppeTorException
+ * Thrown if there is a problem with the JVM-external Tor
+ * processes that we cannot handle.
+ */
+ public static void main(final String[] args) throws PuppeTorException {
+ // create a network to initialize the test case
+ final Network network = NetworkFactory.createNetwork("example2");
+
+ // create a single proxy node
+ final ProxyNode proxy = network.createProxy("proxy");
+
+ // add hidden service to the configuration
+ proxy.addHiddenService("hidServ");
+
+ // write configuration of proxy node
+ network.writeConfigurations();
+
+ // create event listener to listen for events from our proxy
+ final EventListener proxyEventListener = new EventListener() {
+
+ // remember time when request was sent
+ private long circuitOpened = -1;
+
+ public void handleEvent(Event event) {
+ if (event.getType() == NodeEventType.NODE_CIRCUIT_OPENED) {
+ if (circuitOpened == -1) {
+ circuitOpened = System.currentTimeMillis();
+ }
+ } else if (event.getType() == HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED) {
+ System.out.println("RSD published "
+ + (System.currentTimeMillis() - circuitOpened)
+ + " milliseconds after first circuit was opened");
+ }
+ }
+ };
+
+ // obtain reference to event manager to be able to respond to events
+ final EventManager manager = network.getEventManager();
+
+ // register event handler for proxy events
+ manager.addEventListener(proxy.getNodeName(), proxyEventListener);
+
+ // start proxy node and wait until it has opened a circuit with a
+ // timeout of 5 seconds
+ if (!network.startNodes(5000)) {
+
+ // failed to start the proxy
+ System.out.println("Failed to start the node!");
+ System.exit(0);
+ }
+ System.out.println("Successfully started the node!");
+
+ // hup until proxy has built circuits (5 retries, 10 seconds timeout
+ // each)
+ if (!network.hupUntilUp(5, 10000)) {
+
+ // failed to build circuits
+ System.out.println("Failed to build circuits!");
+ System.exit(0);
+ }
+ System.out.println("Successfully built circuits!");
+
+ // let it run for 2 minutes and observe when RSDs are published...
+ System.out
+ .println("Waiting for 2 minutes and observing RSD publications...");
+
+ try {
+ Thread.sleep(2L * 60L * 1000L);
+ } catch (final InterruptedException e) {
+ // do nothing
+ }
+
+ // shut down proxy
+ network.shutdownNodes();
+
+ // Shut down the JVM
+ System.out.println("Goodbye.");
+ System.exit(0);
+ }
}
diff --git a/src/org/torproject/puppetor/impl/ClientApplicationImpl.java b/src/org/torproject/puppetor/impl/ClientApplicationImpl.java
index ef4cbb4..bbbcf8a 100644
--- a/src/org/torproject/puppetor/impl/ClientApplicationImpl.java
+++ b/src/org/torproject/puppetor/impl/ClientApplicationImpl.java
@@ -28,431 +28,431 @@ import org.torproject.puppetor.ClientEventType;
*/
public class ClientApplicationImpl implements ClientApplication {
- /**
- * Internal thread class that is used to perform requests.
- */
- private class RequestThread extends Thread {
-
- /**
- * Flag to remember whether requests are performed at the moment (<code>true</code>),
- * or have been stopped (<code>false</code>).
- */
- private boolean connected;
-
- /**
- * Number of retries to be performed.
- */
- private final int retries;
-
- /**
- * Flag that determines whether requests shall be stopped after the
- * first successful reply (<code>true</code>), or not (<code>false</code>).
- */
- private final boolean stopOnSuccess;
-
- /**
- * Timeout in milliseconds for each retry.
- */
- private final long timeoutForEachRetry;
-
- /**
- * Creates a new thread, but does not start performing requests, yet.
- *
- * @param retries
- * Number of retries to be performed.
- * @param timeoutForEachRetry
- * Timeout in milliseconds for each retry.
- * @param stopOnSuccess
- * Flag that determines whether requests shall be stopped
- * after the first successful reply (<code>true</code>),
- * or not (<code>false</code>).
- */
- RequestThread(final int retries, final long timeoutForEachRetry,
- final boolean stopOnSuccess) {
-
- // log entering
- logger
- .entering(this.getClass().getName(), "RequestThread",
- new Object[] { retries, timeoutForEachRetry,
- stopOnSuccess });
-
- // check parameters
- if (retries < 0 || timeoutForEachRetry < 0) {
- final IllegalArgumentException e =
- new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "RequestThread", e);
- throw e;
- }
-
- // remember parameters
- this.retries = retries;
- this.timeoutForEachRetry = timeoutForEachRetry;
- this.stopOnSuccess = stopOnSuccess;
-
- // start connected
- connected = true;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "RequestThread");
- }
-
- /**
- * Perform one or more requests.
- */
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- try {
-
- // set Tor as proxy
- final InetSocketAddress isa =
- new InetSocketAddress("127.0.0.1", socksPort);
- final Proxy p = new Proxy(Type.SOCKS, isa);
-
- // create target address for socket -- don't resolve the target
- // name to an IP address!
- final InetSocketAddress hs =
- InetSocketAddress.createUnresolved(targetName,
- targetPort);
-
- // start retry loop
- for (int i = 0; connected && i < retries; i++) {
-
- // log this try
- logger.log(Level.FINE, "Trying to perform request");
-
- // remember when we started
- final long timeBeforeConnectionAttempt =
- System.currentTimeMillis();
-
- // send event to event manager
- eventManager.observeInternalEvent(
- timeBeforeConnectionAttempt,
- getClientApplicationName(),
- ClientEventType.CLIENT_SENDING_REQUEST,
- "Sending request.");
-
- Socket s = null;
- try {
-
- // create new socket using Tor as proxy
- s = new Socket(p);
-
- // try to connect to remote server
- s.connect(hs, (int) timeoutForEachRetry);
-
- // open output stream to write request
- final PrintStream out =
- new PrintStream(s.getOutputStream());
- out.print("GET / HTTP/1.0\r\n\r\n");
-
- // open input stream to read reply
- final BufferedReader in =
- new BufferedReader(new InputStreamReader(s
- .getInputStream()));
-
- // only read the first char in the response; this method
- // blocks until there is a response
- in.read();
-
- // send event to event manager
- eventManager.observeInternalEvent(System
- .currentTimeMillis(),
- getClientApplicationName(),
- ClientEventType.CLIENT_REPLY_RECEIVED,
- "Received response.");
-
- // if we should stop on success, stop further connection
- // attempts
- if (stopOnSuccess) {
- connected = false;
- }
-
- // clean up socket
- in.close();
- out.close();
- s.close();
-
- } catch (final SocketTimeoutException e) {
-
- // log warning
- logger.log(Level.WARNING,
- "Connection to remote server timed out!", e);
-
- // send event to event manager
- eventManager.observeInternalEvent(System
- .currentTimeMillis(),
- getClientApplicationName(),
- ClientEventType.CLIENT_GAVE_UP_REQUEST,
- "Giving up request.");
-
- // try again immediately, if there are retries left
-
- } catch (final IOException e) {
-
- // log warning
- logger.log(Level.WARNING,
- "Connection to remote server could not be "
- + "established!", e);
-
- // send event to event manager
- eventManager.observeInternalEvent(System
- .currentTimeMillis(),
- getClientApplicationName(),
- ClientEventType.CLIENT_GAVE_UP_REQUEST,
- "Giving up request.");
-
- // wait for the rest of the timeout
- final long timeOfTimeoutLeft =
- timeBeforeConnectionAttempt
- + timeoutForEachRetry
- - System.currentTimeMillis();
- if (timeOfTimeoutLeft > 0) {
- try {
- Thread.sleep(timeOfTimeoutLeft);
- } catch (final InterruptedException ex) {
- // do nothing
- }
- }
-
- } finally {
- if (s != null) {
- // close connection
- try {
-
- // try to close socket
- logger.log(Level.FINER,
- "Trying to close socket.");
- s.close();
- logger.log(Level.FINE, "Socket closed.");
-
- } catch (final IOException e) {
-
- // log warning
- logger.log(Level.WARNING,
- "Exception when trying to close socket!",
- e);
- }
- }
- }
- }
-
- } finally {
-
- // we are done here
- logger.log(Level.FINE, "Requests performed!");
-
- // send event to event manager
- eventManager.observeInternalEvent(System.currentTimeMillis(),
- getClientApplicationName(),
- ClientEventType.CLIENT_REQUESTS_PERFORMED,
- "Requests performed.");
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
- }
-
- /**
- * Immediately stops this and all possibly subsequent requests.
- */
- public void stopRequest() {
-
- // log entering
- logger.entering(this.getClass().getName(), "stopRequest");
-
- // change connected state to false and interrupt thread
- connected = false;
- interrupt();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "stopRequest");
- }
- }
-
- /**
- * Name of this client application that is used as logger name of this node.
- */
- private final String clientApplicationName;
-
- /**
- * Thread that performs the requests in the background.
- */
- private RequestThread clientThread;
-
- /**
- * Event manager that handles all events concerning this client application.
- */
- private final EventManagerImpl eventManager;
-
- /**
- * Logger for this client which is called "client." plus the name of this
- * client application.
- */
- private final Logger logger;
-
- /**
- * SOCKS port of the local Tor node to which requests are sent.
- */
- private final int socksPort;
-
- /**
- * Target name for the requests sent by this client; can be a publicly
- * available URL or an onion address.
- */
- private final String targetName;
-
- /**
- * Target port for the requests sent by this client; can be either a server
- * port or a virtual port of a hidden service.
- */
- private final int targetPort;
-
- /**
- * Creates a new HTTP client within this JVM, but does not start sending
- * requests.
- *
- * @param network
- * Network to which this HTTP client belongs; at the moment this
- * is only used to determine the event manager instance.
- * @param clientApplicationName
- * Name of this client that is used as part of the logger name.
- * @param targetName
- * Target name for requests; can be either a server name/address
- * or an onion address.
- * @param targetPort
- * Target port for requests; can be either a server port or a
- * virtual port of a hidden service.
- * @param socksPort
- * SOCKS port of the local Tor node.
- * @throws IllegalArgumentException
- * If at least one of the parameters is <code>null</code> or
- * has an invalid value.
- */
- ClientApplicationImpl(final NetworkImpl network,
- final String clientApplicationName, final String targetName,
- final int targetPort, final int socksPort) {
-
- // check if clientApplicationName can be used as logger name
- if (clientApplicationName == null
- || clientApplicationName.length() == 0) {
- throw new IllegalArgumentException(
- "Invalid clientApplicationName: " + clientApplicationName);
- }
-
- // create logger
- logger = Logger.getLogger("client." + clientApplicationName);
-
- // log entering
- logger.entering(this.getClass().getName(), "ClientApplicationImpl",
- new Object[] { network, clientApplicationName, targetName,
- targetPort, socksPort });
-
- // check parameters
- if (network == null || targetName == null || targetName.length() == 0
- || targetPort < 0 || targetPort > 65535 || socksPort < 0
- || socksPort > 65535) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "ClientApplicationImpl",
- e);
- throw e;
- }
-
- // remember parameters
- this.clientApplicationName = clientApplicationName;
- this.targetName = targetName;
- this.targetPort = targetPort;
- this.socksPort = socksPort;
-
- // obtain and store reference on event manager
- eventManager = network.getEventManagerImpl();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "ClientApplicationImpl");
- }
-
- public synchronized void startRequests(final int retries,
- final long timeoutForEachRetry, final boolean stopOnSuccess) {
-
- // log entering
- logger.entering(this.getClass().getName(), "performRequest",
- new Object[] { retries, timeoutForEachRetry, stopOnSuccess });
-
- // check parameters
- if (retries <= 0 || timeoutForEachRetry < 0) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "performRequest", e);
- throw e;
- }
-
- // check if we already have started a request (TODO change this to allow
- // multiple requests in parallel? would be possible)
- if (clientThread != null) {
- final IllegalStateException e =
- new IllegalStateException(
- "Another request has already been started!");
- logger.throwing(this.getClass().getName(), "performRequest", e);
- throw e;
- }
-
- // create a thread that performs requests in the background
- clientThread =
- new RequestThread(retries, timeoutForEachRetry, stopOnSuccess);
- clientThread.setName("Request Thread");
- clientThread.setDaemon(true);
- clientThread.start();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "performRequest");
- }
-
- public synchronized void stopRequest() {
-
- // log entering
- logger.entering(this.getClass().getName(), "stopRequest");
-
- // check if a request is running
- if (clientThread == null) {
- final IllegalStateException e =
- new IllegalStateException("Cannot stop "
- + "request, because no request has been started!");
- logger.throwing(this.getClass().getName(), "stopRequest", e);
- throw e;
- }
-
- // log this event
- logger.log(Level.FINE, "Shutting down client");
-
- // interrupt thread
- clientThread.stopRequest();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "stopRequest");
- }
-
- @Override
- public String toString() {
- return this.getClass().getSimpleName() + ": clientApplicationName=\""
- + clientApplicationName + "\", targetAddress=\"" + targetName
- + "\", targetPort=" + targetPort + ", socksPort=" + socksPort;
- }
-
- public String getClientApplicationName() {
- return clientApplicationName;
- }
-
- public int getSocksPort() {
- return socksPort;
- }
-
- public String getTargetName() {
- return targetName;
- }
-
- public int getTargetPort() {
- return targetPort;
- }
+ /**
+ * Internal thread class that is used to perform requests.
+ */
+ private class RequestThread extends Thread {
+
+ /**
+ * Flag to remember whether requests are performed at the moment (<code>true</code>),
+ * or have been stopped (<code>false</code>).
+ */
+ private boolean connected;
+
+ /**
+ * Number of retries to be performed.
+ */
+ private final int retries;
+
+ /**
+ * Flag that determines whether requests shall be stopped after the
+ * first successful reply (<code>true</code>), or not (<code>false</code>).
+ */
+ private final boolean stopOnSuccess;
+
+ /**
+ * Timeout in milliseconds for each retry.
+ */
+ private final long timeoutForEachRetry;
+
+ /**
+ * Creates a new thread, but does not start performing requests, yet.
+ *
+ * @param retries
+ * Number of retries to be performed.
+ * @param timeoutForEachRetry
+ * Timeout in milliseconds for each retry.
+ * @param stopOnSuccess
+ * Flag that determines whether requests shall be stopped
+ * after the first successful reply (<code>true</code>),
+ * or not (<code>false</code>).
+ */
+ RequestThread(final int retries, final long timeoutForEachRetry,
+ final boolean stopOnSuccess) {
+
+ // log entering
+ logger
+ .entering(this.getClass().getName(), "RequestThread",
+ new Object[] { retries, timeoutForEachRetry,
+ stopOnSuccess });
+
+ // check parameters
+ if (retries < 0 || timeoutForEachRetry < 0) {
+ final IllegalArgumentException e =
+ new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "RequestThread", e);
+ throw e;
+ }
+
+ // remember parameters
+ this.retries = retries;
+ this.timeoutForEachRetry = timeoutForEachRetry;
+ this.stopOnSuccess = stopOnSuccess;
+
+ // start connected
+ connected = true;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "RequestThread");
+ }
+
+ /**
+ * Perform one or more requests.
+ */
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ try {
+
+ // set Tor as proxy
+ final InetSocketAddress isa =
+ new InetSocketAddress("127.0.0.1", socksPort);
+ final Proxy p = new Proxy(Type.SOCKS, isa);
+
+ // create target address for socket -- don't resolve the target
+ // name to an IP address!
+ final InetSocketAddress hs =
+ InetSocketAddress.createUnresolved(targetName,
+ targetPort);
+
+ // start retry loop
+ for (int i = 0; connected && i < retries; i++) {
+
+ // log this try
+ logger.log(Level.FINE, "Trying to perform request");
+
+ // remember when we started
+ final long timeBeforeConnectionAttempt =
+ System.currentTimeMillis();
+
+ // send event to event manager
+ eventManager.observeInternalEvent(
+ timeBeforeConnectionAttempt,
+ getClientApplicationName(),
+ ClientEventType.CLIENT_SENDING_REQUEST,
+ "Sending request.");
+
+ Socket s = null;
+ try {
+
+ // create new socket using Tor as proxy
+ s = new Socket(p);
+
+ // try to connect to remote server
+ s.connect(hs, (int) timeoutForEachRetry);
+
+ // open output stream to write request
+ final PrintStream out =
+ new PrintStream(s.getOutputStream());
+ out.print("GET / HTTP/1.0\r\n\r\n");
+
+ // open input stream to read reply
+ final BufferedReader in =
+ new BufferedReader(new InputStreamReader(s
+ .getInputStream()));
+
+ // only read the first char in the response; this method
+ // blocks until there is a response
+ in.read();
+
+ // send event to event manager
+ eventManager.observeInternalEvent(System
+ .currentTimeMillis(),
+ getClientApplicationName(),
+ ClientEventType.CLIENT_REPLY_RECEIVED,
+ "Received response.");
+
+ // if we should stop on success, stop further connection
+ // attempts
+ if (stopOnSuccess) {
+ connected = false;
+ }
+
+ // clean up socket
+ in.close();
+ out.close();
+ s.close();
+
+ } catch (final SocketTimeoutException e) {
+
+ // log warning
+ logger.log(Level.WARNING,
+ "Connection to remote server timed out!", e);
+
+ // send event to event manager
+ eventManager.observeInternalEvent(System
+ .currentTimeMillis(),
+ getClientApplicationName(),
+ ClientEventType.CLIENT_GAVE_UP_REQUEST,
+ "Giving up request.");
+
+ // try again immediately, if there are retries left
+
+ } catch (final IOException e) {
+
+ // log warning
+ logger.log(Level.WARNING,
+ "Connection to remote server could not be "
+ + "established!", e);
+
+ // send event to event manager
+ eventManager.observeInternalEvent(System
+ .currentTimeMillis(),
+ getClientApplicationName(),
+ ClientEventType.CLIENT_GAVE_UP_REQUEST,
+ "Giving up request.");
+
+ // wait for the rest of the timeout
+ final long timeOfTimeoutLeft =
+ timeBeforeConnectionAttempt
+ + timeoutForEachRetry
+ - System.currentTimeMillis();
+ if (timeOfTimeoutLeft > 0) {
+ try {
+ Thread.sleep(timeOfTimeoutLeft);
+ } catch (final InterruptedException ex) {
+ // do nothing
+ }
+ }
+
+ } finally {
+ if (s != null) {
+ // close connection
+ try {
+
+ // try to close socket
+ logger.log(Level.FINER,
+ "Trying to close socket.");
+ s.close();
+ logger.log(Level.FINE, "Socket closed.");
+
+ } catch (final IOException e) {
+
+ // log warning
+ logger.log(Level.WARNING,
+ "Exception when trying to close socket!",
+ e);
+ }
+ }
+ }
+ }
+
+ } finally {
+
+ // we are done here
+ logger.log(Level.FINE, "Requests performed!");
+
+ // send event to event manager
+ eventManager.observeInternalEvent(System.currentTimeMillis(),
+ getClientApplicationName(),
+ ClientEventType.CLIENT_REQUESTS_PERFORMED,
+ "Requests performed.");
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ }
+
+ /**
+ * Immediately stops this and all possibly subsequent requests.
+ */
+ public void stopRequest() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "stopRequest");
+
+ // change connected state to false and interrupt thread
+ connected = false;
+ interrupt();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "stopRequest");
+ }
+ }
+
+ /**
+ * Name of this client application that is used as logger name of this node.
+ */
+ private final String clientApplicationName;
+
+ /**
+ * Thread that performs the requests in the background.
+ */
+ private RequestThread clientThread;
+
+ /**
+ * Event manager that handles all events concerning this client application.
+ */
+ private final EventManagerImpl eventManager;
+
+ /**
+ * Logger for this client which is called "client." plus the name of this
+ * client application.
+ */
+ private final Logger logger;
+
+ /**
+ * SOCKS port of the local Tor node to which requests are sent.
+ */
+ private final int socksPort;
+
+ /**
+ * Target name for the requests sent by this client; can be a publicly
+ * available URL or an onion address.
+ */
+ private final String targetName;
+
+ /**
+ * Target port for the requests sent by this client; can be either a server
+ * port or a virtual port of a hidden service.
+ */
+ private final int targetPort;
+
+ /**
+ * Creates a new HTTP client within this JVM, but does not start sending
+ * requests.
+ *
+ * @param network
+ * Network to which this HTTP client belongs; at the moment this
+ * is only used to determine the event manager instance.
+ * @param clientApplicationName
+ * Name of this client that is used as part of the logger name.
+ * @param targetName
+ * Target name for requests; can be either a server name/address
+ * or an onion address.
+ * @param targetPort
+ * Target port for requests; can be either a server port or a
+ * virtual port of a hidden service.
+ * @param socksPort
+ * SOCKS port of the local Tor node.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
+ */
+ ClientApplicationImpl(final NetworkImpl network,
+ final String clientApplicationName, final String targetName,
+ final int targetPort, final int socksPort) {
+
+ // check if clientApplicationName can be used as logger name
+ if (clientApplicationName == null
+ || clientApplicationName.length() == 0) {
+ throw new IllegalArgumentException(
+ "Invalid clientApplicationName: " + clientApplicationName);
+ }
+
+ // create logger
+ logger = Logger.getLogger("client." + clientApplicationName);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "ClientApplicationImpl",
+ new Object[] { network, clientApplicationName, targetName,
+ targetPort, socksPort });
+
+ // check parameters
+ if (network == null || targetName == null || targetName.length() == 0
+ || targetPort < 0 || targetPort > 65535 || socksPort < 0
+ || socksPort > 65535) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "ClientApplicationImpl",
+ e);
+ throw e;
+ }
+
+ // remember parameters
+ this.clientApplicationName = clientApplicationName;
+ this.targetName = targetName;
+ this.targetPort = targetPort;
+ this.socksPort = socksPort;
+
+ // obtain and store reference on event manager
+ eventManager = network.getEventManagerImpl();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "ClientApplicationImpl");
+ }
+
+ public synchronized void startRequests(final int retries,
+ final long timeoutForEachRetry, final boolean stopOnSuccess) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "performRequest",
+ new Object[] { retries, timeoutForEachRetry, stopOnSuccess });
+
+ // check parameters
+ if (retries <= 0 || timeoutForEachRetry < 0) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "performRequest", e);
+ throw e;
+ }
+
+ // check if we already have started a request (TODO change this to allow
+ // multiple requests in parallel? would be possible)
+ if (clientThread != null) {
+ final IllegalStateException e =
+ new IllegalStateException(
+ "Another request has already been started!");
+ logger.throwing(this.getClass().getName(), "performRequest", e);
+ throw e;
+ }
+
+ // create a thread that performs requests in the background
+ clientThread =
+ new RequestThread(retries, timeoutForEachRetry, stopOnSuccess);
+ clientThread.setName("Request Thread");
+ clientThread.setDaemon(true);
+ clientThread.start();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "performRequest");
+ }
+
+ public synchronized void stopRequest() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "stopRequest");
+
+ // check if a request is running
+ if (clientThread == null) {
+ final IllegalStateException e =
+ new IllegalStateException("Cannot stop "
+ + "request, because no request has been started!");
+ logger.throwing(this.getClass().getName(), "stopRequest", e);
+ throw e;
+ }
+
+ // log this event
+ logger.log(Level.FINE, "Shutting down client");
+
+ // interrupt thread
+ clientThread.stopRequest();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "stopRequest");
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": clientApplicationName=\""
+ + clientApplicationName + "\", targetAddress=\"" + targetName
+ + "\", targetPort=" + targetPort + ", socksPort=" + socksPort;
+ }
+
+ public String getClientApplicationName() {
+ return clientApplicationName;
+ }
+
+ public int getSocksPort() {
+ return socksPort;
+ }
+
+ public String getTargetName() {
+ return targetName;
+ }
+
+ public int getTargetPort() {
+ return targetPort;
+ }
}
diff --git a/src/org/torproject/puppetor/impl/DirectoryNodeImpl.java b/src/org/torproject/puppetor/impl/DirectoryNodeImpl.java
index b8cf15c..d9bcdf1 100644
--- a/src/org/torproject/puppetor/impl/DirectoryNodeImpl.java
+++ b/src/org/torproject/puppetor/impl/DirectoryNodeImpl.java
@@ -32,401 +32,401 @@ import org.torproject.puppetor.PuppeTorException;
*/
public class DirectoryNodeImpl extends RouterNodeImpl implements DirectoryNode {
- /**
- * Executable file for generating v3 directory authority certificates.
- *
- * TODO make this configurable!
- */
- protected static final File torGencertExecutable = new File("tor-gencert");
-
- /**
- * Internal thread class that is used to generate v3 directory authority
- * certificates in parallel, which can take a few seconds.
- */
- private class GenerateCertificateThread extends Thread {
-
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- // run tor-gencert
- final ProcessBuilder processBuilder =
- new ProcessBuilder(torGencertExecutable.getPath(),
- "--create-identity-key"// );
- , "--passphrase-fd", "0");
- final File workingDirectory =
- new File(workingDir.getAbsolutePath() + File.separator
- + "keys" + File.separator);
-
- // create working directory
- workingDirectory.mkdirs();
-
- processBuilder.directory(workingDirectory);
- processBuilder.redirectErrorStream(true);
- Process tmpProcess = null;
- try {
- tmpProcess = processBuilder.start();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not start tor-gencert process for generating a "
- + "v3 directory authority certificate!",
- e);
- logger.log(Level.WARNING, "Could not start tor-gencert "
- + "process for generating a v3 directory authority "
- + "certificate!", ex);
- setCaughtException(ex);
- return;
- }
-
- final BufferedWriter writer =
- new BufferedWriter(new OutputStreamWriter(tmpProcess
- .getOutputStream()));
- try {
- writer.write("somepassword\n");
- writer.close();
- } catch (final IOException e1) {
- System.out.println("Exception at write! " + e1.getMessage());
- e1.printStackTrace();
- }
- // final InputStream read = tmpProcess.getErrorStream();
-
- final InputStream stderr = tmpProcess.getInputStream();
- final InputStreamReader isr = new InputStreamReader(stderr);
- final BufferedReader br = new BufferedReader(isr);
- String line = null;
- try {
- while ((line = br.readLine()) != null) {
- ;
- }
- } catch (final IOException e1) {
- e1.printStackTrace();
- }
-
- // wait for process to terminate
- int exitValue = 0;
- try {
- exitValue = tmpProcess.waitFor();
- } catch (final InterruptedException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Interrupted while waiting for tor-gencert process to exit!",
- e);
- logger.log(Level.WARNING,
- "tor-gencert process was interrupted!", ex);
- setCaughtException(ex);
- return;
- }
-
- if (exitValue != 0) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not start tor-gencert process! tor-gencert exited with "
- + "exit value " + exitValue + "!");
- logger.log(Level.WARNING,
- "Could not start tor-gencert process!", ex);
- setCaughtException(ex);
- return;
- }
-
- // read fingerprint from file
- final File authorityCertificateFile =
- new File(workingDirectory.getAbsolutePath()
- + File.separator + "authority_certificate");
- String identity;
- try {
- final BufferedReader br2 =
- new BufferedReader(new FileReader(
- authorityCertificateFile));
- while ((line = br2.readLine()) != null
- && !line.startsWith("fingerprint ")) {
- ;
- }
- if (line == null) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not find fingerprint line in file "
- + "authority_certificate!");
- logger.log(Level.WARNING,
- "Could not find fingerprint line in file "
- + "authority_certificate!", ex);
- setCaughtException(ex);
- return;
- }
- identity = line.substring(line.indexOf(" ") + 1);
- br2.close();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not read fingerprint from file!", e);
- logger.log(Level.WARNING, "Could not read fingerprint file!",
- ex);
- setCaughtException(ex);
- return;
- }
-
- setV3Identity(identity);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
- }
-
- /**
- * Set of routers that are approved by this directory node.
- */
- private final SortedSet<String> approvedRouters;
-
- /**
- * Creates a <code>DirectoryNodeImpl</code> and adds it to the given
- * <code>network</code>, but does not yet write its configuration to disk
- * or start the corresponding Tor process.
- *
- * @param network
- * Network configuration to which this node belongs.
- * @param nodeName
- * The name of the new node which may only consist of between 1
- * and 19 alpha-numeric characters.
- * @param controlPort
- * Port on which the Tor node will be listening for us as its
- * controller. May not be negative or greater than 65535.
- * @param socksPort
- * Port on which the Tor node will be listening for SOCKS
- * connection requests. May not be negative or greater than
- * 65535.
- * @param orPort
- * Port on which the Tor node will be listening for onion
- * requests by other Tor nodes. May not be negative or greater
- * than 65535.
- * @param dirPort
- * Port on which the Tor node will be listening for directory
- * requests from other Tor nodes. May not be negative or greater
- * than 65535.
- * @param serverIpAddress
- * The IP address on which the node will listen. Must be a valid
- * IP v4 address in dotted decimal notation. May not be
- * <code>null</code>.
- * @throws IllegalArgumentException
- * If at least one of the parameters is <code>null</code> or
- * has an invalid value.
- * @throws PuppeTorException
- * Thrown if an I/O problem occurs while writing the temporary
- * <code>approved-routers</code> file.
- */
- DirectoryNodeImpl(final NetworkImpl network, final String nodeName,
- final int controlPort, final int socksPort, final int orPort,
- final int dirPort, final String serverIpAddress) {
- // create superclass instance; parameter checking is done in super
- // constructor
- super(network, nodeName, controlPort, socksPort, orPort, dirPort,
- serverIpAddress);
-
- // log entering
- logger.entering(this.getClass().getName(), "DirectoryNodeImpl",
- new Object[] { network, nodeName, controlPort, socksPort,
- orPort, dirPort });
-
- // initialize attribute
- approvedRouters = new TreeSet<String>();
-
- // extend configuration by template configuration of directory nodes
- configuration.addAll(templateConfiguration);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "DirectoryNodeImpl");
- }
-
- /**
- * Invoked by the certificate generating thread: sets the generated v3
- * identity string.
- *
- * @param v3Identity
- * The generated v3 identity string.
- */
- private synchronized void setV3Identity(final String v3Identity) {
- // log entering
- logger.entering(this.getClass().getName(), "setV3Identity", v3Identity);
-
- // remember fingerprint and notify all waiting threads
- this.v3Identity = v3Identity;
- notifyAll();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "setV3Identity");
- }
-
- /**
- * The generated v3 identity string.
- */
- private String v3Identity;
-
- public synchronized String getV3Identity() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "getV3Identity");
-
- // wait until either the v3 identity has been determined or an exception
- // was caught
- while (v3Identity == null && caughtException == null) {
-
- try {
- wait(500);
- } catch (final InterruptedException e) {
- // do nothing
- }
- }
-
- if (caughtException != null) {
- logger.throwing(this.getClass().getName(), "getV3Identity",
- caughtException);
- throw caughtException;
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "getV3Identity", v3Identity);
- return v3Identity;
- }
-
- public synchronized String getDirServerString() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "getDirServerString");
-
- // determine fingerprint
- String fingerprint = getFingerprint();
-
- // cut off router nickname
- fingerprint = fingerprint.substring(fingerprint.indexOf(" ") + 1);
-
- // determine v3 identity
- final String determinedV3Identity = getV3Identity();
-
- // put everything together
- final String dirServerString =
- "DirServer " + nodeName + " v3ident=" + determinedV3Identity
- + " orport=" + orPort + " " + serverIpAddress + ":"
- + dirPort + " " + fingerprint;
-
- // log exiting and return dir server string
- logger.exiting(this.getClass().getName(), "getDirServerString",
- dirServerString);
- return dirServerString;
- }
-
- public void addApprovedRouters(final Set<String> routers) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addApprovedRouters",
- routers);
-
- // check parameter
- if (routers == null) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "addApprovedRouters", e);
- throw e;
- }
-
- // add the given approved router strings to the sorted set of already
- // known strings (if any)
- approvedRouters.addAll(routers);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "addApprovedRouters");
- }
-
- @Override
- protected synchronized void determineFingerprint() {
-
- // log entering
- logger.entering(this.getClass().getName(), "determineFingerprint");
-
- // start a thread to generate the directory's certificate
- final GenerateCertificateThread certificateThread =
- new GenerateCertificateThread();
- certificateThread.setName(nodeName + " Certificate Generator");
- certificateThread.start();
-
- // wait (non-blocking) for the v3 identity string
- try {
- getV3Identity();
- } catch (final PuppeTorException e1) {
- final PuppeTorException ex =
- new PuppeTorException("Could not read v3 identity string!",
- e1);
- caughtException = ex;
- return;
- }
-
- // create an empty approved-routers file to make Tor happy
- try {
- new File(workingDir.getAbsolutePath() + File.separator
- + "approved-routers").createNewFile();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not write empty approved-routers file!", e);
- caughtException = ex;
- return;
- }
-
- // invoke overwritten method
- super.determineFingerprint();
- }
-
- @Override
- public synchronized void writeConfiguration() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "writeConfiguration");
-
- // write approved-routers file
- try {
- final File approvedRoutersFile =
- new File(workingDir.getAbsolutePath() + File.separator
- + "approved-routers");
- final BufferedWriter bw =
- new BufferedWriter(new FileWriter(approvedRoutersFile));
- for (final String approvedRouter : approvedRouters) {
- bw.write(approvedRouter + "\n");
- }
- bw.close();
- } catch (final IOException e) {
- final PuppeTorException ex = new PuppeTorException(e);
- logger
- .throwing(this.getClass().getName(), "writeConfiguration",
- ex);
- throw ex;
- }
-
- // invoke overridden method
- super.writeConfiguration();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "writeConfiguration");
- }
-
- /**
- * Template configuration of directory nodes.
- */
- static List<String> templateConfiguration;
-
- static {
- templateConfiguration = new ArrayList<String>();
-
- // configure this node as an authoritative directory
- templateConfiguration.add("AuthoritativeDirectory 1");
- templateConfiguration.add("V2AuthoritativeDirectory 1");
- templateConfiguration.add("V3AuthoritativeDirectory 1");
- templateConfiguration.add("DirAllowPrivateAddresses 1");
- templateConfiguration.add("MinUptimeHidServDirectoryV2 0 minutes");
-
- // TODO This is now contained in proposal 135.
- // templateConfiguration.add("AuthDirMaxServersPerAddr 0");
- // templateConfiguration.add("AuthDirMaxServersPerAuthAddr 0");
- // templateConfiguration.add("V3AuthVotingInterval 5 minutes");
- // templateConfiguration.add("V3AuthVoteDelay 20 seconds");
- // templateConfiguration.add("V3AuthDistDelay 20 seconds");
- }
+ /**
+ * Executable file for generating v3 directory authority certificates.
+ *
+ * TODO make this configurable!
+ */
+ protected static final File torGencertExecutable = new File("tor-gencert");
+
+ /**
+ * Internal thread class that is used to generate v3 directory authority
+ * certificates in parallel, which can take a few seconds.
+ */
+ private class GenerateCertificateThread extends Thread {
+
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ // run tor-gencert
+ final ProcessBuilder processBuilder =
+ new ProcessBuilder(torGencertExecutable.getPath(),
+ "--create-identity-key"// );
+ , "--passphrase-fd", "0");
+ final File workingDirectory =
+ new File(workingDir.getAbsolutePath() + File.separator
+ + "keys" + File.separator);
+
+ // create working directory
+ workingDirectory.mkdirs();
+
+ processBuilder.directory(workingDirectory);
+ processBuilder.redirectErrorStream(true);
+ Process tmpProcess = null;
+ try {
+ tmpProcess = processBuilder.start();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not start tor-gencert process for generating a "
+ + "v3 directory authority certificate!",
+ e);
+ logger.log(Level.WARNING, "Could not start tor-gencert "
+ + "process for generating a v3 directory authority "
+ + "certificate!", ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ final BufferedWriter writer =
+ new BufferedWriter(new OutputStreamWriter(tmpProcess
+ .getOutputStream()));
+ try {
+ writer.write("somepassword\n");
+ writer.close();
+ } catch (final IOException e1) {
+ System.out.println("Exception at write! " + e1.getMessage());
+ e1.printStackTrace();
+ }
+ // final InputStream read = tmpProcess.getErrorStream();
+
+ final InputStream stderr = tmpProcess.getInputStream();
+ final InputStreamReader isr = new InputStreamReader(stderr);
+ final BufferedReader br = new BufferedReader(isr);
+ String line = null;
+ try {
+ while ((line = br.readLine()) != null) {
+ ;
+ }
+ } catch (final IOException e1) {
+ e1.printStackTrace();
+ }
+
+ // wait for process to terminate
+ int exitValue = 0;
+ try {
+ exitValue = tmpProcess.waitFor();
+ } catch (final InterruptedException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Interrupted while waiting for tor-gencert process to exit!",
+ e);
+ logger.log(Level.WARNING,
+ "tor-gencert process was interrupted!", ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ if (exitValue != 0) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not start tor-gencert process! tor-gencert exited with "
+ + "exit value " + exitValue + "!");
+ logger.log(Level.WARNING,
+ "Could not start tor-gencert process!", ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ // read fingerprint from file
+ final File authorityCertificateFile =
+ new File(workingDirectory.getAbsolutePath()
+ + File.separator + "authority_certificate");
+ String identity;
+ try {
+ final BufferedReader br2 =
+ new BufferedReader(new FileReader(
+ authorityCertificateFile));
+ while ((line = br2.readLine()) != null
+ && !line.startsWith("fingerprint ")) {
+ ;
+ }
+ if (line == null) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not find fingerprint line in file "
+ + "authority_certificate!");
+ logger.log(Level.WARNING,
+ "Could not find fingerprint line in file "
+ + "authority_certificate!", ex);
+ setCaughtException(ex);
+ return;
+ }
+ identity = line.substring(line.indexOf(" ") + 1);
+ br2.close();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not read fingerprint from file!", e);
+ logger.log(Level.WARNING, "Could not read fingerprint file!",
+ ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ setV3Identity(identity);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ }
+
+ /**
+ * Set of routers that are approved by this directory node.
+ */
+ private final SortedSet<String> approvedRouters;
+
+ /**
+ * Creates a <code>DirectoryNodeImpl</code> and adds it to the given
+ * <code>network</code>, but does not yet write its configuration to disk
+ * or start the corresponding Tor process.
+ *
+ * @param network
+ * Network configuration to which this node belongs.
+ * @param nodeName
+ * The name of the new node which may only consist of between 1
+ * and 19 alpha-numeric characters.
+ * @param controlPort
+ * Port on which the Tor node will be listening for us as its
+ * controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * Port on which the Tor node will be listening for SOCKS
+ * connection requests. May not be negative or greater than
+ * 65535.
+ * @param orPort
+ * Port on which the Tor node will be listening for onion
+ * requests by other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @param dirPort
+ * Port on which the Tor node will be listening for directory
+ * requests from other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @param serverIpAddress
+ * The IP address on which the node will listen. Must be a valid
+ * IP v4 address in dotted decimal notation. May not be
+ * <code>null</code>.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
+ * @throws PuppeTorException
+ * Thrown if an I/O problem occurs while writing the temporary
+ * <code>approved-routers</code> file.
+ */
+ DirectoryNodeImpl(final NetworkImpl network, final String nodeName,
+ final int controlPort, final int socksPort, final int orPort,
+ final int dirPort, final String serverIpAddress) {
+ // create superclass instance; parameter checking is done in super
+ // constructor
+ super(network, nodeName, controlPort, socksPort, orPort, dirPort,
+ serverIpAddress);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "DirectoryNodeImpl",
+ new Object[] { network, nodeName, controlPort, socksPort,
+ orPort, dirPort });
+
+ // initialize attribute
+ approvedRouters = new TreeSet<String>();
+
+ // extend configuration by template configuration of directory nodes
+ configuration.addAll(templateConfiguration);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "DirectoryNodeImpl");
+ }
+
+ /**
+ * Invoked by the certificate generating thread: sets the generated v3
+ * identity string.
+ *
+ * @param v3Identity
+ * The generated v3 identity string.
+ */
+ private synchronized void setV3Identity(final String v3Identity) {
+ // log entering
+ logger.entering(this.getClass().getName(), "setV3Identity", v3Identity);
+
+ // remember fingerprint and notify all waiting threads
+ this.v3Identity = v3Identity;
+ notifyAll();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "setV3Identity");
+ }
+
+ /**
+ * The generated v3 identity string.
+ */
+ private String v3Identity;
+
+ public synchronized String getV3Identity() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "getV3Identity");
+
+ // wait until either the v3 identity has been determined or an exception
+ // was caught
+ while (v3Identity == null && caughtException == null) {
+
+ try {
+ wait(500);
+ } catch (final InterruptedException e) {
+ // do nothing
+ }
+ }
+
+ if (caughtException != null) {
+ logger.throwing(this.getClass().getName(), "getV3Identity",
+ caughtException);
+ throw caughtException;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "getV3Identity", v3Identity);
+ return v3Identity;
+ }
+
+ public synchronized String getDirServerString() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "getDirServerString");
+
+ // determine fingerprint
+ String fingerprint = getFingerprint();
+
+ // cut off router nickname
+ fingerprint = fingerprint.substring(fingerprint.indexOf(" ") + 1);
+
+ // determine v3 identity
+ final String determinedV3Identity = getV3Identity();
+
+ // put everything together
+ final String dirServerString =
+ "DirServer " + nodeName + " v3ident=" + determinedV3Identity
+ + " orport=" + orPort + " " + serverIpAddress + ":"
+ + dirPort + " " + fingerprint;
+
+ // log exiting and return dir server string
+ logger.exiting(this.getClass().getName(), "getDirServerString",
+ dirServerString);
+ return dirServerString;
+ }
+
+ public void addApprovedRouters(final Set<String> routers) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addApprovedRouters",
+ routers);
+
+ // check parameter
+ if (routers == null) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "addApprovedRouters", e);
+ throw e;
+ }
+
+ // add the given approved router strings to the sorted set of already
+ // known strings (if any)
+ approvedRouters.addAll(routers);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "addApprovedRouters");
+ }
+
+ @Override
+ protected synchronized void determineFingerprint() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "determineFingerprint");
+
+ // start a thread to generate the directory's certificate
+ final GenerateCertificateThread certificateThread =
+ new GenerateCertificateThread();
+ certificateThread.setName(nodeName + " Certificate Generator");
+ certificateThread.start();
+
+ // wait (non-blocking) for the v3 identity string
+ try {
+ getV3Identity();
+ } catch (final PuppeTorException e1) {
+ final PuppeTorException ex =
+ new PuppeTorException("Could not read v3 identity string!",
+ e1);
+ caughtException = ex;
+ return;
+ }
+
+ // create an empty approved-routers file to make Tor happy
+ try {
+ new File(workingDir.getAbsolutePath() + File.separator
+ + "approved-routers").createNewFile();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not write empty approved-routers file!", e);
+ caughtException = ex;
+ return;
+ }
+
+ // invoke overwritten method
+ super.determineFingerprint();
+ }
+
+ @Override
+ public synchronized void writeConfiguration() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "writeConfiguration");
+
+ // write approved-routers file
+ try {
+ final File approvedRoutersFile =
+ new File(workingDir.getAbsolutePath() + File.separator
+ + "approved-routers");
+ final BufferedWriter bw =
+ new BufferedWriter(new FileWriter(approvedRoutersFile));
+ for (final String approvedRouter : approvedRouters) {
+ bw.write(approvedRouter + "\n");
+ }
+ bw.close();
+ } catch (final IOException e) {
+ final PuppeTorException ex = new PuppeTorException(e);
+ logger
+ .throwing(this.getClass().getName(), "writeConfiguration",
+ ex);
+ throw ex;
+ }
+
+ // invoke overridden method
+ super.writeConfiguration();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "writeConfiguration");
+ }
+
+ /**
+ * Template configuration of directory nodes.
+ */
+ static List<String> templateConfiguration;
+
+ static {
+ templateConfiguration = new ArrayList<String>();
+
+ // configure this node as an authoritative directory
+ templateConfiguration.add("AuthoritativeDirectory 1");
+ templateConfiguration.add("V2AuthoritativeDirectory 1");
+ templateConfiguration.add("V3AuthoritativeDirectory 1");
+ templateConfiguration.add("DirAllowPrivateAddresses 1");
+ templateConfiguration.add("MinUptimeHidServDirectoryV2 0 minutes");
+
+ // TODO This is now contained in proposal 135.
+ // templateConfiguration.add("AuthDirMaxServersPerAddr 0");
+ // templateConfiguration.add("AuthDirMaxServersPerAuthAddr 0");
+ // templateConfiguration.add("V3AuthVotingInterval 5 minutes");
+ // templateConfiguration.add("V3AuthVoteDelay 20 seconds");
+ // templateConfiguration.add("V3AuthDistDelay 20 seconds");
+ }
}
diff --git a/src/org/torproject/puppetor/impl/EventImpl.java b/src/org/torproject/puppetor/impl/EventImpl.java
index 4c277c5..c260e2c 100644
--- a/src/org/torproject/puppetor/impl/EventImpl.java
+++ b/src/org/torproject/puppetor/impl/EventImpl.java
@@ -19,105 +19,105 @@ import org.torproject.puppetor.EventType;
@SuppressWarnings("serial")
public class EventImpl implements Event {
- /**
- * The source of this event.
- */
- private final String source;
-
- /**
- * The type of this event.
- */
- private EventType type;
-
- /**
- * Either the log message that led to firing this event, or an internal
- * message.
- */
- private final String message;
-
- /**
- * The occurrence time of the event or of the corresponding log statement.
- */
- private long occurrenceTime;
-
- /**
- * Creates a new <code>EventImpl</code>.
- *
- * @param occurrenceTime
- * The occurrence time of the event or of the corresponding log
- * statement.
- * @param source
- * The source of this event.
- * @param type
- * The type of this event.
- * @param message
- * Either the log message that led to firing this event, or an
- * internal message.
- */
- EventImpl(final long occurrenceTime, final String source,
- final EventType type, final String message) {
- this.occurrenceTime = occurrenceTime;
- this.source = source;
- this.type = type;
- this.message = message;
- }
-
- /**
- * Creates a new <code>EventImpl</code>.
- *
- * @param source
- * The source of this event.
- * @param message
- * Either the log message that led to firing this event, or an
- * internal message.
- */
- EventImpl(final String source, final String message) {
- this.source = source;
- this.message = message;
- }
-
- public String getSource() {
- return source;
- }
-
- public EventType getType() {
- return type;
- }
-
- /**
- * Sets the event type to the given type.
- *
- * @param type
- * The type of this event.
- */
- void setType(final EventType type) {
- this.type = type;
- }
-
- public String getMessage() {
- return message;
- }
-
- public long getOccurrenceTime() {
- return occurrenceTime;
- }
-
- @Override
- public String toString() {
- return this.getClass().getSimpleName() + ": occurenceTime="
- + new Date(occurrenceTime) + ", source=\"" + source
- + "\", type=" + type.getTypeName() + ", message=\"" + message
- + "\"";
- }
-
- /**
- * Sets the occurrence time to the given time.
- *
- * @param occurrenceTime
- * The occurrence time of the event or of the corresponding log
- * statement.
- */
- void setOccurenceTime(final long occurrenceTime) {
- this.occurrenceTime = occurrenceTime;
- }
+ /**
+ * The source of this event.
+ */
+ private final String source;
+
+ /**
+ * The type of this event.
+ */
+ private EventType type;
+
+ /**
+ * Either the log message that led to firing this event, or an internal
+ * message.
+ */
+ private final String message;
+
+ /**
+ * The occurrence time of the event or of the corresponding log statement.
+ */
+ private long occurrenceTime;
+
+ /**
+ * Creates a new <code>EventImpl</code>.
+ *
+ * @param occurrenceTime
+ * The occurrence time of the event or of the corresponding log
+ * statement.
+ * @param source
+ * The source of this event.
+ * @param type
+ * The type of this event.
+ * @param message
+ * Either the log message that led to firing this event, or an
+ * internal message.
+ */
+ EventImpl(final long occurrenceTime, final String source,
+ final EventType type, final String message) {
+ this.occurrenceTime = occurrenceTime;
+ this.source = source;
+ this.type = type;
+ this.message = message;
+ }
+
+ /**
+ * Creates a new <code>EventImpl</code>.
+ *
+ * @param source
+ * The source of this event.
+ * @param message
+ * Either the log message that led to firing this event, or an
+ * internal message.
+ */
+ EventImpl(final String source, final String message) {
+ this.source = source;
+ this.message = message;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public EventType getType() {
+ return type;
+ }
+
+ /**
+ * Sets the event type to the given type.
+ *
+ * @param type
+ * The type of this event.
+ */
+ void setType(final EventType type) {
+ this.type = type;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public long getOccurrenceTime() {
+ return occurrenceTime;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": occurenceTime="
+ + new Date(occurrenceTime) + ", source=\"" + source
+ + "\", type=" + type.getTypeName() + ", message=\"" + message
+ + "\"";
+ }
+
+ /**
+ * Sets the occurrence time to the given time.
+ *
+ * @param occurrenceTime
+ * The occurrence time of the event or of the corresponding log
+ * statement.
+ */
+ void setOccurenceTime(final long occurrenceTime) {
+ this.occurrenceTime = occurrenceTime;
+ }
}
diff --git a/src/org/torproject/puppetor/impl/EventManagerImpl.java b/src/org/torproject/puppetor/impl/EventManagerImpl.java
index 163e4d8..99f2ba2 100644
--- a/src/org/torproject/puppetor/impl/EventManagerImpl.java
+++ b/src/org/torproject/puppetor/impl/EventManagerImpl.java
@@ -38,693 +38,693 @@ import org.torproject.puppetor.NodeEventType;
*/
public class EventManagerImpl implements EventManager {
- /**
- * Registered event handlers for specific sources.
- */
- private final Map<String, Set<EventListener>> eventHandlers;
-
- /**
- * Registered event handlers for all sources.
- */
- private final Set<EventListener> eventHandlersForAllSources;
-
- /**
- * Logger for this event manager which is called "event." plus the name of
- * the network.
- */
- private final Logger logger;
-
- /**
- * Events observed so far.
- */
- private final Map<String, List<Event>> observedEvents;
-
- /**
- * Set of all registered event sources. This is required to ensure that
- * requests for events from a given source specify valid event sources.
- */
- private final Set<String> eventSources;
-
- /**
- * Creates a new <code>EventManagerImpl</code> for the network with name
- * <code>networkName</code> and initializes it.
- *
- * @param networkName
- * Name of this event manager that is used as part of the logger
- * name.
- * @throws IllegalArgumentException
- * Thrown if the given <code>networkName</code> is either
- * <code>null</code> or a zero-length string.
- */
- EventManagerImpl(final String networkName) {
-
- // check if networkName can be used as logger name
- if (networkName == null || networkName.length() == 0) {
- throw new IllegalArgumentException("Invalid networkName: "
- + networkName);
- }
-
- // create logger
- logger = Logger.getLogger("event." + networkName);
-
- // log entering
- logger.entering(this.getClass().getName(), "EventManagerImpl",
- networkName);
-
- // create data structures
- observedEvents = new HashMap<String, List<Event>>();
- eventHandlers = new HashMap<String, Set<EventListener>>();
- eventHandlersForAllSources = new HashSet<EventListener>();
- eventSources = new HashSet<String>();
-
- // start thread to parse events
- final Thread eventParseThread = new Thread() {
- @Override
- public void run() {
- while (true) {
- parseNextEvent();
- }
- }
- };
- eventParseThread.setDaemon(true);
- eventParseThread.start();
-
- // initialize event type patterns
- initializeEventTypePatterns();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "EventManagerImpl");
- }
-
- public synchronized List<Event> addEventListener(final String source,
- final EventListener listener) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addEventListener",
- new Object[] { source, listener });
-
- // check parameters
- if (source == null || listener == null
- || !eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "addEventListener", e);
- throw e;
- }
-
- // if necessary, create new event listener set for source
- if (!eventHandlers.containsKey(source)) {
- eventHandlers.put(source, new HashSet<EventListener>());
- }
-
- // add listener
- eventHandlers.get(source).add(listener);
-
- // log change
- logger.log(Level.FINE, "Added event listener for source " + source);
-
- // log exiting and return
- final List<Event> result = getEventHistory(source);
- logger.exiting(this.getClass().getName(), "addEventListener", result);
- return result;
- }
-
- public synchronized void addEventListener(final EventListener listener) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addEventListener",
- new Object[] { listener });
-
- // check parameters
- if (listener == null) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "addEventListener", e);
- throw e;
- }
-
- // add listener
- eventHandlersForAllSources.add(listener);
-
- // log change
- logger.log(Level.FINE, "Added event listener for all sources.");
-
- // log exiting and return
- logger.exiting(this.getClass().getName(), "addEventListener");
- return;
- }
-
- public synchronized List<Event> getEventHistory(final String source) {
-
- // log entering
- logger.entering(this.getClass().getName(), "getEventHistory", source);
-
- // check parameter
- if (source == null || !eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "getEventHistory", e);
- throw e;
- }
-
- // prepare result
- final List<Event> result = new ArrayList<Event>();
-
- // did we already observe events for this source?
- if (observedEvents.containsKey(source)) {
- // yes, add all events to result list
- result.addAll(observedEvents.get(source));
- }
-
- // log exiting and return result
- logger.exiting(this.getClass().getName(), "getEventHistory", result);
- return result;
- }
-
- public synchronized boolean hasEventOccured(final String source,
- final EventType type) {
-
- // log entering
- logger.entering(this.getClass().getName(), "hasEventOccured",
- new Object[] { source, type });
-
- // check parameters
- if (source == null || type == null || !eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "hasEventOccured", e);
- throw e;
- }
-
- // determine result
- boolean result = false;
- if (observedEvents.containsKey(source)) {
- for (final Event event : observedEvents.get(source)) {
- if (event.getType() == type) {
- result = true;
- break;
- }
- }
- }
-
- // log exiting and return result
- logger.exiting(this.getClass().getName(), "hasEventOccured", result);
- return result;
- }
-
- /**
- * An ordered list of all log statements that are still unparsed.
- */
- private final List<EventImpl> unparsedLogStatements =
- new LinkedList<EventImpl>();
-
- /**
- * Stores the occurrence of an unparsed Tor log events that might result in
- * an event. All such unparsed events are later parsed by a background
- * thread in invocation order. Then, the occurrence time and the event type
- * will be parsed from the log message; if the log message does not contain
- * anything of interest, the event will be discarded.
- *
- * @param source
- * The event source.
- * @param logMessage
- * The log message.
- * @throws IllegalArgumentException
- * Thrown if the source is unknown.
- */
- synchronized void observeUnparsedEvent(final String source,
- final String logMessage) {
- unparsedLogStatements.add(new EventImpl(source, logMessage));
- notifyAll();
- }
-
- /**
- * Add an internal event to the event queue.
- *
- * @param occurrenceTime
- * The occurrence time of the event.
- * @param source
- * The event source.
- * @param type
- * The event type.
- * @param message
- * The event message.
- * @throws IllegalArgumentException
- * Thrown if the source is unknown.
- */
- public synchronized void observeInternalEvent(final long occurrenceTime,
- final String source, final EventType type, final String message) {
-
- if (!eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "observeInternalEvent",
- e);
- throw e;
- }
-
- unparsedLogStatements.add(new EventImpl(occurrenceTime, source, type,
- message));
- notifyAll();
- }
-
- /**
- * Parses a log statement coming from Tor and decides whether it is
- * interesting for us.
- */
- void parseNextEvent() {
-
- // wait for the next event in the queue
- EventImpl event = null;
- synchronized (this) {
- while (unparsedLogStatements.isEmpty()) {
- try {
- wait();
- } catch (final InterruptedException e) {}
- }
- event = unparsedLogStatements.remove(0);
- }
-
- // does the event contain a known source? if not, discard it
- if (!eventSources.contains(event.getSource())) {
- logger.log(Level.WARNING,
- "Unknown event source while parsing an event: "
- + event.getSource());
- return;
- }
-
- // does the event require parsing? if not, process immediately
- if (event.getType() != null) {
- observeEvent(event);
- } else {
- final String line = event.getMessage();
-
- /*
- * the logging output of Tor does not contain a year component; put
- * in the year at the time of parsing (which happens approx. 10 ms
- * after the logging took place) in the good hope that this tool is
- * not run at midnight on New Year's Eve...
- */
- final Calendar c = Calendar.getInstance();
- final int currentYear = c.get(Calendar.YEAR);
-
- // try to apply one of the event type patterns
- for (final Entry<Pattern, EventType> entry : eventTypePatterns
- .entrySet()) {
- final Matcher matcher = entry.getKey().matcher(line);
- if (matcher.find()) {
- final SimpleDateFormat sdf =
- new SimpleDateFormat("MMM dd HH:mm:ss.SSS",
- Locale.US);
- final Date logTime = sdf.parse(line, new ParsePosition(0));
- c.setTimeInMillis(logTime.getTime());
- c.set(Calendar.YEAR, currentYear);
- final long t = c.getTimeInMillis();
- event.setOccurenceTime(t);
- event.setType(entry.getValue());
- observeEvent(event);
- break;
- }
- }
- }
- }
-
- /**
- * Map of all patterns, that should be included when parsing log statements
- * coming from Tor, and the respective event types of the events that should
- * be fired.
- */
- Map<Pattern, EventType> eventTypePatterns;
-
- public synchronized void registerEventTypePattern(
- final String patternString, final EventType eventType) {
- eventTypePatterns.put(Pattern.compile(patternString), eventType);
- }
-
- /**
- * Initializes the parsing engine with the standard log message patterns
- * that should be included in current Tor. Any further patterns need to be
- * added by the test application manually.
- */
- private void initializeEventTypePatterns() {
- eventTypePatterns = new HashMap<Pattern, EventType>();
- registerEventTypePattern("Opening Control listener on .*",
- NodeEventType.NODE_CONTROL_PORT_OPENED);
- registerEventTypePattern("Tor has successfully opened a circuit. "
- + "Looks like client functionality is working.",
- NodeEventType.NODE_CIRCUIT_OPENED);
- registerEventTypePattern(
- "Established circuit .* as introduction "
- + "point for service .*",
- HiddenServiceEventType.BOB_BUILT_INTRO_CIRC_SENDING_ESTABLISH_INTRO);
- registerEventTypePattern("Received INTRO_ESTABLISHED cell on "
- + "circuit .* for service .*",
- HiddenServiceEventType.BOB_INTRO_ESTABLISHED_RECEIVED);
- registerEventTypePattern("Sending publish request for hidden "
- + "service .*", HiddenServiceEventType.BOB_SENDING_PUBLISH_DESC);
- registerEventTypePattern("Uploaded rendezvous descriptor",
- HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED);
- registerEventTypePattern("Received INTRODUCE2 cell for service .* "
- + "on circ .*", HiddenServiceEventType.BOB_INTRODUCE2_RECEIVED);
- registerEventTypePattern("Done building circuit .* to rendezvous "
- + "with cookie .* for service .*",
- HiddenServiceEventType.BOB_BUILT_REND_CIRC_SENDING_RENDEZVOUS1);
- registerEventTypePattern("begin is for rendezvous",
- HiddenServiceEventType.BOB_APP_CONN_OPENED);
- registerEventTypePattern("Got a hidden service request for ID '.*'",
- HiddenServiceEventType.ALICE_ONION_REQUEST_RECEIVED);
- registerEventTypePattern("Fetching rendezvous descriptor for "
- + "service .*", HiddenServiceEventType.ALICE_SENDING_FETCH_DESC);
- registerEventTypePattern("Received rendezvous descriptor",
- HiddenServiceEventType.ALICE_DESC_FETCHED_RECEIVED);
- registerEventTypePattern(
- "Sending an ESTABLISH_RENDEZVOUS cell",
- HiddenServiceEventType.ALICE_BUILT_REND_CIRC_SENDING_ESTABLISH_RENDEZVOUS);
- registerEventTypePattern("Got rendezvous ack. This circuit is now "
- + "ready for rendezvous",
- HiddenServiceEventType.ALICE_RENDEZVOUS_ESTABLISHED_RECEIVED);
- registerEventTypePattern("introcirc is open",
- HiddenServiceEventType.ALICE_BUILT_INTRO_CIRC);
- registerEventTypePattern("Sending an INTRODUCE1 cell",
- HiddenServiceEventType.ALICE_SENDING_INTRODUCE1);
- registerEventTypePattern("Received ack. Telling rend circ",
- HiddenServiceEventType.ALICE_INTRODUCE_ACK_RECEIVED);
- registerEventTypePattern(
- "Got RENDEZVOUS2 cell from hidden service",
- HiddenServiceEventType.ALICE_RENDEZVOUS2_RECEIVED_APP_CONN_OPENED);
- registerEventTypePattern("Handling rendezvous descriptor post",
- HiddenServiceEventType.DIR_PUBLISH_DESC_RECEIVED);
- registerEventTypePattern("Handling rendezvous descriptor get",
- HiddenServiceEventType.DIR_FETCH_DESC_RECEIVED);
- registerEventTypePattern(
- "Received an ESTABLISH_INTRO request on circuit .*",
- HiddenServiceEventType.IPO_RECEIVED_ESTABLISH_INTRO_SENDING_INTRO_ESTABLISHED);
- registerEventTypePattern(
- "Received an INTRODUCE1 request on circuit .*",
- HiddenServiceEventType.IPO_RECEIVED_INTRODUCE1_SENDING_INTRODUCE2_AND_INTRODUCE_ACK);
- registerEventTypePattern(
- "Received an ESTABLISH_RENDEZVOUS request on circuit .*",
- HiddenServiceEventType.RPO_RECEIVED_ESTABLISH_RENDEZVOUS_SENDING_RENDEZVOUS_ESTABLISHED);
- registerEventTypePattern(
- "Got request for rendezvous from circuit .* to cookie .*",
- HiddenServiceEventType.RPO_RECEIVING_RENDEZVOUS1_SENDING_RENDEZVOUS2);
- }
-
- /**
- * Stores the given <code>event</code> from <code>source</code> to the
- * event history and propagates its occurrence to all registered event
- * handlers.
- *
- * @param event
- * The observed event.
- */
- private synchronized void observeEvent(final Event event) {
-
- // log entering
- logger.entering(this.getClass().getName(), "observeEvent", event);
-
- final String source = event.getSource();
- logger.log(Level.FINE, "Observed event " + event + " from source "
- + source + "!");
-
- // remember observed event
- if (!observedEvents.containsKey(event.getSource())) {
- observedEvents.put(source, new ArrayList<Event>());
- }
- observedEvents.get(source).add(event);
-
- // notify waiting threads
- notifyAll();
-
- // inform event listeners
- if (eventHandlers.containsKey(source)) {
-
- // make a copy of the event handler set, because some event handlers
- // might want to remove themselves from this set while handling the
- // event
- final Set<EventListener> copyOfEventHandlers =
- new HashSet<EventListener>(eventHandlers.get(source));
-
- for (final EventListener eventHandler : copyOfEventHandlers) {
-
- logger.log(Level.FINE, "Informing event listener "
- + eventHandler + " about recently observed event "
- + event + " from source " + source + "!");
- eventHandler.handleEvent(event);
-
- }
- }
-
- // make a copy of the event handler set for all sources, because some
- // event handlers might want to remove themselves from this set while
- // handling the event
- final Set<EventListener> copyOfEventHandlersForAllSources =
- new HashSet<EventListener>(eventHandlersForAllSources);
-
- for (final EventListener eventHandler : copyOfEventHandlersForAllSources) {
-
- logger.log(Level.FINE, "Informing event listener " + eventHandler
- + " about recently observed event " + event
- + " from source " + source + "!");
- eventHandler.handleEvent(event);
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "observeEvent");
- }
-
- public synchronized void removeEventListener(
- final EventListener eventListener) {
-
- // log entering
- logger.entering(this.getClass().getName(), "removeEventListener",
- eventListener);
-
- // check parameters
- if (eventListener == null) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger
- .throwing(this.getClass().getName(), "removeEventListener",
- e);
- throw e;
- }
-
- // don't know to which source this listener has been added (may to more
- // than one), so remove it from all possible sets
- for (final Set<EventListener> set : eventHandlers.values()) {
- if (set.remove(eventListener)) {
- logger.log(Level.FINE, "Removed event listener!");
- }
- }
-
- // remove from event listeners for all sources
- if (eventHandlersForAllSources.remove(eventListener)) {
- logger.log(Level.FINE, "Removed event listener!");
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "removeEventListener");
- }
-
- public synchronized void waitForAnyOccurence(final String source,
- final EventType event) {
-
- // log entering
- logger.entering(this.getClass().getName(), "waitForAnyOccurence",
- new Object[] { source, event });
-
- // check parameters
- if (source == null || event == null || !eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger
- .throwing(this.getClass().getName(), "waitForAnyOccurence",
- e);
- throw e;
- }
-
- // invoke overloaded method with maximumTimeToWaitInMillis of -1L which
- // means to wait forever
- waitForAnyOccurence(source, event, -1L);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "waitForAnyOccurence");
-
- }
-
- public synchronized boolean waitForAnyOccurence(final String source,
- final EventType event, final long maximumTimeToWaitInMillis) {
-
- // log entering
- logger.entering(this.getClass().getName(), "waitForAnyOccurence",
- new Object[] { source, event, maximumTimeToWaitInMillis });
-
- // check parameters
- if (source == null || event == null || !eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger
- .throwing(this.getClass().getName(), "waitForAnyOccurence",
- e);
- throw e;
- }
-
- // check if we have already observed the event
- if (hasEventOccured(source, event)) {
- logger.log(Level.FINE, "Waiting for any occurence of event "
- + event + " returned immediately!");
- logger.exiting(this.getClass().getName(), "waitForAnyOccurence",
- true);
- return true;
- }
-
- // invoke method that waits for next occurence of the event
- final boolean result =
- waitForNextOccurence(source, event, maximumTimeToWaitInMillis);
-
- // log exiting and return result
- logger
- .exiting(this.getClass().getName(), "waitForAnyOccurence",
- result);
- return result;
- }
-
- public synchronized void waitForNextOccurence(final String source,
- final EventType event) {
-
- // log entering
- logger.entering(this.getClass().getName(), "waitForNextOccurence",
- new Object[] { source, event });
-
- // check parameters
- if (source == null || event == null || !eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "waitForNextOccurence",
- e);
- throw e;
- }
-
- // invoke overloaded method with maximumTimeToWaitInMillis of -1L which
- // means to wait forever
- waitForNextOccurence(source, event, -1L);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "waitForNextOccurence");
- }
-
- public synchronized boolean waitForNextOccurence(final String source,
- final EventType type, final long maximumTimeToWaitInMillis) {
-
- // log entering
- logger.entering(this.getClass().getName(), "waitForNextOccurence",
- new Object[] { source, type, maximumTimeToWaitInMillis });
-
- // check parameters
- if (source == null || type == null || !eventSources.contains(source)) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "waitForNextOccurence",
- e);
- throw e;
- }
-
- // distinguish between negative waiting time (wait forever) and zero or
- // positive waiting time
- if (maximumTimeToWaitInMillis < 0) {
-
- // wait forever
- while (!hasEventOccured(source, type)) {
-
- logger.log(Level.FINEST,
- "We will wait infinetely for the next occurence of "
- + "event type " + type + " from source "
- + source + "...");
- try {
- wait();
- } catch (final InterruptedException e) {
- // don't handle
- }
-
- logger.log(Level.FINEST,
- "We have been notified about an observed event while "
- + "waiting for events of type " + type
- + " from source " + source
- + "; need to check whether the observed event "
- + "is what we are looking for...");
- }
-
- logger.log(Level.FINE, "Waiting for occurence of event type "
- + type + " succeeded!");
-
- // log exiting and return result
- logger.exiting(this.getClass().getName(), "waitForNextOccurence",
- true);
- return true;
-
- }
-
- // wait for the given time at most
- final long endOfTime =
- System.currentTimeMillis() + maximumTimeToWaitInMillis;
- long timeLeft = 0;
- while (!hasEventOccured(source, type)
- && (timeLeft = endOfTime - System.currentTimeMillis()) > 0) {
-
- logger.log(Level.FINEST, "We will wait for " + timeLeft
- + " milliseconds for the next occurence of event type "
- + type + " from source " + source + "...");
-
- try {
- wait(timeLeft);
- } catch (final InterruptedException e) {
- // don't handle
- }
-
- logger.log(Level.FINEST,
- "We have been notified about an observed event while "
- + "waiting for events of type " + type
- + " from source " + source
- + "; need to check whether the observed event "
- + "is what we are looking for...");
- }
-
- // determine result
- final boolean result = hasEventOccured(source, type);
-
- logger.log(Level.FINE, "Waiting for next occurence of event type "
- + type + " from source " + source
- + (result ? " succeeded!" : " did not succeed!"));
-
- // log exiting and return result
- logger.exiting(this.getClass().getName(), "waitForNextOccurence",
- result);
- return result;
- }
-
- /**
- * Adds the given <code>source</code> as possible event source.
- *
- * @param source
- * The name of the node, client, or server to add.
- * @throws IllegalArgumentException
- * Thrown if there is already an event source with this name.
- */
- void addEventSource(final String source) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addEventSource", source);
-
- // check if source name is unique in this network
- if (eventSources.contains(source)) {
- final IllegalArgumentException e =
- new IllegalArgumentException(
- "There is already an event source with name "
- + source + " in this network!");
- logger.throwing(this.getClass().getName(), "addEventSource", e);
- throw e;
- }
-
- // add event source name
- eventSources.add(source);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "addEventSource");
- }
-
- @Override
- public String toString() {
- return this.getClass().getSimpleName();
- }
+ /**
+ * Registered event handlers for specific sources.
+ */
+ private final Map<String, Set<EventListener>> eventHandlers;
+
+ /**
+ * Registered event handlers for all sources.
+ */
+ private final Set<EventListener> eventHandlersForAllSources;
+
+ /**
+ * Logger for this event manager which is called "event." plus the name of
+ * the network.
+ */
+ private final Logger logger;
+
+ /**
+ * Events observed so far.
+ */
+ private final Map<String, List<Event>> observedEvents;
+
+ /**
+ * Set of all registered event sources. This is required to ensure that
+ * requests for events from a given source specify valid event sources.
+ */
+ private final Set<String> eventSources;
+
+ /**
+ * Creates a new <code>EventManagerImpl</code> for the network with name
+ * <code>networkName</code> and initializes it.
+ *
+ * @param networkName
+ * Name of this event manager that is used as part of the logger
+ * name.
+ * @throws IllegalArgumentException
+ * Thrown if the given <code>networkName</code> is either
+ * <code>null</code> or a zero-length string.
+ */
+ EventManagerImpl(final String networkName) {
+
+ // check if networkName can be used as logger name
+ if (networkName == null || networkName.length() == 0) {
+ throw new IllegalArgumentException("Invalid networkName: "
+ + networkName);
+ }
+
+ // create logger
+ logger = Logger.getLogger("event." + networkName);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "EventManagerImpl",
+ networkName);
+
+ // create data structures
+ observedEvents = new HashMap<String, List<Event>>();
+ eventHandlers = new HashMap<String, Set<EventListener>>();
+ eventHandlersForAllSources = new HashSet<EventListener>();
+ eventSources = new HashSet<String>();
+
+ // start thread to parse events
+ final Thread eventParseThread = new Thread() {
+ @Override
+ public void run() {
+ while (true) {
+ parseNextEvent();
+ }
+ }
+ };
+ eventParseThread.setDaemon(true);
+ eventParseThread.start();
+
+ // initialize event type patterns
+ initializeEventTypePatterns();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "EventManagerImpl");
+ }
+
+ public synchronized List<Event> addEventListener(final String source,
+ final EventListener listener) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addEventListener",
+ new Object[] { source, listener });
+
+ // check parameters
+ if (source == null || listener == null
+ || !eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "addEventListener", e);
+ throw e;
+ }
+
+ // if necessary, create new event listener set for source
+ if (!eventHandlers.containsKey(source)) {
+ eventHandlers.put(source, new HashSet<EventListener>());
+ }
+
+ // add listener
+ eventHandlers.get(source).add(listener);
+
+ // log change
+ logger.log(Level.FINE, "Added event listener for source " + source);
+
+ // log exiting and return
+ final List<Event> result = getEventHistory(source);
+ logger.exiting(this.getClass().getName(), "addEventListener", result);
+ return result;
+ }
+
+ public synchronized void addEventListener(final EventListener listener) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addEventListener",
+ new Object[] { listener });
+
+ // check parameters
+ if (listener == null) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "addEventListener", e);
+ throw e;
+ }
+
+ // add listener
+ eventHandlersForAllSources.add(listener);
+
+ // log change
+ logger.log(Level.FINE, "Added event listener for all sources.");
+
+ // log exiting and return
+ logger.exiting(this.getClass().getName(), "addEventListener");
+ return;
+ }
+
+ public synchronized List<Event> getEventHistory(final String source) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "getEventHistory", source);
+
+ // check parameter
+ if (source == null || !eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "getEventHistory", e);
+ throw e;
+ }
+
+ // prepare result
+ final List<Event> result = new ArrayList<Event>();
+
+ // did we already observe events for this source?
+ if (observedEvents.containsKey(source)) {
+ // yes, add all events to result list
+ result.addAll(observedEvents.get(source));
+ }
+
+ // log exiting and return result
+ logger.exiting(this.getClass().getName(), "getEventHistory", result);
+ return result;
+ }
+
+ public synchronized boolean hasEventOccured(final String source,
+ final EventType type) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "hasEventOccured",
+ new Object[] { source, type });
+
+ // check parameters
+ if (source == null || type == null || !eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "hasEventOccured", e);
+ throw e;
+ }
+
+ // determine result
+ boolean result = false;
+ if (observedEvents.containsKey(source)) {
+ for (final Event event : observedEvents.get(source)) {
+ if (event.getType() == type) {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ // log exiting and return result
+ logger.exiting(this.getClass().getName(), "hasEventOccured", result);
+ return result;
+ }
+
+ /**
+ * An ordered list of all log statements that are still unparsed.
+ */
+ private final List<EventImpl> unparsedLogStatements =
+ new LinkedList<EventImpl>();
+
+ /**
+ * Stores the occurrence of an unparsed Tor log events that might result in
+ * an event. All such unparsed events are later parsed by a background
+ * thread in invocation order. Then, the occurrence time and the event type
+ * will be parsed from the log message; if the log message does not contain
+ * anything of interest, the event will be discarded.
+ *
+ * @param source
+ * The event source.
+ * @param logMessage
+ * The log message.
+ * @throws IllegalArgumentException
+ * Thrown if the source is unknown.
+ */
+ synchronized void observeUnparsedEvent(final String source,
+ final String logMessage) {
+ unparsedLogStatements.add(new EventImpl(source, logMessage));
+ notifyAll();
+ }
+
+ /**
+ * Add an internal event to the event queue.
+ *
+ * @param occurrenceTime
+ * The occurrence time of the event.
+ * @param source
+ * The event source.
+ * @param type
+ * The event type.
+ * @param message
+ * The event message.
+ * @throws IllegalArgumentException
+ * Thrown if the source is unknown.
+ */
+ public synchronized void observeInternalEvent(final long occurrenceTime,
+ final String source, final EventType type, final String message) {
+
+ if (!eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "observeInternalEvent",
+ e);
+ throw e;
+ }
+
+ unparsedLogStatements.add(new EventImpl(occurrenceTime, source, type,
+ message));
+ notifyAll();
+ }
+
+ /**
+ * Parses a log statement coming from Tor and decides whether it is
+ * interesting for us.
+ */
+ void parseNextEvent() {
+
+ // wait for the next event in the queue
+ EventImpl event = null;
+ synchronized (this) {
+ while (unparsedLogStatements.isEmpty()) {
+ try {
+ wait();
+ } catch (final InterruptedException e) {}
+ }
+ event = unparsedLogStatements.remove(0);
+ }
+
+ // does the event contain a known source? if not, discard it
+ if (!eventSources.contains(event.getSource())) {
+ logger.log(Level.WARNING,
+ "Unknown event source while parsing an event: "
+ + event.getSource());
+ return;
+ }
+
+ // does the event require parsing? if not, process immediately
+ if (event.getType() != null) {
+ observeEvent(event);
+ } else {
+ final String line = event.getMessage();
+
+ /*
+ * the logging output of Tor does not contain a year component; put
+ * in the year at the time of parsing (which happens approx. 10 ms
+ * after the logging took place) in the good hope that this tool is
+ * not run at midnight on New Year's Eve...
+ */
+ final Calendar c = Calendar.getInstance();
+ final int currentYear = c.get(Calendar.YEAR);
+
+ // try to apply one of the event type patterns
+ for (final Entry<Pattern, EventType> entry : eventTypePatterns
+ .entrySet()) {
+ final Matcher matcher = entry.getKey().matcher(line);
+ if (matcher.find()) {
+ final SimpleDateFormat sdf =
+ new SimpleDateFormat("MMM dd HH:mm:ss.SSS",
+ Locale.US);
+ final Date logTime = sdf.parse(line, new ParsePosition(0));
+ c.setTimeInMillis(logTime.getTime());
+ c.set(Calendar.YEAR, currentYear);
+ final long t = c.getTimeInMillis();
+ event.setOccurenceTime(t);
+ event.setType(entry.getValue());
+ observeEvent(event);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Map of all patterns, that should be included when parsing log statements
+ * coming from Tor, and the respective event types of the events that should
+ * be fired.
+ */
+ Map<Pattern, EventType> eventTypePatterns;
+
+ public synchronized void registerEventTypePattern(
+ final String patternString, final EventType eventType) {
+ eventTypePatterns.put(Pattern.compile(patternString), eventType);
+ }
+
+ /**
+ * Initializes the parsing engine with the standard log message patterns
+ * that should be included in current Tor. Any further patterns need to be
+ * added by the test application manually.
+ */
+ private void initializeEventTypePatterns() {
+ eventTypePatterns = new HashMap<Pattern, EventType>();
+ registerEventTypePattern("Opening Control listener on .*",
+ NodeEventType.NODE_CONTROL_PORT_OPENED);
+ registerEventTypePattern("Tor has successfully opened a circuit. "
+ + "Looks like client functionality is working.",
+ NodeEventType.NODE_CIRCUIT_OPENED);
+ registerEventTypePattern(
+ "Established circuit .* as introduction "
+ + "point for service .*",
+ HiddenServiceEventType.BOB_BUILT_INTRO_CIRC_SENDING_ESTABLISH_INTRO);
+ registerEventTypePattern("Received INTRO_ESTABLISHED cell on "
+ + "circuit .* for service .*",
+ HiddenServiceEventType.BOB_INTRO_ESTABLISHED_RECEIVED);
+ registerEventTypePattern("Sending publish request for hidden "
+ + "service .*", HiddenServiceEventType.BOB_SENDING_PUBLISH_DESC);
+ registerEventTypePattern("Uploaded rendezvous descriptor",
+ HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED);
+ registerEventTypePattern("Received INTRODUCE2 cell for service .* "
+ + "on circ .*", HiddenServiceEventType.BOB_INTRODUCE2_RECEIVED);
+ registerEventTypePattern("Done building circuit .* to rendezvous "
+ + "with cookie .* for service .*",
+ HiddenServiceEventType.BOB_BUILT_REND_CIRC_SENDING_RENDEZVOUS1);
+ registerEventTypePattern("begin is for rendezvous",
+ HiddenServiceEventType.BOB_APP_CONN_OPENED);
+ registerEventTypePattern("Got a hidden service request for ID '.*'",
+ HiddenServiceEventType.ALICE_ONION_REQUEST_RECEIVED);
+ registerEventTypePattern("Fetching rendezvous descriptor for "
+ + "service .*", HiddenServiceEventType.ALICE_SENDING_FETCH_DESC);
+ registerEventTypePattern("Received rendezvous descriptor",
+ HiddenServiceEventType.ALICE_DESC_FETCHED_RECEIVED);
+ registerEventTypePattern(
+ "Sending an ESTABLISH_RENDEZVOUS cell",
+ HiddenServiceEventType.ALICE_BUILT_REND_CIRC_SENDING_ESTABLISH_RENDEZVOUS);
+ registerEventTypePattern("Got rendezvous ack. This circuit is now "
+ + "ready for rendezvous",
+ HiddenServiceEventType.ALICE_RENDEZVOUS_ESTABLISHED_RECEIVED);
+ registerEventTypePattern("introcirc is open",
+ HiddenServiceEventType.ALICE_BUILT_INTRO_CIRC);
+ registerEventTypePattern("Sending an INTRODUCE1 cell",
+ HiddenServiceEventType.ALICE_SENDING_INTRODUCE1);
+ registerEventTypePattern("Received ack. Telling rend circ",
+ HiddenServiceEventType.ALICE_INTRODUCE_ACK_RECEIVED);
+ registerEventTypePattern(
+ "Got RENDEZVOUS2 cell from hidden service",
+ HiddenServiceEventType.ALICE_RENDEZVOUS2_RECEIVED_APP_CONN_OPENED);
+ registerEventTypePattern("Handling rendezvous descriptor post",
+ HiddenServiceEventType.DIR_PUBLISH_DESC_RECEIVED);
+ registerEventTypePattern("Handling rendezvous descriptor get",
+ HiddenServiceEventType.DIR_FETCH_DESC_RECEIVED);
+ registerEventTypePattern(
+ "Received an ESTABLISH_INTRO request on circuit .*",
+ HiddenServiceEventType.IPO_RECEIVED_ESTABLISH_INTRO_SENDING_INTRO_ESTABLISHED);
+ registerEventTypePattern(
+ "Received an INTRODUCE1 request on circuit .*",
+ HiddenServiceEventType.IPO_RECEIVED_INTRODUCE1_SENDING_INTRODUCE2_AND_INTRODUCE_ACK);
+ registerEventTypePattern(
+ "Received an ESTABLISH_RENDEZVOUS request on circuit .*",
+ HiddenServiceEventType.RPO_RECEIVED_ESTABLISH_RENDEZVOUS_SENDING_RENDEZVOUS_ESTABLISHED);
+ registerEventTypePattern(
+ "Got request for rendezvous from circuit .* to cookie .*",
+ HiddenServiceEventType.RPO_RECEIVING_RENDEZVOUS1_SENDING_RENDEZVOUS2);
+ }
+
+ /**
+ * Stores the given <code>event</code> from <code>source</code> to the
+ * event history and propagates its occurrence to all registered event
+ * handlers.
+ *
+ * @param event
+ * The observed event.
+ */
+ private synchronized void observeEvent(final Event event) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "observeEvent", event);
+
+ final String source = event.getSource();
+ logger.log(Level.FINE, "Observed event " + event + " from source "
+ + source + "!");
+
+ // remember observed event
+ if (!observedEvents.containsKey(event.getSource())) {
+ observedEvents.put(source, new ArrayList<Event>());
+ }
+ observedEvents.get(source).add(event);
+
+ // notify waiting threads
+ notifyAll();
+
+ // inform event listeners
+ if (eventHandlers.containsKey(source)) {
+
+ // make a copy of the event handler set, because some event handlers
+ // might want to remove themselves from this set while handling the
+ // event
+ final Set<EventListener> copyOfEventHandlers =
+ new HashSet<EventListener>(eventHandlers.get(source));
+
+ for (final EventListener eventHandler : copyOfEventHandlers) {
+
+ logger.log(Level.FINE, "Informing event listener "
+ + eventHandler + " about recently observed event "
+ + event + " from source " + source + "!");
+ eventHandler.handleEvent(event);
+
+ }
+ }
+
+ // make a copy of the event handler set for all sources, because some
+ // event handlers might want to remove themselves from this set while
+ // handling the event
+ final Set<EventListener> copyOfEventHandlersForAllSources =
+ new HashSet<EventListener>(eventHandlersForAllSources);
+
+ for (final EventListener eventHandler : copyOfEventHandlersForAllSources) {
+
+ logger.log(Level.FINE, "Informing event listener " + eventHandler
+ + " about recently observed event " + event
+ + " from source " + source + "!");
+ eventHandler.handleEvent(event);
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "observeEvent");
+ }
+
+ public synchronized void removeEventListener(
+ final EventListener eventListener) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "removeEventListener",
+ eventListener);
+
+ // check parameters
+ if (eventListener == null) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger
+ .throwing(this.getClass().getName(), "removeEventListener",
+ e);
+ throw e;
+ }
+
+ // don't know to which source this listener has been added (may to more
+ // than one), so remove it from all possible sets
+ for (final Set<EventListener> set : eventHandlers.values()) {
+ if (set.remove(eventListener)) {
+ logger.log(Level.FINE, "Removed event listener!");
+ }
+ }
+
+ // remove from event listeners for all sources
+ if (eventHandlersForAllSources.remove(eventListener)) {
+ logger.log(Level.FINE, "Removed event listener!");
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "removeEventListener");
+ }
+
+ public synchronized void waitForAnyOccurence(final String source,
+ final EventType event) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "waitForAnyOccurence",
+ new Object[] { source, event });
+
+ // check parameters
+ if (source == null || event == null || !eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger
+ .throwing(this.getClass().getName(), "waitForAnyOccurence",
+ e);
+ throw e;
+ }
+
+ // invoke overloaded method with maximumTimeToWaitInMillis of -1L which
+ // means to wait forever
+ waitForAnyOccurence(source, event, -1L);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "waitForAnyOccurence");
+
+ }
+
+ public synchronized boolean waitForAnyOccurence(final String source,
+ final EventType event, final long maximumTimeToWaitInMillis) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "waitForAnyOccurence",
+ new Object[] { source, event, maximumTimeToWaitInMillis });
+
+ // check parameters
+ if (source == null || event == null || !eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger
+ .throwing(this.getClass().getName(), "waitForAnyOccurence",
+ e);
+ throw e;
+ }
+
+ // check if we have already observed the event
+ if (hasEventOccured(source, event)) {
+ logger.log(Level.FINE, "Waiting for any occurence of event "
+ + event + " returned immediately!");
+ logger.exiting(this.getClass().getName(), "waitForAnyOccurence",
+ true);
+ return true;
+ }
+
+ // invoke method that waits for next occurence of the event
+ final boolean result =
+ waitForNextOccurence(source, event, maximumTimeToWaitInMillis);
+
+ // log exiting and return result
+ logger
+ .exiting(this.getClass().getName(), "waitForAnyOccurence",
+ result);
+ return result;
+ }
+
+ public synchronized void waitForNextOccurence(final String source,
+ final EventType event) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "waitForNextOccurence",
+ new Object[] { source, event });
+
+ // check parameters
+ if (source == null || event == null || !eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "waitForNextOccurence",
+ e);
+ throw e;
+ }
+
+ // invoke overloaded method with maximumTimeToWaitInMillis of -1L which
+ // means to wait forever
+ waitForNextOccurence(source, event, -1L);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "waitForNextOccurence");
+ }
+
+ public synchronized boolean waitForNextOccurence(final String source,
+ final EventType type, final long maximumTimeToWaitInMillis) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "waitForNextOccurence",
+ new Object[] { source, type, maximumTimeToWaitInMillis });
+
+ // check parameters
+ if (source == null || type == null || !eventSources.contains(source)) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "waitForNextOccurence",
+ e);
+ throw e;
+ }
+
+ // distinguish between negative waiting time (wait forever) and zero or
+ // positive waiting time
+ if (maximumTimeToWaitInMillis < 0) {
+
+ // wait forever
+ while (!hasEventOccured(source, type)) {
+
+ logger.log(Level.FINEST,
+ "We will wait infinetely for the next occurence of "
+ + "event type " + type + " from source "
+ + source + "...");
+ try {
+ wait();
+ } catch (final InterruptedException e) {
+ // don't handle
+ }
+
+ logger.log(Level.FINEST,
+ "We have been notified about an observed event while "
+ + "waiting for events of type " + type
+ + " from source " + source
+ + "; need to check whether the observed event "
+ + "is what we are looking for...");
+ }
+
+ logger.log(Level.FINE, "Waiting for occurence of event type "
+ + type + " succeeded!");
+
+ // log exiting and return result
+ logger.exiting(this.getClass().getName(), "waitForNextOccurence",
+ true);
+ return true;
+
+ }
+
+ // wait for the given time at most
+ final long endOfTime =
+ System.currentTimeMillis() + maximumTimeToWaitInMillis;
+ long timeLeft = 0;
+ while (!hasEventOccured(source, type)
+ && (timeLeft = endOfTime - System.currentTimeMillis()) > 0) {
+
+ logger.log(Level.FINEST, "We will wait for " + timeLeft
+ + " milliseconds for the next occurence of event type "
+ + type + " from source " + source + "...");
+
+ try {
+ wait(timeLeft);
+ } catch (final InterruptedException e) {
+ // don't handle
+ }
+
+ logger.log(Level.FINEST,
+ "We have been notified about an observed event while "
+ + "waiting for events of type " + type
+ + " from source " + source
+ + "; need to check whether the observed event "
+ + "is what we are looking for...");
+ }
+
+ // determine result
+ final boolean result = hasEventOccured(source, type);
+
+ logger.log(Level.FINE, "Waiting for next occurence of event type "
+ + type + " from source " + source
+ + (result ? " succeeded!" : " did not succeed!"));
+
+ // log exiting and return result
+ logger.exiting(this.getClass().getName(), "waitForNextOccurence",
+ result);
+ return result;
+ }
+
+ /**
+ * Adds the given <code>source</code> as possible event source.
+ *
+ * @param source
+ * The name of the node, client, or server to add.
+ * @throws IllegalArgumentException
+ * Thrown if there is already an event source with this name.
+ */
+ void addEventSource(final String source) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addEventSource", source);
+
+ // check if source name is unique in this network
+ if (eventSources.contains(source)) {
+ final IllegalArgumentException e =
+ new IllegalArgumentException(
+ "There is already an event source with name "
+ + source + " in this network!");
+ logger.throwing(this.getClass().getName(), "addEventSource", e);
+ throw e;
+ }
+
+ // add event source name
+ eventSources.add(source);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "addEventSource");
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName();
+ }
}
diff --git a/src/org/torproject/puppetor/impl/HiddenServiceImpl.java b/src/org/torproject/puppetor/impl/HiddenServiceImpl.java
index 35fe787..1ece2e4 100644
--- a/src/org/torproject/puppetor/impl/HiddenServiceImpl.java
+++ b/src/org/torproject/puppetor/impl/HiddenServiceImpl.java
@@ -23,145 +23,145 @@ import org.torproject.puppetor.PuppeTorException;
*/
public class HiddenServiceImpl implements HiddenService {
- /**
- * Logger for this node which is called "hidserv." plus the name of this
- * hidden service.
- */
- protected Logger logger;
-
- /**
- * The node at which this hidden service is configured.
- */
- private final ProxyNodeImpl node;
-
- /**
- * Name of the hidden service that will be used as name for the hidden
- * service directory.
- */
- private final String serviceName;
-
- /**
- * The TCP port on which the service will be available for requests.
- */
- private final int servicePort;
-
- /**
- * The virtual TCP port that this hidden service runs on as it is announced
- * to clients.
- */
- private final int virtualPort;
-
- /**
- * Adds the entries for a hidden service to the configuration of this node.
- *
- * Creates a new <code>HiddenServiceImpl</code>.
- *
- * @param node
- * The node at which this hidden service is configured.
- * @param serviceName
- * Name of the hidden service that will be used as name for the
- * hidden service directory. May neither be <code>null</code>
- * or a zero-length string.
- * @param servicePort
- * The TCP port on which the service will be available for
- * requests. This can, but need not be different from the virtual
- * port that is announced to clients. May not be negative or
- * greater than 65535.
- * @param virtualPort
- * The virtual TCP port that this hidden service runs on as it is
- * announced to clients. May not be negative or greater than
- * 65535.
- * @throws IllegalArgumentException
- * Thrown if an invalid value is given for either of the
- * parameters.
- */
- HiddenServiceImpl(final ProxyNodeImpl node, final String serviceName,
- final int servicePort, final int virtualPort) {
-
- // check if networkName can be used as logger name
- if (serviceName == null || serviceName.length() == 0) {
- throw new IllegalArgumentException("Invalid serviceName: "
- + serviceName);
- }
-
- // create logger
- logger = Logger.getLogger("hidserv." + serviceName);
-
- // log entering
- logger.entering(this.getClass().getName(), "HiddenServiceImpl",
- new Object[] { node, serviceName, servicePort, virtualPort });
-
- // check parameters
- if (servicePort < 0 || servicePort > 65535 || virtualPort < 0
- || virtualPort > 65535) {
- logger.log(Level.SEVERE,
- "Illegal argument when adding hidden service!");
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "addHiddenService", e);
- throw e;
- }
-
- // store parameter values
- this.node = node;
- this.serviceName = serviceName;
- this.servicePort = servicePort;
- this.virtualPort = virtualPort;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "HiddenServiceImpl");
- }
-
- public String determineOnionAddress() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "getOnionAddress");
-
- // check if hidden service directory exists
- final File hiddenServiceFile =
- new File(node.getWorkingDir().getAbsolutePath()
- + File.separator + serviceName + File.separator
- + "hostname");
- if (!hiddenServiceFile.exists()) {
- logger.log(Level.SEVERE,
- "Hidden service directory or hostname file does not exist: "
- + hiddenServiceFile.getAbsolutePath());
-
- final PuppeTorException e =
- new PuppeTorException(
- "Hidden service directory or hostname file does not exist: "
- + hiddenServiceFile.getAbsolutePath());
- logger.throwing(this.getClass().getName(), "getOnionAddress", e);
- throw e;
- }
-
- // read hostname from file
- String address = null;
- try {
- final BufferedReader br =
- new BufferedReader(new FileReader(hiddenServiceFile));
- address = br.readLine();
- br.close();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException("Could not read hostname file!", e);
- logger.throwing(this.getClass().getName(), "getOnionAddress", ex);
- throw ex;
- }
-
- // log exiting and return address
- logger.exiting(this.getClass().getName(), "getOnionAddress", address);
- return address;
- }
-
- public String getServiceName() {
- return serviceName;
- }
-
- public int getServicePort() {
- return servicePort;
- }
-
- public int getVirtualPort() {
- return virtualPort;
- }
+ /**
+ * Logger for this node which is called "hidserv." plus the name of this
+ * hidden service.
+ */
+ protected Logger logger;
+
+ /**
+ * The node at which this hidden service is configured.
+ */
+ private final ProxyNodeImpl node;
+
+ /**
+ * Name of the hidden service that will be used as name for the hidden
+ * service directory.
+ */
+ private final String serviceName;
+
+ /**
+ * The TCP port on which the service will be available for requests.
+ */
+ private final int servicePort;
+
+ /**
+ * The virtual TCP port that this hidden service runs on as it is announced
+ * to clients.
+ */
+ private final int virtualPort;
+
+ /**
+ * Adds the entries for a hidden service to the configuration of this node.
+ *
+ * Creates a new <code>HiddenServiceImpl</code>.
+ *
+ * @param node
+ * The node at which this hidden service is configured.
+ * @param serviceName
+ * Name of the hidden service that will be used as name for the
+ * hidden service directory. May neither be <code>null</code>
+ * or a zero-length string.
+ * @param servicePort
+ * The TCP port on which the service will be available for
+ * requests. This can, but need not be different from the virtual
+ * port that is announced to clients. May not be negative or
+ * greater than 65535.
+ * @param virtualPort
+ * The virtual TCP port that this hidden service runs on as it is
+ * announced to clients. May not be negative or greater than
+ * 65535.
+ * @throws IllegalArgumentException
+ * Thrown if an invalid value is given for either of the
+ * parameters.
+ */
+ HiddenServiceImpl(final ProxyNodeImpl node, final String serviceName,
+ final int servicePort, final int virtualPort) {
+
+ // check if networkName can be used as logger name
+ if (serviceName == null || serviceName.length() == 0) {
+ throw new IllegalArgumentException("Invalid serviceName: "
+ + serviceName);
+ }
+
+ // create logger
+ logger = Logger.getLogger("hidserv." + serviceName);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "HiddenServiceImpl",
+ new Object[] { node, serviceName, servicePort, virtualPort });
+
+ // check parameters
+ if (servicePort < 0 || servicePort > 65535 || virtualPort < 0
+ || virtualPort > 65535) {
+ logger.log(Level.SEVERE,
+ "Illegal argument when adding hidden service!");
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "addHiddenService", e);
+ throw e;
+ }
+
+ // store parameter values
+ this.node = node;
+ this.serviceName = serviceName;
+ this.servicePort = servicePort;
+ this.virtualPort = virtualPort;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "HiddenServiceImpl");
+ }
+
+ public String determineOnionAddress() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "getOnionAddress");
+
+ // check if hidden service directory exists
+ final File hiddenServiceFile =
+ new File(node.getWorkingDir().getAbsolutePath()
+ + File.separator + serviceName + File.separator
+ + "hostname");
+ if (!hiddenServiceFile.exists()) {
+ logger.log(Level.SEVERE,
+ "Hidden service directory or hostname file does not exist: "
+ + hiddenServiceFile.getAbsolutePath());
+
+ final PuppeTorException e =
+ new PuppeTorException(
+ "Hidden service directory or hostname file does not exist: "
+ + hiddenServiceFile.getAbsolutePath());
+ logger.throwing(this.getClass().getName(), "getOnionAddress", e);
+ throw e;
+ }
+
+ // read hostname from file
+ String address = null;
+ try {
+ final BufferedReader br =
+ new BufferedReader(new FileReader(hiddenServiceFile));
+ address = br.readLine();
+ br.close();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException("Could not read hostname file!", e);
+ logger.throwing(this.getClass().getName(), "getOnionAddress", ex);
+ throw ex;
+ }
+
+ // log exiting and return address
+ logger.exiting(this.getClass().getName(), "getOnionAddress", address);
+ return address;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public int getServicePort() {
+ return servicePort;
+ }
+
+ public int getVirtualPort() {
+ return virtualPort;
+ }
}
diff --git a/src/org/torproject/puppetor/impl/NetworkImpl.java b/src/org/torproject/puppetor/impl/NetworkImpl.java
index 8bda03d..a0eb0c8 100644
--- a/src/org/torproject/puppetor/impl/NetworkImpl.java
+++ b/src/org/torproject/puppetor/impl/NetworkImpl.java
@@ -37,1047 +37,1047 @@ import org.torproject.puppetor.ServerApplication;
*/
public class NetworkImpl implements Network {
- /**
- * Internal thread class that is used to start Tor processes in parallel.
- */
- private class NodeStarter extends Thread {
-
- /**
- * The exception, if one is caught while trying to start the node.
- */
- Exception caughtException;
-
- /**
- * The maximum time to wait for the Tor process to start in
- * milliseconds.
- */
- private final long maximumTimeToWaitInMillis;
-
- /**
- * The node for which the Tor process shall be started.
- */
- private final ProxyNode node;
-
- /**
- * Flag that denotes whether starting the Tor process was successful.
- */
- boolean success = false;
-
- /**
- * Creates a new <code>NodeStarter</code> for node <code>node</code>
- * that will wait for <code>maximumTimeToWaitInMillis</code>
- * milliseconds to start a Tor process, but that is not started, yet.
- *
- * @param node
- * The node for which the Tor process shall be started.
- * @param maximumTimeToWaitInMillis
- * The maximum time to wait for the Tor process to start in
- * milliseconds.
- */
- NodeStarter(final ProxyNode node, final long maximumTimeToWaitInMillis) {
-
- // log entering
- logger.entering(this.getClass().getName(), "NodeStarter",
- new Object[] { node, maximumTimeToWaitInMillis });
-
- // store parameters
- this.node = node;
- this.maximumTimeToWaitInMillis = maximumTimeToWaitInMillis;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "NodeStarter");
- }
-
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- try {
- // try to start node
- success = node.startNode(maximumTimeToWaitInMillis);
- } catch (final PuppeTorException e) {
- logger.log(Level.SEVERE,
- "Caught an exception while starting node "
- + node.toString() + "!");
- caughtException = e;
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
- }
-
- /**
- * Event manager to which all events concerning this network are notified.
- */
- private final EventManagerImpl eventManager;
-
- /**
- * Logger for this network which is called "network." plus the name of this
- * network.
- */
- private final Logger logger;
-
- /**
- * Contains the name of this network configuration which is the String
- * conversion of System.currentTimeMillis() of the network creation time.
- */
- private final String networkName;
-
- /**
- * All nodes contained in this network.
- */
- private final Map<String, ProxyNode> nodes;
-
- /**
- * Directory that contains status information of all nodes contained in this
- * network.
- */
- private final File workingDir;
-
- /**
- * The counter for automatically assigned port numbers created by this
- * <code>Network</code>.
- */
- private int portCounter = 7000;
-
- /**
- * Creates an initially unpopulated Tor network and creates a new working
- * directory for it at test-env/randomTestID/.
- *
- * @param networkName
- * Name of this network configuration. May neither be
- * <code>null</code> or a zero-length string.
- * @param startPort
- * The initial value for automatically assigned port numbers of
- * nodes created by this <code>Network</code>; must be a value
- * between 1024 and 65535.
- * @throws IllegalArgumentException
- * Thrown if the given <code>networkName</code> is either
- * <code>null</code> or a zero-length string, or if an illegal
- * number is given for <code>startPort</code>.
- */
- public NetworkImpl(final String networkName, final int startPort) {
- // initialize using overloaded constructor
- this(networkName);
-
- // check if start port is valid
- if (startPort < 1024 || startPort > 65535) {
- throw new IllegalArgumentException("Invalid startPort: "
- + startPort);
- }
-
- // remember parameter
- portCounter = startPort;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "NetworkImpl");
- }
-
- /**
- * Creates an initially unpopulated Tor network and creates a new working
- * directory for it at test-env/randomTestID/.
- *
- * @param networkName
- * Name of this network configuration. May neither be
- * <code>null</code> or a zero-length string.
- * @throws IllegalArgumentException
- * Thrown if the given <code>networkName</code> is either
- * <code>null</code> or a zero-length string.
- */
- public NetworkImpl(final String networkName) {
-
- // check if networkName can be used as logger name
- if (networkName == null || networkName.length() == 0) {
- throw new IllegalArgumentException("Invalid networkName: "
- + networkName);
- }
-
- // create logger
- logger = Logger.getLogger("network." + networkName);
-
- // log entering
- logger.entering(this.getClass().getName(), "NetworkImpl", networkName);
-
- // TODO is this necessary?!
- logger.setLevel(Level.ALL);
-
- // remember parameter
- this.networkName = networkName;
-
- // create working directory
- workingDir = new File("test-env/" + System.currentTimeMillis());
- workingDir.mkdirs();
- logger.log(Level.FINE, "Created working directory \""
- + workingDir.getAbsolutePath() + "\"");
-
- // TODO if we want to log to file, set this... somehow...
- // this.logFile = new File(this.workingDir.getAbsolutePath()
- // + "\\events.log");
-
- // initialize data structures
- nodes = new ConcurrentHashMap<String, ProxyNode>();
-
- // create event manager
- eventManager = new EventManagerImpl(this.networkName);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "NetworkImpl");
- }
-
- /**
- * Returns whether all nodes in this network are up, or not.
- *
- * @return <code>true</code> if all nodes are up, <code>false</code> if
- * at least one node is not up.
- */
- private boolean allNodesUp() {
-
- // log entering
- logger.entering(this.getClass().getName(), "allNodesUp");
-
- // fail on first node that is not up
- for (final ProxyNode node : nodes.values()) {
- if (!eventManager.hasEventOccured(node.getNodeName(),
- NodeEventType.NODE_CIRCUIT_OPENED)) {
-
- // log exiting and return false
- logger.exiting(this.getClass().getName(), "allNodesUp");
- return false;
- }
- }
-
- // log exiting and return true
- logger.exiting(this.getClass().getName(), "allNodesUp");
- return true;
- }
-
- public void configureAsPrivateNetwork() throws PuppeTorException {
- // log entering
- logger.entering(this.getClass().getName(), "configureAsPrivateNetwork");
-
- // read DirServer strings for all directories
- final List<String> authorizedDirectoriesFingerprints =
- new ArrayList<String>();
- for (final ProxyNode node : nodes.values()) {
- if (node instanceof DirectoryNode) {
- final DirectoryNode dirNode = (DirectoryNode) node;
- authorizedDirectoriesFingerprints.add(dirNode
- .getDirServerString());
- }
- }
-
- this.configureAsPartOfPrivateNetwork(authorizedDirectoriesFingerprints);
-
- // read fingerprints for all directories and routers
- final HashSet<String> approvedRoutersFingerprints =
- new HashSet<String>();
- for (final ProxyNode node : nodes.values()) {
- if (node instanceof RouterNode) {
- final RouterNode routerOrDirNode = (RouterNode) node;
- approvedRoutersFingerprints.add(routerOrDirNode
- .getFingerprint());
- }
- }
-
- // write fingerprints for all directories and routers to the
- // approved-routers file
- for (final ProxyNode node : nodes.values()) {
- if (node instanceof DirectoryNode) {
- final DirectoryNode dirNode = (DirectoryNode) node;
- dirNode.addApprovedRouters(approvedRoutersFingerprints);
- }
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "configureAsPrivateNetwork");
- }
-
- public void configureAsPartOfPrivateNetwork(
- List<String> authorizedDirectoriesFingerprints) {
- //throws PuppeTorException {
- // log entering
- logger.entering(this.getClass().getName(), "configureAsPartOfPrivateNetwork");
-
- for (final ProxyNode node : nodes.values()) {
- if (node.getNodeState() == NodeState.CONFIGURING ||
- node.getNodeState() == NodeState.CONFIGURATION_WRITTEN) {
- // add to configuration
- node.addConfiguration("TestingTorNetwork 1");
- }
- }
-
- // configure nodes
- for (final ProxyNode node : nodes.values()) {
- if (node.getNodeState() == NodeState.CONFIGURING ||
- node.getNodeState() == NodeState.CONFIGURATION_WRITTEN) {
- // add to configuration
- node.addConfigurations(authorizedDirectoriesFingerprints);
- }
- }
-
-/* // read fingerprints for all directories and routers
- final HashSet<String> approvedRoutersFingerprints =
- new HashSet<String>();
- for (final ProxyNode node : nodes.values()) {
- if (node instanceof RouterNode) {
- final RouterNode routerOrDirNode = (RouterNode) node;
- approvedRoutersFingerprints.add(routerOrDirNode
- .getFingerprint());
- }
- }
-
- // write fingerprints for all directories and routers to the
- // approved-routers file
- for (final ProxyNode node : nodes.values()) {
- if (node instanceof DirectoryNode) {
- final DirectoryNode dirNode = (DirectoryNode) node;
- dirNode.addApprovedRouters(approvedRoutersFingerprints);
- }
- }
+ /**
+ * Internal thread class that is used to start Tor processes in parallel.
+ */
+ private class NodeStarter extends Thread {
+
+ /**
+ * The exception, if one is caught while trying to start the node.
+ */
+ Exception caughtException;
+
+ /**
+ * The maximum time to wait for the Tor process to start in
+ * milliseconds.
+ */
+ private final long maximumTimeToWaitInMillis;
+
+ /**
+ * The node for which the Tor process shall be started.
+ */
+ private final ProxyNode node;
+
+ /**
+ * Flag that denotes whether starting the Tor process was successful.
+ */
+ boolean success = false;
+
+ /**
+ * Creates a new <code>NodeStarter</code> for node <code>node</code>
+ * that will wait for <code>maximumTimeToWaitInMillis</code>
+ * milliseconds to start a Tor process, but that is not started, yet.
+ *
+ * @param node
+ * The node for which the Tor process shall be started.
+ * @param maximumTimeToWaitInMillis
+ * The maximum time to wait for the Tor process to start in
+ * milliseconds.
+ */
+ NodeStarter(final ProxyNode node, final long maximumTimeToWaitInMillis) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "NodeStarter",
+ new Object[] { node, maximumTimeToWaitInMillis });
+
+ // store parameters
+ this.node = node;
+ this.maximumTimeToWaitInMillis = maximumTimeToWaitInMillis;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "NodeStarter");
+ }
+
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ try {
+ // try to start node
+ success = node.startNode(maximumTimeToWaitInMillis);
+ } catch (final PuppeTorException e) {
+ logger.log(Level.SEVERE,
+ "Caught an exception while starting node "
+ + node.toString() + "!");
+ caughtException = e;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ }
+
+ /**
+ * Event manager to which all events concerning this network are notified.
+ */
+ private final EventManagerImpl eventManager;
+
+ /**
+ * Logger for this network which is called "network." plus the name of this
+ * network.
+ */
+ private final Logger logger;
+
+ /**
+ * Contains the name of this network configuration which is the String
+ * conversion of System.currentTimeMillis() of the network creation time.
+ */
+ private final String networkName;
+
+ /**
+ * All nodes contained in this network.
+ */
+ private final Map<String, ProxyNode> nodes;
+
+ /**
+ * Directory that contains status information of all nodes contained in this
+ * network.
+ */
+ private final File workingDir;
+
+ /**
+ * The counter for automatically assigned port numbers created by this
+ * <code>Network</code>.
+ */
+ private int portCounter = 7000;
+
+ /**
+ * Creates an initially unpopulated Tor network and creates a new working
+ * directory for it at test-env/randomTestID/.
+ *
+ * @param networkName
+ * Name of this network configuration. May neither be
+ * <code>null</code> or a zero-length string.
+ * @param startPort
+ * The initial value for automatically assigned port numbers of
+ * nodes created by this <code>Network</code>; must be a value
+ * between 1024 and 65535.
+ * @throws IllegalArgumentException
+ * Thrown if the given <code>networkName</code> is either
+ * <code>null</code> or a zero-length string, or if an illegal
+ * number is given for <code>startPort</code>.
+ */
+ public NetworkImpl(final String networkName, final int startPort) {
+ // initialize using overloaded constructor
+ this(networkName);
+
+ // check if start port is valid
+ if (startPort < 1024 || startPort > 65535) {
+ throw new IllegalArgumentException("Invalid startPort: "
+ + startPort);
+ }
+
+ // remember parameter
+ portCounter = startPort;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "NetworkImpl");
+ }
+
+ /**
+ * Creates an initially unpopulated Tor network and creates a new working
+ * directory for it at test-env/randomTestID/.
+ *
+ * @param networkName
+ * Name of this network configuration. May neither be
+ * <code>null</code> or a zero-length string.
+ * @throws IllegalArgumentException
+ * Thrown if the given <code>networkName</code> is either
+ * <code>null</code> or a zero-length string.
+ */
+ public NetworkImpl(final String networkName) {
+
+ // check if networkName can be used as logger name
+ if (networkName == null || networkName.length() == 0) {
+ throw new IllegalArgumentException("Invalid networkName: "
+ + networkName);
+ }
+
+ // create logger
+ logger = Logger.getLogger("network." + networkName);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "NetworkImpl", networkName);
+
+ // TODO is this necessary?!
+ logger.setLevel(Level.ALL);
+
+ // remember parameter
+ this.networkName = networkName;
+
+ // create working directory
+ workingDir = new File("test-env/" + System.currentTimeMillis());
+ workingDir.mkdirs();
+ logger.log(Level.FINE, "Created working directory \""
+ + workingDir.getAbsolutePath() + "\"");
+
+ // TODO if we want to log to file, set this... somehow...
+ // this.logFile = new File(this.workingDir.getAbsolutePath()
+ // + "\\events.log");
+
+ // initialize data structures
+ nodes = new ConcurrentHashMap<String, ProxyNode>();
+
+ // create event manager
+ eventManager = new EventManagerImpl(this.networkName);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "NetworkImpl");
+ }
+
+ /**
+ * Returns whether all nodes in this network are up, or not.
+ *
+ * @return <code>true</code> if all nodes are up, <code>false</code> if
+ * at least one node is not up.
+ */
+ private boolean allNodesUp() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "allNodesUp");
+
+ // fail on first node that is not up
+ for (final ProxyNode node : nodes.values()) {
+ if (!eventManager.hasEventOccured(node.getNodeName(),
+ NodeEventType.NODE_CIRCUIT_OPENED)) {
+
+ // log exiting and return false
+ logger.exiting(this.getClass().getName(), "allNodesUp");
+ return false;
+ }
+ }
+
+ // log exiting and return true
+ logger.exiting(this.getClass().getName(), "allNodesUp");
+ return true;
+ }
+
+ public void configureAsPrivateNetwork() throws PuppeTorException {
+ // log entering
+ logger.entering(this.getClass().getName(), "configureAsPrivateNetwork");
+
+ // read DirServer strings for all directories
+ final List<String> authorizedDirectoriesFingerprints =
+ new ArrayList<String>();
+ for (final ProxyNode node : nodes.values()) {
+ if (node instanceof DirectoryNode) {
+ final DirectoryNode dirNode = (DirectoryNode) node;
+ authorizedDirectoriesFingerprints.add(dirNode
+ .getDirServerString());
+ }
+ }
+
+ this.configureAsPartOfPrivateNetwork(authorizedDirectoriesFingerprints);
+
+ // read fingerprints for all directories and routers
+ final HashSet<String> approvedRoutersFingerprints =
+ new HashSet<String>();
+ for (final ProxyNode node : nodes.values()) {
+ if (node instanceof RouterNode) {
+ final RouterNode routerOrDirNode = (RouterNode) node;
+ approvedRoutersFingerprints.add(routerOrDirNode
+ .getFingerprint());
+ }
+ }
+
+ // write fingerprints for all directories and routers to the
+ // approved-routers file
+ for (final ProxyNode node : nodes.values()) {
+ if (node instanceof DirectoryNode) {
+ final DirectoryNode dirNode = (DirectoryNode) node;
+ dirNode.addApprovedRouters(approvedRoutersFingerprints);
+ }
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "configureAsPrivateNetwork");
+ }
+
+ public void configureAsPartOfPrivateNetwork(
+ List<String> authorizedDirectoriesFingerprints) {
+ //throws PuppeTorException {
+ // log entering
+ logger.entering(this.getClass().getName(), "configureAsPartOfPrivateNetwork");
+
+ for (final ProxyNode node : nodes.values()) {
+ if (node.getNodeState() == NodeState.CONFIGURING ||
+ node.getNodeState() == NodeState.CONFIGURATION_WRITTEN) {
+ // add to configuration
+ node.addConfiguration("TestingTorNetwork 1");
+ }
+ }
+
+ // configure nodes
+ for (final ProxyNode node : nodes.values()) {
+ if (node.getNodeState() == NodeState.CONFIGURING ||
+ node.getNodeState() == NodeState.CONFIGURATION_WRITTEN) {
+ // add to configuration
+ node.addConfigurations(authorizedDirectoriesFingerprints);
+ }
+ }
+
+/* // read fingerprints for all directories and routers
+ final HashSet<String> approvedRoutersFingerprints =
+ new HashSet<String>();
+ for (final ProxyNode node : nodes.values()) {
+ if (node instanceof RouterNode) {
+ final RouterNode routerOrDirNode = (RouterNode) node;
+ approvedRoutersFingerprints.add(routerOrDirNode
+ .getFingerprint());
+ }
+ }
+
+ // write fingerprints for all directories and routers to the
+ // approved-routers file
+ for (final ProxyNode node : nodes.values()) {
+ if (node instanceof DirectoryNode) {
+ final DirectoryNode dirNode = (DirectoryNode) node;
+ dirNode.addApprovedRouters(approvedRoutersFingerprints);
+ }
+ }
*/
- // log exiting
- logger.exiting(this.getClass().getName(), "configureAsPartOfPrivateNetwork");
- }
-
- public ClientApplication createClient(final String clientApplicationName,
- final String targetAddress, final int targetPort,
- final int socksPort) {
- // log entering
- logger.entering(this.getClass().getName(), "createClient",
- new Object[] { clientApplicationName, targetAddress,
- targetPort, socksPort });
-
- // create client; parameter checking is done in constructor
- final ClientApplicationImpl client =
- new ClientApplicationImpl(this, clientApplicationName,
- targetAddress, targetPort, socksPort);
-
- // add name to event manager as event source
- eventManager.addEventSource(clientApplicationName);
-
- // log exiting and return client
- logger.exiting(this.getClass().getName(), "createClient", client);
- return client;
- }
-
- public DirectoryNode createDirectory(final String nodeName,
- final int controlPort, final int socksPort, final int orPort,
- final int dirPort, final String serverIpAddress) {
- // log entering
- logger.entering(this.getClass().getName(), "createDirectory",
- new Object[] { nodeName, controlPort, socksPort, orPort,
- dirPort, serverIpAddress });
-
- // create directory node; parameter checking is done in constructor
- final DirectoryNode dir =
- new DirectoryNodeImpl(this, nodeName, controlPort, socksPort,
- orPort, dirPort, serverIpAddress);
-
- // add new directory node to nodes collection
- nodes.put(nodeName, dir);
-
- // add name to event manager as event source
- eventManager.addEventSource(nodeName);
-
- // log exiting and return directory node
- logger.exiting(this.getClass().getName(), "createDirectory", dir);
- return dir;
- }
-
- public DirectoryNode createDirectory(final String nodeName,
- final int controlPort, final int socksPort, final int orPort,
- final int dirPort) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createDirectory",
- new Object[] { nodeName, controlPort, socksPort, orPort,
- dirPort });
-
- // invoke overloaded method
- final DirectoryNode dir =
- this.createDirectory(nodeName, controlPort, socksPort, orPort,
- dirPort, "127.0.0.1");
-
- // log exiting and return directory node
- logger.exiting(this.getClass().getName(), "createDirectory", dir);
- return dir;
- }
-
- public DirectoryNode createDirectory(final String nodeName,
- final String serverIpAddress) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createDirectory",
- new Object[] { nodeName, serverIpAddress });
-
- // invoke overloaded method
- final DirectoryNode dir =
- this.createDirectory(nodeName, portCounter++, portCounter++,
- portCounter++, portCounter++, serverIpAddress);
-
- // log exiting and return directory node
- logger.exiting(this.getClass().getName(), "createDirectory", dir);
- return dir;
- }
-
- public DirectoryNode createDirectory(final String nodeName) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createDirectory", nodeName);
-
- // invoke overloaded method
- final DirectoryNode dir =
- this.createDirectory(nodeName, portCounter++, portCounter++,
- portCounter++, portCounter++, "127.0.0.1");
-
- // log exiting and return directory node
- logger.exiting(this.getClass().getName(), "createDirectory", dir);
- return dir;
- }
-
- public ProxyNode createProxy(final String nodeName, final int controlPort,
- final int socksPort) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createProxy", new Object[] {
- nodeName, controlPort, socksPort });
-
- // create proxy node; parameter checking is done in constructor
- final ProxyNode proxy =
- new ProxyNodeImpl(this, nodeName, controlPort, socksPort);
-
- // add new proxy node to nodes collection
- nodes.put(nodeName, proxy);
-
- // add name to event manager as event source
- eventManager.addEventSource(nodeName);
-
- // log exiting and return proxy node
- logger.exiting(this.getClass().getName(), "createProxy", proxy);
- return proxy;
- }
-
- public ProxyNode createProxy(final String nodeName) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createProxy", nodeName);
-
- // invoke overloaded method
- final ProxyNode proxy =
- this.createProxy(nodeName, portCounter++, portCounter++);
-
- // log exiting and return proxy node
- logger.exiting(this.getClass().getName(), "createProxy", proxy);
- return proxy;
- }
-
- public RouterNode createRouter(final String nodeName,
- final int controlPort, final int socksPort, final int orPort,
- final int dirPort, final String serverIpAddress) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createRouter",
- new Object[] { nodeName, controlPort, socksPort, orPort,
- dirPort, serverIpAddress });
-
- // create router node; parameter checking is done in constructor
- final RouterNode router =
- new RouterNodeImpl(this, nodeName, controlPort, socksPort,
- orPort, dirPort, serverIpAddress);
-
- // add new router node to nodes collection
- nodes.put(nodeName, router);
-
- // add name to event manager as event source
- eventManager.addEventSource(nodeName);
-
- // log exiting and return router node
- logger.exiting(this.getClass().getName(), "createRouter", router);
- return router;
- }
-
- public RouterNode createRouter(final String nodeName,
- final int controlPort, final int socksPort, final int orPort,
- final int dirPort) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createRouter",
- new Object[] { nodeName, controlPort, socksPort, orPort,
- dirPort });
-
- // invoke overloaded method
- final DirectoryNode dir =
- this.createDirectory(nodeName, controlPort, socksPort, orPort,
- dirPort, "127.0.0.1");
-
- // log exiting and return directory node
- logger.exiting(this.getClass().getName(), "createRouter", dir);
- return dir;
- }
-
- public RouterNode createRouter(final String nodeName,
- final String serverIpAddress) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createRouter",
- new Object[] { nodeName, serverIpAddress });
-
- // invoke overloaded method
- final RouterNode dir =
- this.createRouter(nodeName, portCounter++, portCounter++,
- portCounter++, portCounter++, serverIpAddress);
-
- // log exiting and return directory node
- logger.exiting(this.getClass().getName(), "createRouter", dir);
- return dir;
- }
-
- public RouterNode createRouter(final String nodeName) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createRouter", nodeName);
-
- // invoke overloaded method
- final RouterNode router =
- this.createRouter(nodeName, portCounter++, portCounter++,
- portCounter++, portCounter++, "127.0.0.1");
-
- // log exiting and return router node
- logger.exiting(this.getClass().getName(), "createRouter", router);
- return router;
- }
-
- public ServerApplication createServer(final String serverApplicationName,
- final int serverPort) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createServer",
- new Object[] { serverApplicationName, serverPort });
-
- // create server; parameter checking is done in constructor
- final ServerApplicationImpl server =
- new ServerApplicationImpl(this, serverApplicationName,
- serverPort);
-
- // add name to event manager as event source
- eventManager.addEventSource(serverApplicationName);
-
- // log exiting and return server
- logger.exiting(this.getClass().getName(), "createServer", server);
- return server;
- }
-
- public ServerApplication createServer(final String serverApplicationName) {
-
- // log entering
- logger.entering(this.getClass().getName(), "createServer",
- serverApplicationName);
-
- // invoke overloaded method
- final ServerApplication server =
- this.createServer(serverApplicationName, portCounter++);
-
- // log exiting and return server
- logger.exiting(this.getClass().getName(), "createServer", server);
- return server;
- }
-
- public EventManager getEventManager() {
- return eventManager;
- }
-
- /**
- * Returns the implementation instance of the event manager of this network.
- *
- * @return The implementation instance of the event manager of this network.
- */
- public EventManagerImpl getEventManagerImpl() {
- return eventManager;
- }
-
- public File getWorkingDirectory() {
- return workingDir;
- }
-
- public ProxyNode getNode(final String nodeName) {
- return nodes.get(nodeName);
- }
-
- public Map<String, ProxyNode> getAllProxyNodes() {
- final Map<String, ProxyNode> result = new HashMap<String, ProxyNode>();
- for (final String nodeName : nodes.keySet()) {
- final ProxyNode node = nodes.get(nodeName);
- if (!(node instanceof RouterNode)) {
- result.put(nodeName, node);
- }
- }
- return result;
- }
-
- public Map<String, RouterNode> getAllRouterNodes() {
- final Map<String, RouterNode> result =
- new HashMap<String, RouterNode>();
- for (final String nodeName : nodes.keySet()) {
- final ProxyNode node = nodes.get(nodeName);
- if (node instanceof RouterNode && !(node instanceof DirectoryNode)) {
- result.put(nodeName, (RouterNode) node);
- }
- }
- return result;
- }
-
- public Map<String, DirectoryNode> getAllDirectoryNodes() {
- final Map<String, DirectoryNode> result =
- new HashMap<String, DirectoryNode>();
- for (final String nodeName : nodes.keySet()) {
- final ProxyNode node = nodes.get(nodeName);
- if (node instanceof DirectoryNode) {
- result.put(nodeName, (DirectoryNode) node);
- }
- }
- return result;
- }
-
- public Map<String, ProxyNode> getAllNodes() {
- return new HashMap<String, ProxyNode>(nodes);
- }
-
- public boolean hupUntilUp(final int tries, final long hupInterval)
- throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "hupUntilUp", new Object[] {
- tries, hupInterval });
-
- // check if all nodes are running
- for (final ProxyNode node : nodes.values()) {
- if (node.getNodeState() != NodeState.RUNNING) {
- final IllegalStateException e =
- new IllegalStateException(
- "All nodes must be running before sending them HUP "
- + "commands!");
- logger.throwing(this.getClass().getName(), "hupUntilUp", e);
- throw e;
- }
- }
-
- // check if nodes are already up; if so, return immediately
- if (allNodesUp()) {
-
- // log exiting and return true
- logger.exiting(this.getClass().getName(), "hupUntilUp", true);
- return true;
- }
-
- final Object hupLock = new Object();
- // create and register a new event handler for each node
- for (final ProxyNode node : nodes.values()) {
- eventManager.addEventListener(node.getNodeName(),
- new EventListener() {
- public void handleEvent(final Event event) {
- if (event.getType() == NodeEventType.NODE_CIRCUIT_OPENED) {
- synchronized(hupLock) {
- hupLock.notify();
- }
- eventManager.removeEventListener(this);
- }
- }
- });
- }
-
- // walk through wait-check-hup loop until there are no tries left
- for (int i = 0; i < tries; i++) {
-
- // determine how long to try waiting for the hangup
- final long endOfSleeping = System.currentTimeMillis() + hupInterval;
-
- // unless all nodes have reported to be up, wait for the given
- // maximum time
- while (System.currentTimeMillis() < endOfSleeping) {
-
- synchronized(hupLock) {
- // check if nodes are up now
- if (allNodesUp()) {
-
- // log exiting and return true
- logger.exiting(this.getClass().getName(), "hupUntilUp",
- true);
- return true;
- }
- // sleep
- try {
- hupLock.wait(hupInterval);
- } catch (final InterruptedException e) {
- // do nothing about it
- }
- }
- }
-
- logger.log(Level.FINE, "Sending HUP to nodes");
- // send a HUP signal to all nodes
- for (final ProxyNode node : nodes.values()) {
- logger
- .log(Level.FINE, "Sending HUP to node "
- + node.toString());
- node.hup();
- }
-
- // continue in loop
- }
-
- // no retries left and not all nodes are up; log exiting and return
- // failure
- logger.exiting(this.getClass().getName(), "hupUntilUp", false);
- return false;
- }
-
- public void hupAllNodes() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "hupAllNodes");
-
- // check if all nodes are running
- for (final ProxyNode node : nodes.values()) {
- if (node.getNodeState() != NodeState.RUNNING) {
- final IllegalStateException e =
- new IllegalStateException(
- "All nodes must be running before sending them HUP "
- + "commands!");
- logger.throwing(this.getClass().getName(), "hupAllNodes", e);
- throw e;
- }
- }
-
- // send a HUP signal to all nodes
- for (final ProxyNode node : nodes.values()) {
- logger.log(Level.FINE, "Sending HUP to node " + node.toString());
- node.hup();
- }
-
- // no retries left and not all nodes are up; log exiting and return
- // failure
- logger.exiting(this.getClass().getName(), "hupAllNodes");
- }
-
- public void hupAllDirectories() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "hupAllDirectories");
-
- // check if all directory nodes are running
- for (final ProxyNode node : nodes.values()) {
- if (node instanceof DirectoryNode
- && node.getNodeState() != NodeState.RUNNING) {
- final IllegalStateException e =
- new IllegalStateException(
- "All directory nodes must be running before sending "
- + "them HUP commands!");
- logger.throwing(this.getClass().getName(), "hupAllDirectories",
- e);
- throw e;
- }
- }
-
- // send a HUP signal to all nodes
- for (final ProxyNode node : nodes.values()) {
- if (node instanceof DirectoryNode) {
- logger
- .log(Level.FINE, "Sending HUP to node "
- + node.toString());
- node.hup();
- }
- }
-
- // no retries left and not all nodes are up; log exiting and return
- // failure
- logger.exiting(this.getClass().getName(), "hupAllDirectories");
- }
-
- public void shutdownNodes() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "shutdownNodes");
-
- // iteratively shut down all running nodes; if an exception is caught,
- // continue shutting down the other nodes and throw the first exception
- // subsequently
- PuppeTorException firstCaughtException = null;
- for (final ProxyNode node : nodes.values()) {
- if (node.getNodeState() == NodeState.RUNNING) {
- try {
- node.shutdown();
- } catch (final PuppeTorException e) {
- if (firstCaughtException == null) {
- firstCaughtException = e;
- }
- }
- }
- }
-
- // if an exception was caught during shutting down nodes, throw the
- // first caught exception
- if (firstCaughtException != null) {
- logger.throwing(this.getClass().getName(), "shutdownNodes",
- firstCaughtException);
- throw firstCaughtException;
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "shutdownNodes");
- }
-
- public boolean startNodes(final long maximumTimeToWaitInMillis)
- throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "startNodes",
- maximumTimeToWaitInMillis);
-
- // check node states
- for (final ProxyNode node : nodes.values()) {
- if (node.getNodeState() != NodeState.CONFIGURATION_WRITTEN) {
- final IllegalStateException e =
- new IllegalStateException(
- "All configurations must be written before starting "
- + "nodes!");
- logger.throwing(this.getClass().getName(), "startNodes", e);
- throw e;
- }
- }
-
- // check parameter
- if (maximumTimeToWaitInMillis < 0) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "startNodes", e);
- throw e;
- }
-
- // remember time when we begin starting the nodes
- final long before = System.currentTimeMillis();
-
- // start nodes in parallel
- final Set<NodeStarter> allNodeStarters = new HashSet<NodeStarter>();
- for (final ProxyNode node : nodes.values()) {
- final NodeStarter nodeStarter =
- new NodeStarter(node, maximumTimeToWaitInMillis);
- allNodeStarters.add(nodeStarter);
- nodeStarter.start();
- }
-
- // wait for all node starts to complete
- for (final NodeStarter nodeStarter : allNodeStarters) {
-
- // join node starts one after the other
- try {
- nodeStarter.join();
- } catch (final InterruptedException e) {
- // this happens?! we have some kind of problem here!
- logger.log(Level.WARNING,
- "Interrupt while joining node starter!");
-
- // log exiting and return false
- logger.exiting(this.getClass().getName(), "startNodes", false);
- return false;
- }
-
- // if any thread has caught an exception, throw that exception now
- final Exception caughtException = nodeStarter.caughtException;
- if (caughtException != null) {
- final PuppeTorException ex =
- new PuppeTorException("Exception while starting node "
- + nodeStarter.node.getNodeName(),
- caughtException);
- logger.throwing(this.getClass().getName(), "startNodes", ex);
- throw ex;
- }
-
- // if node start did not succeed in the given time, fail
- if (!nodeStarter.success) {
- logger.log(Level.WARNING,
- "Starting nodes was not successful in "
- + maximumTimeToWaitInMillis / 1000
- + " seconds.", networkName);
-
- // log exiting and return false
- logger.exiting(this.getClass().getName(), "startNodes", false);
- return false;
- }
- }
-
- // determine how long we took to start all nodes
- final long after = System.currentTimeMillis();
- logger.log(Level.FINE, "Starting nodes was successful and took "
- + (after - before) / 1000 + " seconds.", networkName);
-
- // log exiting and return true
- logger.exiting(this.getClass().getName(), "startNodes", true);
- return true;
- }
-
- @Override
- public String toString() {
- return this.getClass().getSimpleName() + ": networkName=\""
- + networkName;
- }
-
- public String getNetworkName() {
- return networkName;
- }
-
- public void writeConfigurations() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "writeConfigurations");
-
- // write configurations for all nodes
- for (final ProxyNode node : nodes.values()) {
- node.writeConfiguration();
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "writeConfigurations");
- }
-
- public void addTemplateConfiguration(
- final Class<? extends ProxyNode> nodeClass,
- final String templateConfigurationString) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addTemplateConfiguration",
- new Object[] { nodeClass, templateConfigurationString });
-
- // check parameters
- if (nodeClass == null || templateConfigurationString == null
- || templateConfigurationString.length() < 1
- || !templateConfigurationString.contains(" ")) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(),
- "addTemplateConfiguration", e);
- throw e;
- }
-
- // add template string to appropriate template configuration
- if (nodeClass == ProxyNode.class) {
- ProxyNodeImpl.templateConfiguration
- .add(templateConfigurationString);
- } else if (nodeClass == RouterNode.class) {
- RouterNodeImpl.templateConfiguration
- .add(templateConfigurationString);
- } else if (nodeClass == DirectoryNode.class) {
- DirectoryNodeImpl.templateConfiguration
- .add(templateConfigurationString);
- } else {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(),
- "addTemplateConfiguration", e);
- throw e;
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "addTemplateConfiguration");
- }
-
- public List<String> getTemplateConfiguration(
- final Class<? extends ProxyNode> nodeClass) {
-
- // log entering
- logger.entering(this.getClass().getName(), "getTemplateConfiguration",
- nodeClass);
-
- // check parameter
- if (nodeClass == null) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(),
- "getTemplateConfiguration", e);
- throw e;
- }
-
- // obtain reference on appropriate template configuration
- List<String> result = null;
- if (nodeClass == ProxyNode.class) {
- result = new ArrayList<String>(ProxyNodeImpl.templateConfiguration);
- } else if (nodeClass == RouterNode.class) {
- result =
- new ArrayList<String>(RouterNodeImpl.templateConfiguration);
- } else if (nodeClass == DirectoryNode.class) {
- result =
- new ArrayList<String>(
- DirectoryNodeImpl.templateConfiguration);
- } else {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(),
- "getTemplateConfiguration", e);
- throw e;
- }
-
- // log exiting and return result
- logger.exiting(this.getClass().getName(), "getTemplateConfiguration",
- result);
- return result;
- }
-
- public void removeTemplateConfiguration(
- final Class<? extends ProxyNode> nodeClass,
- final String templateConfigurationKey) {
-
- // log entering
- logger.entering(this.getClass().getName(),
- "removeTemplateConfiguration", new Object[] { nodeClass,
- templateConfigurationKey });
-
- // check parameters
- if (nodeClass == null || templateConfigurationKey == null
- || templateConfigurationKey.length() < 1) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(),
- "removeTemplateConfiguration", e);
- throw e;
- }
-
- // obtain reference on appropriate template configuration
- List<String> templateConfig = null;
- if (nodeClass == ProxyNode.class) {
- templateConfig = ProxyNodeImpl.templateConfiguration;
- } else if (nodeClass == RouterNode.class) {
- templateConfig = RouterNodeImpl.templateConfiguration;
- } else if (nodeClass == DirectoryNode.class) {
- templateConfig = DirectoryNodeImpl.templateConfiguration;
- } else {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(),
- "removeTemplateConfiguration", e);
- throw e;
- }
-
- // iterate over existing template configuration strings and remove all
- // configuration strings that have the given configuration key
- final List<String> configurationStringsToRemove =
- new ArrayList<String>();
- for (final String currentConfigurationString : templateConfig) {
- final String currentConfigurationKey =
- currentConfigurationString.substring(0,
- currentConfigurationString.indexOf(" "));
- if (currentConfigurationKey.equals(templateConfigurationKey)) {
- configurationStringsToRemove.add(currentConfigurationString);
- }
- }
- templateConfig.removeAll(configurationStringsToRemove);
-
- // log exiting
- logger
- .exiting(this.getClass().getName(),
- "removeTemplateConfiguration");
- }
-
- /**
- * Returns the current port number and increments it afterwards.
- *
- * @return The current port number.
- */
- int getNextPortNumber() {
- return portCounter++;
- }
+ // log exiting
+ logger.exiting(this.getClass().getName(), "configureAsPartOfPrivateNetwork");
+ }
+
+ public ClientApplication createClient(final String clientApplicationName,
+ final String targetAddress, final int targetPort,
+ final int socksPort) {
+ // log entering
+ logger.entering(this.getClass().getName(), "createClient",
+ new Object[] { clientApplicationName, targetAddress,
+ targetPort, socksPort });
+
+ // create client; parameter checking is done in constructor
+ final ClientApplicationImpl client =
+ new ClientApplicationImpl(this, clientApplicationName,
+ targetAddress, targetPort, socksPort);
+
+ // add name to event manager as event source
+ eventManager.addEventSource(clientApplicationName);
+
+ // log exiting and return client
+ logger.exiting(this.getClass().getName(), "createClient", client);
+ return client;
+ }
+
+ public DirectoryNode createDirectory(final String nodeName,
+ final int controlPort, final int socksPort, final int orPort,
+ final int dirPort, final String serverIpAddress) {
+ // log entering
+ logger.entering(this.getClass().getName(), "createDirectory",
+ new Object[] { nodeName, controlPort, socksPort, orPort,
+ dirPort, serverIpAddress });
+
+ // create directory node; parameter checking is done in constructor
+ final DirectoryNode dir =
+ new DirectoryNodeImpl(this, nodeName, controlPort, socksPort,
+ orPort, dirPort, serverIpAddress);
+
+ // add new directory node to nodes collection
+ nodes.put(nodeName, dir);
+
+ // add name to event manager as event source
+ eventManager.addEventSource(nodeName);
+
+ // log exiting and return directory node
+ logger.exiting(this.getClass().getName(), "createDirectory", dir);
+ return dir;
+ }
+
+ public DirectoryNode createDirectory(final String nodeName,
+ final int controlPort, final int socksPort, final int orPort,
+ final int dirPort) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createDirectory",
+ new Object[] { nodeName, controlPort, socksPort, orPort,
+ dirPort });
+
+ // invoke overloaded method
+ final DirectoryNode dir =
+ this.createDirectory(nodeName, controlPort, socksPort, orPort,
+ dirPort, "127.0.0.1");
+
+ // log exiting and return directory node
+ logger.exiting(this.getClass().getName(), "createDirectory", dir);
+ return dir;
+ }
+
+ public DirectoryNode createDirectory(final String nodeName,
+ final String serverIpAddress) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createDirectory",
+ new Object[] { nodeName, serverIpAddress });
+
+ // invoke overloaded method
+ final DirectoryNode dir =
+ this.createDirectory(nodeName, portCounter++, portCounter++,
+ portCounter++, portCounter++, serverIpAddress);
+
+ // log exiting and return directory node
+ logger.exiting(this.getClass().getName(), "createDirectory", dir);
+ return dir;
+ }
+
+ public DirectoryNode createDirectory(final String nodeName) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createDirectory", nodeName);
+
+ // invoke overloaded method
+ final DirectoryNode dir =
+ this.createDirectory(nodeName, portCounter++, portCounter++,
+ portCounter++, portCounter++, "127.0.0.1");
+
+ // log exiting and return directory node
+ logger.exiting(this.getClass().getName(), "createDirectory", dir);
+ return dir;
+ }
+
+ public ProxyNode createProxy(final String nodeName, final int controlPort,
+ final int socksPort) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createProxy", new Object[] {
+ nodeName, controlPort, socksPort });
+
+ // create proxy node; parameter checking is done in constructor
+ final ProxyNode proxy =
+ new ProxyNodeImpl(this, nodeName, controlPort, socksPort);
+
+ // add new proxy node to nodes collection
+ nodes.put(nodeName, proxy);
+
+ // add name to event manager as event source
+ eventManager.addEventSource(nodeName);
+
+ // log exiting and return proxy node
+ logger.exiting(this.getClass().getName(), "createProxy", proxy);
+ return proxy;
+ }
+
+ public ProxyNode createProxy(final String nodeName) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createProxy", nodeName);
+
+ // invoke overloaded method
+ final ProxyNode proxy =
+ this.createProxy(nodeName, portCounter++, portCounter++);
+
+ // log exiting and return proxy node
+ logger.exiting(this.getClass().getName(), "createProxy", proxy);
+ return proxy;
+ }
+
+ public RouterNode createRouter(final String nodeName,
+ final int controlPort, final int socksPort, final int orPort,
+ final int dirPort, final String serverIpAddress) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createRouter",
+ new Object[] { nodeName, controlPort, socksPort, orPort,
+ dirPort, serverIpAddress });
+
+ // create router node; parameter checking is done in constructor
+ final RouterNode router =
+ new RouterNodeImpl(this, nodeName, controlPort, socksPort,
+ orPort, dirPort, serverIpAddress);
+
+ // add new router node to nodes collection
+ nodes.put(nodeName, router);
+
+ // add name to event manager as event source
+ eventManager.addEventSource(nodeName);
+
+ // log exiting and return router node
+ logger.exiting(this.getClass().getName(), "createRouter", router);
+ return router;
+ }
+
+ public RouterNode createRouter(final String nodeName,
+ final int controlPort, final int socksPort, final int orPort,
+ final int dirPort) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createRouter",
+ new Object[] { nodeName, controlPort, socksPort, orPort,
+ dirPort });
+
+ // invoke overloaded method
+ final DirectoryNode dir =
+ this.createDirectory(nodeName, controlPort, socksPort, orPort,
+ dirPort, "127.0.0.1");
+
+ // log exiting and return directory node
+ logger.exiting(this.getClass().getName(), "createRouter", dir);
+ return dir;
+ }
+
+ public RouterNode createRouter(final String nodeName,
+ final String serverIpAddress) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createRouter",
+ new Object[] { nodeName, serverIpAddress });
+
+ // invoke overloaded method
+ final RouterNode dir =
+ this.createRouter(nodeName, portCounter++, portCounter++,
+ portCounter++, portCounter++, serverIpAddress);
+
+ // log exiting and return directory node
+ logger.exiting(this.getClass().getName(), "createRouter", dir);
+ return dir;
+ }
+
+ public RouterNode createRouter(final String nodeName) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createRouter", nodeName);
+
+ // invoke overloaded method
+ final RouterNode router =
+ this.createRouter(nodeName, portCounter++, portCounter++,
+ portCounter++, portCounter++, "127.0.0.1");
+
+ // log exiting and return router node
+ logger.exiting(this.getClass().getName(), "createRouter", router);
+ return router;
+ }
+
+ public ServerApplication createServer(final String serverApplicationName,
+ final int serverPort) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createServer",
+ new Object[] { serverApplicationName, serverPort });
+
+ // create server; parameter checking is done in constructor
+ final ServerApplicationImpl server =
+ new ServerApplicationImpl(this, serverApplicationName,
+ serverPort);
+
+ // add name to event manager as event source
+ eventManager.addEventSource(serverApplicationName);
+
+ // log exiting and return server
+ logger.exiting(this.getClass().getName(), "createServer", server);
+ return server;
+ }
+
+ public ServerApplication createServer(final String serverApplicationName) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "createServer",
+ serverApplicationName);
+
+ // invoke overloaded method
+ final ServerApplication server =
+ this.createServer(serverApplicationName, portCounter++);
+
+ // log exiting and return server
+ logger.exiting(this.getClass().getName(), "createServer", server);
+ return server;
+ }
+
+ public EventManager getEventManager() {
+ return eventManager;
+ }
+
+ /**
+ * Returns the implementation instance of the event manager of this network.
+ *
+ * @return The implementation instance of the event manager of this network.
+ */
+ public EventManagerImpl getEventManagerImpl() {
+ return eventManager;
+ }
+
+ public File getWorkingDirectory() {
+ return workingDir;
+ }
+
+ public ProxyNode getNode(final String nodeName) {
+ return nodes.get(nodeName);
+ }
+
+ public Map<String, ProxyNode> getAllProxyNodes() {
+ final Map<String, ProxyNode> result = new HashMap<String, ProxyNode>();
+ for (final String nodeName : nodes.keySet()) {
+ final ProxyNode node = nodes.get(nodeName);
+ if (!(node instanceof RouterNode)) {
+ result.put(nodeName, node);
+ }
+ }
+ return result;
+ }
+
+ public Map<String, RouterNode> getAllRouterNodes() {
+ final Map<String, RouterNode> result =
+ new HashMap<String, RouterNode>();
+ for (final String nodeName : nodes.keySet()) {
+ final ProxyNode node = nodes.get(nodeName);
+ if (node instanceof RouterNode && !(node instanceof DirectoryNode)) {
+ result.put(nodeName, (RouterNode) node);
+ }
+ }
+ return result;
+ }
+
+ public Map<String, DirectoryNode> getAllDirectoryNodes() {
+ final Map<String, DirectoryNode> result =
+ new HashMap<String, DirectoryNode>();
+ for (final String nodeName : nodes.keySet()) {
+ final ProxyNode node = nodes.get(nodeName);
+ if (node instanceof DirectoryNode) {
+ result.put(nodeName, (DirectoryNode) node);
+ }
+ }
+ return result;
+ }
+
+ public Map<String, ProxyNode> getAllNodes() {
+ return new HashMap<String, ProxyNode>(nodes);
+ }
+
+ public boolean hupUntilUp(final int tries, final long hupInterval)
+ throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "hupUntilUp", new Object[] {
+ tries, hupInterval });
+
+ // check if all nodes are running
+ for (final ProxyNode node : nodes.values()) {
+ if (node.getNodeState() != NodeState.RUNNING) {
+ final IllegalStateException e =
+ new IllegalStateException(
+ "All nodes must be running before sending them HUP "
+ + "commands!");
+ logger.throwing(this.getClass().getName(), "hupUntilUp", e);
+ throw e;
+ }
+ }
+
+ // check if nodes are already up; if so, return immediately
+ if (allNodesUp()) {
+
+ // log exiting and return true
+ logger.exiting(this.getClass().getName(), "hupUntilUp", true);
+ return true;
+ }
+
+ final Object hupLock = new Object();
+ // create and register a new event handler for each node
+ for (final ProxyNode node : nodes.values()) {
+ eventManager.addEventListener(node.getNodeName(),
+ new EventListener() {
+ public void handleEvent(final Event event) {
+ if (event.getType() == NodeEventType.NODE_CIRCUIT_OPENED) {
+ synchronized(hupLock) {
+ hupLock.notify();
+ }
+ eventManager.removeEventListener(this);
+ }
+ }
+ });
+ }
+
+ // walk through wait-check-hup loop until there are no tries left
+ for (int i = 0; i < tries; i++) {
+
+ // determine how long to try waiting for the hangup
+ final long endOfSleeping = System.currentTimeMillis() + hupInterval;
+
+ // unless all nodes have reported to be up, wait for the given
+ // maximum time
+ while (System.currentTimeMillis() < endOfSleeping) {
+
+ synchronized(hupLock) {
+ // check if nodes are up now
+ if (allNodesUp()) {
+
+ // log exiting and return true
+ logger.exiting(this.getClass().getName(), "hupUntilUp",
+ true);
+ return true;
+ }
+ // sleep
+ try {
+ hupLock.wait(hupInterval);
+ } catch (final InterruptedException e) {
+ // do nothing about it
+ }
+ }
+ }
+
+ logger.log(Level.FINE, "Sending HUP to nodes");
+ // send a HUP signal to all nodes
+ for (final ProxyNode node : nodes.values()) {
+ logger
+ .log(Level.FINE, "Sending HUP to node "
+ + node.toString());
+ node.hup();
+ }
+
+ // continue in loop
+ }
+
+ // no retries left and not all nodes are up; log exiting and return
+ // failure
+ logger.exiting(this.getClass().getName(), "hupUntilUp", false);
+ return false;
+ }
+
+ public void hupAllNodes() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "hupAllNodes");
+
+ // check if all nodes are running
+ for (final ProxyNode node : nodes.values()) {
+ if (node.getNodeState() != NodeState.RUNNING) {
+ final IllegalStateException e =
+ new IllegalStateException(
+ "All nodes must be running before sending them HUP "
+ + "commands!");
+ logger.throwing(this.getClass().getName(), "hupAllNodes", e);
+ throw e;
+ }
+ }
+
+ // send a HUP signal to all nodes
+ for (final ProxyNode node : nodes.values()) {
+ logger.log(Level.FINE, "Sending HUP to node " + node.toString());
+ node.hup();
+ }
+
+ // no retries left and not all nodes are up; log exiting and return
+ // failure
+ logger.exiting(this.getClass().getName(), "hupAllNodes");
+ }
+
+ public void hupAllDirectories() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "hupAllDirectories");
+
+ // check if all directory nodes are running
+ for (final ProxyNode node : nodes.values()) {
+ if (node instanceof DirectoryNode
+ && node.getNodeState() != NodeState.RUNNING) {
+ final IllegalStateException e =
+ new IllegalStateException(
+ "All directory nodes must be running before sending "
+ + "them HUP commands!");
+ logger.throwing(this.getClass().getName(), "hupAllDirectories",
+ e);
+ throw e;
+ }
+ }
+
+ // send a HUP signal to all nodes
+ for (final ProxyNode node : nodes.values()) {
+ if (node instanceof DirectoryNode) {
+ logger
+ .log(Level.FINE, "Sending HUP to node "
+ + node.toString());
+ node.hup();
+ }
+ }
+
+ // no retries left and not all nodes are up; log exiting and return
+ // failure
+ logger.exiting(this.getClass().getName(), "hupAllDirectories");
+ }
+
+ public void shutdownNodes() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "shutdownNodes");
+
+ // iteratively shut down all running nodes; if an exception is caught,
+ // continue shutting down the other nodes and throw the first exception
+ // subsequently
+ PuppeTorException firstCaughtException = null;
+ for (final ProxyNode node : nodes.values()) {
+ if (node.getNodeState() == NodeState.RUNNING) {
+ try {
+ node.shutdown();
+ } catch (final PuppeTorException e) {
+ if (firstCaughtException == null) {
+ firstCaughtException = e;
+ }
+ }
+ }
+ }
+
+ // if an exception was caught during shutting down nodes, throw the
+ // first caught exception
+ if (firstCaughtException != null) {
+ logger.throwing(this.getClass().getName(), "shutdownNodes",
+ firstCaughtException);
+ throw firstCaughtException;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "shutdownNodes");
+ }
+
+ public boolean startNodes(final long maximumTimeToWaitInMillis)
+ throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "startNodes",
+ maximumTimeToWaitInMillis);
+
+ // check node states
+ for (final ProxyNode node : nodes.values()) {
+ if (node.getNodeState() != NodeState.CONFIGURATION_WRITTEN) {
+ final IllegalStateException e =
+ new IllegalStateException(
+ "All configurations must be written before starting "
+ + "nodes!");
+ logger.throwing(this.getClass().getName(), "startNodes", e);
+ throw e;
+ }
+ }
+
+ // check parameter
+ if (maximumTimeToWaitInMillis < 0) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "startNodes", e);
+ throw e;
+ }
+
+ // remember time when we begin starting the nodes
+ final long before = System.currentTimeMillis();
+
+ // start nodes in parallel
+ final Set<NodeStarter> allNodeStarters = new HashSet<NodeStarter>();
+ for (final ProxyNode node : nodes.values()) {
+ final NodeStarter nodeStarter =
+ new NodeStarter(node, maximumTimeToWaitInMillis);
+ allNodeStarters.add(nodeStarter);
+ nodeStarter.start();
+ }
+
+ // wait for all node starts to complete
+ for (final NodeStarter nodeStarter : allNodeStarters) {
+
+ // join node starts one after the other
+ try {
+ nodeStarter.join();
+ } catch (final InterruptedException e) {
+ // this happens?! we have some kind of problem here!
+ logger.log(Level.WARNING,
+ "Interrupt while joining node starter!");
+
+ // log exiting and return false
+ logger.exiting(this.getClass().getName(), "startNodes", false);
+ return false;
+ }
+
+ // if any thread has caught an exception, throw that exception now
+ final Exception caughtException = nodeStarter.caughtException;
+ if (caughtException != null) {
+ final PuppeTorException ex =
+ new PuppeTorException("Exception while starting node "
+ + nodeStarter.node.getNodeName(),
+ caughtException);
+ logger.throwing(this.getClass().getName(), "startNodes", ex);
+ throw ex;
+ }
+
+ // if node start did not succeed in the given time, fail
+ if (!nodeStarter.success) {
+ logger.log(Level.WARNING,
+ "Starting nodes was not successful in "
+ + maximumTimeToWaitInMillis / 1000
+ + " seconds.", networkName);
+
+ // log exiting and return false
+ logger.exiting(this.getClass().getName(), "startNodes", false);
+ return false;
+ }
+ }
+
+ // determine how long we took to start all nodes
+ final long after = System.currentTimeMillis();
+ logger.log(Level.FINE, "Starting nodes was successful and took "
+ + (after - before) / 1000 + " seconds.", networkName);
+
+ // log exiting and return true
+ logger.exiting(this.getClass().getName(), "startNodes", true);
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": networkName=\""
+ + networkName;
+ }
+
+ public String getNetworkName() {
+ return networkName;
+ }
+
+ public void writeConfigurations() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "writeConfigurations");
+
+ // write configurations for all nodes
+ for (final ProxyNode node : nodes.values()) {
+ node.writeConfiguration();
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "writeConfigurations");
+ }
+
+ public void addTemplateConfiguration(
+ final Class<? extends ProxyNode> nodeClass,
+ final String templateConfigurationString) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addTemplateConfiguration",
+ new Object[] { nodeClass, templateConfigurationString });
+
+ // check parameters
+ if (nodeClass == null || templateConfigurationString == null
+ || templateConfigurationString.length() < 1
+ || !templateConfigurationString.contains(" ")) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(),
+ "addTemplateConfiguration", e);
+ throw e;
+ }
+
+ // add template string to appropriate template configuration
+ if (nodeClass == ProxyNode.class) {
+ ProxyNodeImpl.templateConfiguration
+ .add(templateConfigurationString);
+ } else if (nodeClass == RouterNode.class) {
+ RouterNodeImpl.templateConfiguration
+ .add(templateConfigurationString);
+ } else if (nodeClass == DirectoryNode.class) {
+ DirectoryNodeImpl.templateConfiguration
+ .add(templateConfigurationString);
+ } else {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(),
+ "addTemplateConfiguration", e);
+ throw e;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "addTemplateConfiguration");
+ }
+
+ public List<String> getTemplateConfiguration(
+ final Class<? extends ProxyNode> nodeClass) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "getTemplateConfiguration",
+ nodeClass);
+
+ // check parameter
+ if (nodeClass == null) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(),
+ "getTemplateConfiguration", e);
+ throw e;
+ }
+
+ // obtain reference on appropriate template configuration
+ List<String> result = null;
+ if (nodeClass == ProxyNode.class) {
+ result = new ArrayList<String>(ProxyNodeImpl.templateConfiguration);
+ } else if (nodeClass == RouterNode.class) {
+ result =
+ new ArrayList<String>(RouterNodeImpl.templateConfiguration);
+ } else if (nodeClass == DirectoryNode.class) {
+ result =
+ new ArrayList<String>(
+ DirectoryNodeImpl.templateConfiguration);
+ } else {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(),
+ "getTemplateConfiguration", e);
+ throw e;
+ }
+
+ // log exiting and return result
+ logger.exiting(this.getClass().getName(), "getTemplateConfiguration",
+ result);
+ return result;
+ }
+
+ public void removeTemplateConfiguration(
+ final Class<? extends ProxyNode> nodeClass,
+ final String templateConfigurationKey) {
+
+ // log entering
+ logger.entering(this.getClass().getName(),
+ "removeTemplateConfiguration", new Object[] { nodeClass,
+ templateConfigurationKey });
+
+ // check parameters
+ if (nodeClass == null || templateConfigurationKey == null
+ || templateConfigurationKey.length() < 1) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(),
+ "removeTemplateConfiguration", e);
+ throw e;
+ }
+
+ // obtain reference on appropriate template configuration
+ List<String> templateConfig = null;
+ if (nodeClass == ProxyNode.class) {
+ templateConfig = ProxyNodeImpl.templateConfiguration;
+ } else if (nodeClass == RouterNode.class) {
+ templateConfig = RouterNodeImpl.templateConfiguration;
+ } else if (nodeClass == DirectoryNode.class) {
+ templateConfig = DirectoryNodeImpl.templateConfiguration;
+ } else {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(),
+ "removeTemplateConfiguration", e);
+ throw e;
+ }
+
+ // iterate over existing template configuration strings and remove all
+ // configuration strings that have the given configuration key
+ final List<String> configurationStringsToRemove =
+ new ArrayList<String>();
+ for (final String currentConfigurationString : templateConfig) {
+ final String currentConfigurationKey =
+ currentConfigurationString.substring(0,
+ currentConfigurationString.indexOf(" "));
+ if (currentConfigurationKey.equals(templateConfigurationKey)) {
+ configurationStringsToRemove.add(currentConfigurationString);
+ }
+ }
+ templateConfig.removeAll(configurationStringsToRemove);
+
+ // log exiting
+ logger
+ .exiting(this.getClass().getName(),
+ "removeTemplateConfiguration");
+ }
+
+ /**
+ * Returns the current port number and increments it afterwards.
+ *
+ * @return The current port number.
+ */
+ int getNextPortNumber() {
+ return portCounter++;
+ }
}
diff --git a/src/org/torproject/puppetor/impl/ProxyNodeImpl.java b/src/org/torproject/puppetor/impl/ProxyNodeImpl.java
index 5b65479..70201b8 100644
--- a/src/org/torproject/puppetor/impl/ProxyNodeImpl.java
+++ b/src/org/torproject/puppetor/impl/ProxyNodeImpl.java
@@ -34,702 +34,702 @@ import net.freehaven.tor.control.TorControlConnection;
*/
public class ProxyNodeImpl implements ProxyNode {
- /**
- * Executable file containing Tor.
- *
- * TODO make this configurable!
- */
- protected static final File torExecutable = new File("tor");
-
- /**
- * The <code>torrc</code> configuration file of this Tor node.
- */
- protected File configFile;
-
- /**
- * Collects all configuration strings for this node during the configuration
- * phase in the order they are added.
- */
- protected List<String> configuration;
-
- /**
- * Connection via Tor controller.
- */
- protected TorControlConnection conn;
-
- /**
- * Port on which the Tor node will be listening for us as its controller.
- */
- protected int controlPort;
-
- /**
- * Event manager to which all events concerning this node are notified.
- */
- private final EventManagerImpl eventManager;
-
- /**
- * Logger for this node which is called "node." plus the name of this node.
- */
- protected Logger logger;
-
- /**
- * Network to which this node belongs.
- */
- protected NetworkImpl network;
-
- /**
- * Name of this node that is used as part of the working directory, as
- * logger name of this node, and as event source.
- */
- protected String nodeName;
-
- /**
- * The state of this node.
- */
- protected NodeState nodeState = NodeState.CONFIGURING;
-
- /**
- * Port on which the Tor node will be listening for SOCKS connection
- * requests.
- */
- protected int socksPort;
-
- /**
- * The running Tor process that belongs to this node.
- */
- protected Process torProcess;
-
- /**
- * Directory in which all information concerning this node is stored.
- */
- protected File workingDir;
-
- /**
- * Returns this node's working directory.
- *
- * @return This node's working directory.
- */
- File getWorkingDir() {
- return workingDir;
- }
-
- /**
- * Creates a new <code>ProxyNodeImpl</code> and adds it to the given
- * <code>network</code>, but does not yet write its configuration to disk
- * or start the corresponding Tor process.
- *
- * @param network
- * Network configuration to which this node belongs.
- * @param nodeName
- * The name of the new node which may only consist of between 1
- * and 19 alpha-numeric characters.
- * @param controlPort
- * Port on which the Tor node will be listening for us as its
- * controller. May not be negative or greater than 65535.
- * @param socksPort
- * Port on which the Tor node will be listening for SOCKS
- * connection requests. May not be negative or greater than
- * 65535.
- * @throws IllegalArgumentException
- * If at least one of the parameters is <code>null</code> or
- * has an invalid value.
- */
- ProxyNodeImpl(final NetworkImpl network, final String nodeName,
- final int controlPort, final int socksPort) {
-
- // make sure that nodeName is a valid logger name
- if (nodeName == null || nodeName.length() < 1 || nodeName.length() > 19
- || !nodeName.matches("[a-zA-Z0-9]*")) {
- final String reason =
- "\"" + nodeName + "\" is not a valid node name!";
- final IllegalArgumentException e =
- new IllegalArgumentException(reason);
- throw e;
- }
-
- // create logger
- logger = Logger.getLogger(nodeName + "." + this.getClass().getName());
-
- logger.setLevel(Level.ALL);
-
- // log entering
- logger.entering(this.getClass().getName(), "ProxyNodeImpl",
- new Object[] { network, nodeName, controlPort, socksPort });
-
- // check remaining parameters
- if (network == null || controlPort < 0 || controlPort > 65535
- || socksPort < 0 || socksPort > 65535) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "ProxyNodeImpl", e);
- throw e;
- }
-
- // store parameter values
- this.network = network;
- this.nodeName = nodeName;
- this.controlPort = controlPort;
- this.socksPort = socksPort;
-
- // obtain reference on event manager from network
- eventManager = network.getEventManagerImpl();
-
- // create working directory
- workingDir =
- new File(this.network.getWorkingDirectory().getAbsolutePath()
- + File.separator + nodeName + File.separator);
- workingDir.mkdirs();
- logger.log(Level.FINE, "Created working directory \""
- + workingDir.getAbsolutePath() + "\"");
-
- // create reference on config file
- configFile =
- new File(workingDir.getAbsolutePath() + File.separator
- + "torrc");
-
- // initialize configuration
- configuration = new ArrayList<String>(templateConfiguration);
- configuration.add("ControlPort " + controlPort);
- configuration.add("SocksPort " + socksPort);
-
- // initialize state
- nodeState = NodeState.CONFIGURING;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "ProxyNodeImpl");
- }
-
- public void addConfiguration(final String configurationString) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addConfiguration",
- configurationString);
-
- // check parameter
- if (configurationString == null || configurationString.length() < 1
- || !configurationString.contains(" ")) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "addConfiguration", e);
- throw e;
- }
-
- // add configuration string
- configuration.add(configurationString);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "addConfiguration");
- }
-
- public void addConfigurations(final List<String> configurationStrings) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addConfigurations",
- configurationStrings);
-
- // check parameter
- if (configurationStrings == null) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "addConfigurations", e);
- throw e;
- }
-
- // add configuration strings one by one
- for (final String conf : configurationStrings) {
- addConfiguration(conf);
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "addConfigurations");
- }
-
- public void replaceConfiguration(final String configurationString) {
-
- // log entering
- logger.entering(this.getClass().getName(), "replaceConfiguration",
- configurationString);
-
- // check parameter
- if (configurationString == null || configurationString.length() < 1
- || !configurationString.contains(" ")) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "replaceConfiguration",
- e);
- throw e;
- }
-
- // extract configuration key
- final String configurationKey =
- configurationString.substring(0, configurationString
- .indexOf(" "));
-
- // iterate over existing configuration strings and replace the first
- // occurrence of configuration key with new configuration string
- final Iterator<String> it = configuration.listIterator();
- boolean replaced = false;
- for (int counter = 0; !replaced && it.hasNext(); counter++) {
- final String currentConfigurationString = it.next();
- final String currentConfigurationKey =
- currentConfigurationString.substring(0,
- currentConfigurationString.indexOf(" "));
- if (currentConfigurationKey.equals(configurationKey)) {
- configuration.set(counter, configurationString);
- replaced = true;
- }
- }
-
- // if no such configuration key was found, append the configuration
- // string
- if (!replaced) {
- configuration.add(configurationString);
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "replaceConfiguration");
- }
-
- public void removeConfiguration(final String configurationKey) {
-
- // log entering
- logger.entering(this.getClass().getName(), "deleteConfiguration",
- configurationKey);
-
- // check parameter
- if (configurationKey == null || configurationKey.length() < 1) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger
- .throwing(this.getClass().getName(), "deleteConfiguration",
- e);
- throw e;
- }
-
- // iterate over existing configuration strings and remove all
- // configuration strings that have the given configuration key
- final List<String> configurationStringsToRemove =
- new ArrayList<String>();
- for (final String currentConfigurationString : configuration) {
- final String currentConfigurationKey =
- currentConfigurationString.substring(0,
- currentConfigurationString.indexOf(" "));
- if (currentConfigurationKey.equals(configurationKey)) {
- configurationStringsToRemove.add(currentConfigurationString);
- }
- }
- configuration.removeAll(configurationStringsToRemove);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "deleteConfiguration");
- }
-
- public synchronized HiddenService addHiddenService(
- final String serviceName, final int servicePort,
- final int virtualPort) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addHiddenService",
- new Object[] { serviceName, servicePort, virtualPort });
-
- // create hidden service object; parameter checking is done in
- // constructor
- final HiddenService result =
- new HiddenServiceImpl(this, serviceName, servicePort,
- virtualPort);
-
- // add hidden service using Tor controller
- configuration.add("HiddenServiceDir " + workingDir.getAbsolutePath()
- + File.separator + serviceName + "\nHiddenServicePort "
- + virtualPort + " 127.0.0.1:" + servicePort);
-
- // log exiting and return hidden service object
- logger.exiting(this.getClass().getName(), "addHiddenService", result);
- return result;
- }
-
- public synchronized HiddenService addHiddenService(
- final String serviceName, final int servicePort) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addHiddenService",
- new Object[] { serviceName, servicePort });
-
- // invoke overloaded method
- final HiddenService result =
- this.addHiddenService(serviceName, servicePort, 80);
-
- // log exiting and return hidden service
- logger.exiting(this.getClass().getName(), "addHiddenService", result);
- return result;
- }
-
- public synchronized HiddenService addHiddenService(final String serviceName) {
-
- // log entering
- logger.entering(this.getClass().getName(), "addHiddenService",
- serviceName);
-
- // invoke overloaded method
- final HiddenService result =
- this.addHiddenService(serviceName, network.getNextPortNumber(),
- 80);
-
- // log exiting and return hidden service
- logger.exiting(this.getClass().getName(), "addHiddenService", result);
- return result;
- }
-
- public String getNodeName() {
- return nodeName;
- }
-
- public synchronized NodeState getNodeState() {
- return nodeState;
- }
-
- public synchronized void hup() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "hup");
-
- // check state
- if (nodeState != NodeState.RUNNING || conn == null) {
- final IllegalStateException e =
- new IllegalStateException(
- "Cannot hup a process when it's not running or there is "
- + "no connection to its control port!");
- logger.throwing(this.getClass().getName(), "hup", e);
- throw e;
- }
-
- // send HUP signal to Tor process
- try {
- conn.signal("HUP");
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not send the command HUP to the Tor process!",
- e);
- logger.throwing(this.getClass().getName(), "hup", ex);
- throw ex;
- }
- // log exiting
- logger.exiting(this.getClass().getName(), "hup");
- }
-
- public synchronized void shutdown() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "shutdown");
-
- // check state
- if (nodeState != NodeState.RUNNING) {
- final IllegalStateException e = new IllegalStateException();
- logger.throwing(this.getClass().getName(), "shutdown", e);
- throw e;
- }
-
- // we cannot simply kill the Tor process, because we have established a
- // controller connection to it which would interpret a closed socket as
- // failure and throw a RuntimeException
- try {
- conn.shutdownTor("SHUTDOWN");
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not send shutdown command to Tor process!",
- e);
- logger.throwing(this.getClass().getName(), "shutdown", ex);
- throw ex;
- }
-
- // change state
- nodeState = NodeState.SHUT_DOWN;
-
- // fire event
- eventManager.observeInternalEvent(System.currentTimeMillis(),
- getNodeName(), NodeEventType.NODE_STOPPED, "Node stopped.");
-
- // log exiting
- logger.exiting(this.getClass().getName(), "shutdown");
- }
-
- /**
- * Helper thread that waits for a given time for a given process to
- * potentially terminate in order to find out if there are problems. If
- * either the process terminates cleanly within this timeout, or does not
- * terminate, the exit value will be 0; otherwise it will contain the exit
- * code of the terminated process. This functionality is added, because it
- * is not provided by Process. XXX Some stuff in here looks still dodgy.
- * What happens if we get an InterruptedException in run and thus don't set
- * exitValue?-SH
- */
- private static class ProcessWaiter extends Thread {
-
- /** The process to wait for. */
- private final Process process;
-
- /** The exit value or 0 if the process is still running. */
- private final AtomicInteger exitValue;
-
- /**
- * Creates a new <code>ProcessWaiter</code> for process
- * <code>process</code>, but does not start it, yet.
- *
- * @param process
- * The process to wait for.
- */
- ProcessWaiter(final Process process) {
- this.process = process;
- exitValue = new AtomicInteger(0);
- }
-
- @Override
- public void run() {
- try {
- exitValue.set(process.waitFor());
- } catch (final InterruptedException e) {}
- }
-
- /**
- * Causes the current thread to wait until the process has terminated or
- * the <code>timeoutInMillis</code> has expired. This method returns
- * immediately if the subprocess has already terminated.
- *
- * @param timeoutInMillis
- * The maximum time to wait for the process to terminate.
- * @return The exit value of the terminated process or 0 if the process
- * is still running.
- */
- public int waitFor(final long timeoutInMillis) {
- try {
- sleep(timeoutInMillis);
- } catch (final InterruptedException e) {}
- interrupt();
- return exitValue.get();
- }
- }
-
- public synchronized boolean startNode(final long maximumTimeToWaitInMillis)
- throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "startNode",
- maximumTimeToWaitInMillis);
-
- // check state
- if (nodeState != NodeState.CONFIGURATION_WRITTEN) {
- final String reason =
- "Node is not in state "
- + "NodeState.CONFIGURATION_WRITTEN!";
- final IllegalStateException e = new IllegalStateException(reason);
- logger.throwing(this.getClass().getName(), "startNode", e);
- throw e;
- }
-
- // start process
- final ProcessBuilder processBuilder =
- new ProcessBuilder(torExecutable.getPath(), "-f", "torrc");
- processBuilder.directory(workingDir);
- processBuilder.redirectErrorStream(true);
- try {
- torProcess = processBuilder.start();
- logger.log(Level.FINE, "Started Tor process successfully!");
- } catch (final IOException e) {
- final String reason = "Could not start Tor process!";
- final PuppeTorException ex = new PuppeTorException(reason, e);
- logger.throwing(this.getClass().getName(), "startNode", ex);
- throw ex;
- }
-
- // start thread to parse output
- final BufferedReader br =
- new BufferedReader(new InputStreamReader(torProcess
- .getInputStream()));
- final Thread outputThread = new Thread() {
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- // read output from Tor to parse it
- String line = null;
- try {
- while ((line = br.readLine()) != null) {
- eventManager.observeUnparsedEvent(ProxyNodeImpl.this
- .getNodeName(), line);
- }
- } catch (IOException e) {
-
- // only print out a warning for this exception if this node
- // is running; otherwise, silently ignore it...
- if (getNodeState() == NodeState.RUNNING) {
- String reason =
- "IOException when reading output from Tor "
- + "process "
- + ProxyNodeImpl.this.getNodeName()
- + "!";
- logger.log(Level.WARNING, reason, e);
- }
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
- };
- outputThread.setDaemon(true);
- outputThread.setName(nodeName + " Output Parser");
- outputThread.start();
- logger.log(Level.FINE, "Started thread to parse output!");
-
- // add shutdown hook that kills the process on JVM exit
- final Process p = torProcess;
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- // destroy Tor process
- p.destroy();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
- });
- logger.log(Level.FINER,
- "Started shutdown hook that will destroy the Tor process on "
- + "JVM exit!");
-
- // wait to see if the process is started or exited immediately; wait for
- // one second to be sure that Tor terminates if there is an error,
- // especially if the computer is very busy and many nodes are created
- final ProcessWaiter waiter = new ProcessWaiter(torProcess);
- waiter.start();
- final int exitValue = waiter.waitFor(1000);
- if (exitValue != 0) {
- // Tor did not manage to start correctly
- logger.log(Level.WARNING, "Could not start Tor process! Tor "
- + "exited with exit value " + exitValue
- + "! Please go check the config options in " + configFile
- + " manually!");
-
- // log exiting
- logger.exiting(this.getClass().getName(), "startNode", false);
- return false;
- }
-
- // wait for Tor to open the control port
- logger.log(Level.FINER, "Waiting for Tor to open its control port...");
- if (!eventManager.waitForAnyOccurence(nodeName,
- NodeEventType.NODE_CONTROL_PORT_OPENED,
- maximumTimeToWaitInMillis)) {
-
- // Tor did not open its control port
- logger.log(Level.WARNING, "Tor node " + nodeName
- + " did not manage to open its control port within "
- + maximumTimeToWaitInMillis + " milliseconds!");
-
- // log exiting
- logger.exiting(this.getClass().getName(), "startNode", false);
- return false;
- }
- logger.log(Level.FINE,
- "Tor has successfully opened its control port and told us "
- + "about that!");
-
- // connect to the controller
- logger.log(Level.FINER, "Connecting to control port...");
- try {
- final Socket controlSocket =
- new java.net.Socket("127.0.0.1", controlPort);
- conn = TorControlConnection.getConnection(controlSocket);
- conn.authenticate(new byte[0]);
- } catch (final IOException e) {
- final String reason =
- "Could not connect to control port " + controlPort + "!";
- final PuppeTorException ex = new PuppeTorException(reason, e);
- logger.throwing(this.getClass().getName(), "startNode", ex);
- throw ex;
- }
- logger.log(Level.FINE, "Connected to control port successfully!");
-
- // set state to RUNNING
- nodeState = NodeState.RUNNING;
-
- // fire event
- eventManager.observeInternalEvent(System.currentTimeMillis(),
- getNodeName(), NodeEventType.NODE_STARTED, "Node started.");
-
- // log exiting and return with success
- logger.exiting(this.getClass().getName(), "startNode", true);
- return true;
- }
-
- @Override
- public String toString() {
- return this.getClass().getSimpleName() + ": nodeName=\"" + nodeName
- + "\", controlPort=" + controlPort + ", socksPort=" + socksPort;
- }
-
- public synchronized void writeConfiguration() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "writeConfiguration");
-
- // write config file
- try {
- final BufferedWriter bw =
- new BufferedWriter(new FileWriter(configFile));
- for (final String c : configuration) {
- bw.write(c + "\n");
- }
- bw.close();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not write configuration file!", e);
- logger.throwing(this.getClass().getName(),
- "writeConfigurationFile", ex);
- throw ex;
- }
-
- // change state, if necessary
- if (nodeState == NodeState.CONFIGURING) {
- nodeState = NodeState.CONFIGURATION_WRITTEN;
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "writeConfiguration");
- }
-
- public int getSocksPort() {
- return socksPort;
- }
-
- public int getControlPort() {
- return controlPort;
- }
-
- public List<String> getConfiguration() {
- return new ArrayList<String>(configuration);
- }
-
- /**
- * Template configuration of proxy nodes.
- */
- static List<String> templateConfiguration;
-
- static {
- templateConfiguration = new ArrayList<String>();
-
- templateConfiguration.add("DataDirectory .");
- templateConfiguration.add("SafeLogging 0");
- templateConfiguration.add("UseEntryGuards 0");
-
- templateConfiguration.add("Log info stdout");
- templateConfiguration.add("Log info file log");
-
- // TODO This is now contained in proposal 135.
- // templateConfiguration.add("EnforceDistinctSubnets 0");
- // templateConfiguration.add("ClientDNSRejectInternalAddresses 0");
- }
+ /**
+ * Executable file containing Tor.
+ *
+ * TODO make this configurable!
+ */
+ protected static final File torExecutable = new File("tor");
+
+ /**
+ * The <code>torrc</code> configuration file of this Tor node.
+ */
+ protected File configFile;
+
+ /**
+ * Collects all configuration strings for this node during the configuration
+ * phase in the order they are added.
+ */
+ protected List<String> configuration;
+
+ /**
+ * Connection via Tor controller.
+ */
+ protected TorControlConnection conn;
+
+ /**
+ * Port on which the Tor node will be listening for us as its controller.
+ */
+ protected int controlPort;
+
+ /**
+ * Event manager to which all events concerning this node are notified.
+ */
+ private final EventManagerImpl eventManager;
+
+ /**
+ * Logger for this node which is called "node." plus the name of this node.
+ */
+ protected Logger logger;
+
+ /**
+ * Network to which this node belongs.
+ */
+ protected NetworkImpl network;
+
+ /**
+ * Name of this node that is used as part of the working directory, as
+ * logger name of this node, and as event source.
+ */
+ protected String nodeName;
+
+ /**
+ * The state of this node.
+ */
+ protected NodeState nodeState = NodeState.CONFIGURING;
+
+ /**
+ * Port on which the Tor node will be listening for SOCKS connection
+ * requests.
+ */
+ protected int socksPort;
+
+ /**
+ * The running Tor process that belongs to this node.
+ */
+ protected Process torProcess;
+
+ /**
+ * Directory in which all information concerning this node is stored.
+ */
+ protected File workingDir;
+
+ /**
+ * Returns this node's working directory.
+ *
+ * @return This node's working directory.
+ */
+ File getWorkingDir() {
+ return workingDir;
+ }
+
+ /**
+ * Creates a new <code>ProxyNodeImpl</code> and adds it to the given
+ * <code>network</code>, but does not yet write its configuration to disk
+ * or start the corresponding Tor process.
+ *
+ * @param network
+ * Network configuration to which this node belongs.
+ * @param nodeName
+ * The name of the new node which may only consist of between 1
+ * and 19 alpha-numeric characters.
+ * @param controlPort
+ * Port on which the Tor node will be listening for us as its
+ * controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * Port on which the Tor node will be listening for SOCKS
+ * connection requests. May not be negative or greater than
+ * 65535.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
+ */
+ ProxyNodeImpl(final NetworkImpl network, final String nodeName,
+ final int controlPort, final int socksPort) {
+
+ // make sure that nodeName is a valid logger name
+ if (nodeName == null || nodeName.length() < 1 || nodeName.length() > 19
+ || !nodeName.matches("[a-zA-Z0-9]*")) {
+ final String reason =
+ "\"" + nodeName + "\" is not a valid node name!";
+ final IllegalArgumentException e =
+ new IllegalArgumentException(reason);
+ throw e;
+ }
+
+ // create logger
+ logger = Logger.getLogger(nodeName + "." + this.getClass().getName());
+
+ logger.setLevel(Level.ALL);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "ProxyNodeImpl",
+ new Object[] { network, nodeName, controlPort, socksPort });
+
+ // check remaining parameters
+ if (network == null || controlPort < 0 || controlPort > 65535
+ || socksPort < 0 || socksPort > 65535) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "ProxyNodeImpl", e);
+ throw e;
+ }
+
+ // store parameter values
+ this.network = network;
+ this.nodeName = nodeName;
+ this.controlPort = controlPort;
+ this.socksPort = socksPort;
+
+ // obtain reference on event manager from network
+ eventManager = network.getEventManagerImpl();
+
+ // create working directory
+ workingDir =
+ new File(this.network.getWorkingDirectory().getAbsolutePath()
+ + File.separator + nodeName + File.separator);
+ workingDir.mkdirs();
+ logger.log(Level.FINE, "Created working directory \""
+ + workingDir.getAbsolutePath() + "\"");
+
+ // create reference on config file
+ configFile =
+ new File(workingDir.getAbsolutePath() + File.separator
+ + "torrc");
+
+ // initialize configuration
+ configuration = new ArrayList<String>(templateConfiguration);
+ configuration.add("ControlPort " + controlPort);
+ configuration.add("SocksPort " + socksPort);
+
+ // initialize state
+ nodeState = NodeState.CONFIGURING;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "ProxyNodeImpl");
+ }
+
+ public void addConfiguration(final String configurationString) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addConfiguration",
+ configurationString);
+
+ // check parameter
+ if (configurationString == null || configurationString.length() < 1
+ || !configurationString.contains(" ")) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "addConfiguration", e);
+ throw e;
+ }
+
+ // add configuration string
+ configuration.add(configurationString);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "addConfiguration");
+ }
+
+ public void addConfigurations(final List<String> configurationStrings) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addConfigurations",
+ configurationStrings);
+
+ // check parameter
+ if (configurationStrings == null) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "addConfigurations", e);
+ throw e;
+ }
+
+ // add configuration strings one by one
+ for (final String conf : configurationStrings) {
+ addConfiguration(conf);
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "addConfigurations");
+ }
+
+ public void replaceConfiguration(final String configurationString) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "replaceConfiguration",
+ configurationString);
+
+ // check parameter
+ if (configurationString == null || configurationString.length() < 1
+ || !configurationString.contains(" ")) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "replaceConfiguration",
+ e);
+ throw e;
+ }
+
+ // extract configuration key
+ final String configurationKey =
+ configurationString.substring(0, configurationString
+ .indexOf(" "));
+
+ // iterate over existing configuration strings and replace the first
+ // occurrence of configuration key with new configuration string
+ final Iterator<String> it = configuration.listIterator();
+ boolean replaced = false;
+ for (int counter = 0; !replaced && it.hasNext(); counter++) {
+ final String currentConfigurationString = it.next();
+ final String currentConfigurationKey =
+ currentConfigurationString.substring(0,
+ currentConfigurationString.indexOf(" "));
+ if (currentConfigurationKey.equals(configurationKey)) {
+ configuration.set(counter, configurationString);
+ replaced = true;
+ }
+ }
+
+ // if no such configuration key was found, append the configuration
+ // string
+ if (!replaced) {
+ configuration.add(configurationString);
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "replaceConfiguration");
+ }
+
+ public void removeConfiguration(final String configurationKey) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "deleteConfiguration",
+ configurationKey);
+
+ // check parameter
+ if (configurationKey == null || configurationKey.length() < 1) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger
+ .throwing(this.getClass().getName(), "deleteConfiguration",
+ e);
+ throw e;
+ }
+
+ // iterate over existing configuration strings and remove all
+ // configuration strings that have the given configuration key
+ final List<String> configurationStringsToRemove =
+ new ArrayList<String>();
+ for (final String currentConfigurationString : configuration) {
+ final String currentConfigurationKey =
+ currentConfigurationString.substring(0,
+ currentConfigurationString.indexOf(" "));
+ if (currentConfigurationKey.equals(configurationKey)) {
+ configurationStringsToRemove.add(currentConfigurationString);
+ }
+ }
+ configuration.removeAll(configurationStringsToRemove);
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "deleteConfiguration");
+ }
+
+ public synchronized HiddenService addHiddenService(
+ final String serviceName, final int servicePort,
+ final int virtualPort) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addHiddenService",
+ new Object[] { serviceName, servicePort, virtualPort });
+
+ // create hidden service object; parameter checking is done in
+ // constructor
+ final HiddenService result =
+ new HiddenServiceImpl(this, serviceName, servicePort,
+ virtualPort);
+
+ // add hidden service using Tor controller
+ configuration.add("HiddenServiceDir " + workingDir.getAbsolutePath()
+ + File.separator + serviceName + "\nHiddenServicePort "
+ + virtualPort + " 127.0.0.1:" + servicePort);
+
+ // log exiting and return hidden service object
+ logger.exiting(this.getClass().getName(), "addHiddenService", result);
+ return result;
+ }
+
+ public synchronized HiddenService addHiddenService(
+ final String serviceName, final int servicePort) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addHiddenService",
+ new Object[] { serviceName, servicePort });
+
+ // invoke overloaded method
+ final HiddenService result =
+ this.addHiddenService(serviceName, servicePort, 80);
+
+ // log exiting and return hidden service
+ logger.exiting(this.getClass().getName(), "addHiddenService", result);
+ return result;
+ }
+
+ public synchronized HiddenService addHiddenService(final String serviceName) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "addHiddenService",
+ serviceName);
+
+ // invoke overloaded method
+ final HiddenService result =
+ this.addHiddenService(serviceName, network.getNextPortNumber(),
+ 80);
+
+ // log exiting and return hidden service
+ logger.exiting(this.getClass().getName(), "addHiddenService", result);
+ return result;
+ }
+
+ public String getNodeName() {
+ return nodeName;
+ }
+
+ public synchronized NodeState getNodeState() {
+ return nodeState;
+ }
+
+ public synchronized void hup() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "hup");
+
+ // check state
+ if (nodeState != NodeState.RUNNING || conn == null) {
+ final IllegalStateException e =
+ new IllegalStateException(
+ "Cannot hup a process when it's not running or there is "
+ + "no connection to its control port!");
+ logger.throwing(this.getClass().getName(), "hup", e);
+ throw e;
+ }
+
+ // send HUP signal to Tor process
+ try {
+ conn.signal("HUP");
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not send the command HUP to the Tor process!",
+ e);
+ logger.throwing(this.getClass().getName(), "hup", ex);
+ throw ex;
+ }
+ // log exiting
+ logger.exiting(this.getClass().getName(), "hup");
+ }
+
+ public synchronized void shutdown() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "shutdown");
+
+ // check state
+ if (nodeState != NodeState.RUNNING) {
+ final IllegalStateException e = new IllegalStateException();
+ logger.throwing(this.getClass().getName(), "shutdown", e);
+ throw e;
+ }
+
+ // we cannot simply kill the Tor process, because we have established a
+ // controller connection to it which would interpret a closed socket as
+ // failure and throw a RuntimeException
+ try {
+ conn.shutdownTor("SHUTDOWN");
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not send shutdown command to Tor process!",
+ e);
+ logger.throwing(this.getClass().getName(), "shutdown", ex);
+ throw ex;
+ }
+
+ // change state
+ nodeState = NodeState.SHUT_DOWN;
+
+ // fire event
+ eventManager.observeInternalEvent(System.currentTimeMillis(),
+ getNodeName(), NodeEventType.NODE_STOPPED, "Node stopped.");
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "shutdown");
+ }
+
+ /**
+ * Helper thread that waits for a given time for a given process to
+ * potentially terminate in order to find out if there are problems. If
+ * either the process terminates cleanly within this timeout, or does not
+ * terminate, the exit value will be 0; otherwise it will contain the exit
+ * code of the terminated process. This functionality is added, because it
+ * is not provided by Process. XXX Some stuff in here looks still dodgy.
+ * What happens if we get an InterruptedException in run and thus don't set
+ * exitValue?-SH
+ */
+ private static class ProcessWaiter extends Thread {
+
+ /** The process to wait for. */
+ private final Process process;
+
+ /** The exit value or 0 if the process is still running. */
+ private final AtomicInteger exitValue;
+
+ /**
+ * Creates a new <code>ProcessWaiter</code> for process
+ * <code>process</code>, but does not start it, yet.
+ *
+ * @param process
+ * The process to wait for.
+ */
+ ProcessWaiter(final Process process) {
+ this.process = process;
+ exitValue = new AtomicInteger(0);
+ }
+
+ @Override
+ public void run() {
+ try {
+ exitValue.set(process.waitFor());
+ } catch (final InterruptedException e) {}
+ }
+
+ /**
+ * Causes the current thread to wait until the process has terminated or
+ * the <code>timeoutInMillis</code> has expired. This method returns
+ * immediately if the subprocess has already terminated.
+ *
+ * @param timeoutInMillis
+ * The maximum time to wait for the process to terminate.
+ * @return The exit value of the terminated process or 0 if the process
+ * is still running.
+ */
+ public int waitFor(final long timeoutInMillis) {
+ try {
+ sleep(timeoutInMillis);
+ } catch (final InterruptedException e) {}
+ interrupt();
+ return exitValue.get();
+ }
+ }
+
+ public synchronized boolean startNode(final long maximumTimeToWaitInMillis)
+ throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "startNode",
+ maximumTimeToWaitInMillis);
+
+ // check state
+ if (nodeState != NodeState.CONFIGURATION_WRITTEN) {
+ final String reason =
+ "Node is not in state "
+ + "NodeState.CONFIGURATION_WRITTEN!";
+ final IllegalStateException e = new IllegalStateException(reason);
+ logger.throwing(this.getClass().getName(), "startNode", e);
+ throw e;
+ }
+
+ // start process
+ final ProcessBuilder processBuilder =
+ new ProcessBuilder(torExecutable.getPath(), "-f", "torrc");
+ processBuilder.directory(workingDir);
+ processBuilder.redirectErrorStream(true);
+ try {
+ torProcess = processBuilder.start();
+ logger.log(Level.FINE, "Started Tor process successfully!");
+ } catch (final IOException e) {
+ final String reason = "Could not start Tor process!";
+ final PuppeTorException ex = new PuppeTorException(reason, e);
+ logger.throwing(this.getClass().getName(), "startNode", ex);
+ throw ex;
+ }
+
+ // start thread to parse output
+ final BufferedReader br =
+ new BufferedReader(new InputStreamReader(torProcess
+ .getInputStream()));
+ final Thread outputThread = new Thread() {
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ // read output from Tor to parse it
+ String line = null;
+ try {
+ while ((line = br.readLine()) != null) {
+ eventManager.observeUnparsedEvent(ProxyNodeImpl.this
+ .getNodeName(), line);
+ }
+ } catch (IOException e) {
+
+ // only print out a warning for this exception if this node
+ // is running; otherwise, silently ignore it...
+ if (getNodeState() == NodeState.RUNNING) {
+ String reason =
+ "IOException when reading output from Tor "
+ + "process "
+ + ProxyNodeImpl.this.getNodeName()
+ + "!";
+ logger.log(Level.WARNING, reason, e);
+ }
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ };
+ outputThread.setDaemon(true);
+ outputThread.setName(nodeName + " Output Parser");
+ outputThread.start();
+ logger.log(Level.FINE, "Started thread to parse output!");
+
+ // add shutdown hook that kills the process on JVM exit
+ final Process p = torProcess;
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ // destroy Tor process
+ p.destroy();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ });
+ logger.log(Level.FINER,
+ "Started shutdown hook that will destroy the Tor process on "
+ + "JVM exit!");
+
+ // wait to see if the process is started or exited immediately; wait for
+ // one second to be sure that Tor terminates if there is an error,
+ // especially if the computer is very busy and many nodes are created
+ final ProcessWaiter waiter = new ProcessWaiter(torProcess);
+ waiter.start();
+ final int exitValue = waiter.waitFor(1000);
+ if (exitValue != 0) {
+ // Tor did not manage to start correctly
+ logger.log(Level.WARNING, "Could not start Tor process! Tor "
+ + "exited with exit value " + exitValue
+ + "! Please go check the config options in " + configFile
+ + " manually!");
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "startNode", false);
+ return false;
+ }
+
+ // wait for Tor to open the control port
+ logger.log(Level.FINER, "Waiting for Tor to open its control port...");
+ if (!eventManager.waitForAnyOccurence(nodeName,
+ NodeEventType.NODE_CONTROL_PORT_OPENED,
+ maximumTimeToWaitInMillis)) {
+
+ // Tor did not open its control port
+ logger.log(Level.WARNING, "Tor node " + nodeName
+ + " did not manage to open its control port within "
+ + maximumTimeToWaitInMillis + " milliseconds!");
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "startNode", false);
+ return false;
+ }
+ logger.log(Level.FINE,
+ "Tor has successfully opened its control port and told us "
+ + "about that!");
+
+ // connect to the controller
+ logger.log(Level.FINER, "Connecting to control port...");
+ try {
+ final Socket controlSocket =
+ new java.net.Socket("127.0.0.1", controlPort);
+ conn = TorControlConnection.getConnection(controlSocket);
+ conn.authenticate(new byte[0]);
+ } catch (final IOException e) {
+ final String reason =
+ "Could not connect to control port " + controlPort + "!";
+ final PuppeTorException ex = new PuppeTorException(reason, e);
+ logger.throwing(this.getClass().getName(), "startNode", ex);
+ throw ex;
+ }
+ logger.log(Level.FINE, "Connected to control port successfully!");
+
+ // set state to RUNNING
+ nodeState = NodeState.RUNNING;
+
+ // fire event
+ eventManager.observeInternalEvent(System.currentTimeMillis(),
+ getNodeName(), NodeEventType.NODE_STARTED, "Node started.");
+
+ // log exiting and return with success
+ logger.exiting(this.getClass().getName(), "startNode", true);
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": nodeName=\"" + nodeName
+ + "\", controlPort=" + controlPort + ", socksPort=" + socksPort;
+ }
+
+ public synchronized void writeConfiguration() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "writeConfiguration");
+
+ // write config file
+ try {
+ final BufferedWriter bw =
+ new BufferedWriter(new FileWriter(configFile));
+ for (final String c : configuration) {
+ bw.write(c + "\n");
+ }
+ bw.close();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not write configuration file!", e);
+ logger.throwing(this.getClass().getName(),
+ "writeConfigurationFile", ex);
+ throw ex;
+ }
+
+ // change state, if necessary
+ if (nodeState == NodeState.CONFIGURING) {
+ nodeState = NodeState.CONFIGURATION_WRITTEN;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "writeConfiguration");
+ }
+
+ public int getSocksPort() {
+ return socksPort;
+ }
+
+ public int getControlPort() {
+ return controlPort;
+ }
+
+ public List<String> getConfiguration() {
+ return new ArrayList<String>(configuration);
+ }
+
+ /**
+ * Template configuration of proxy nodes.
+ */
+ static List<String> templateConfiguration;
+
+ static {
+ templateConfiguration = new ArrayList<String>();
+
+ templateConfiguration.add("DataDirectory .");
+ templateConfiguration.add("SafeLogging 0");
+ templateConfiguration.add("UseEntryGuards 0");
+
+ templateConfiguration.add("Log info stdout");
+ templateConfiguration.add("Log info file log");
+
+ // TODO This is now contained in proposal 135.
+ // templateConfiguration.add("EnforceDistinctSubnets 0");
+ // templateConfiguration.add("ClientDNSRejectInternalAddresses 0");
+ }
}
diff --git a/src/org/torproject/puppetor/impl/RouterNodeImpl.java b/src/org/torproject/puppetor/impl/RouterNodeImpl.java
index d291452..7320e6a 100644
--- a/src/org/torproject/puppetor/impl/RouterNodeImpl.java
+++ b/src/org/torproject/puppetor/impl/RouterNodeImpl.java
@@ -27,377 +27,377 @@ import org.torproject.puppetor.RouterNode;
*/
public class RouterNodeImpl extends ProxyNodeImpl implements RouterNode {
- /**
- * Internal thread class that is used to determine fingerprints in parallel,
- * which can take a few seconds.
- */
- private class FingerprintThread extends Thread {
-
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- // create file reference for temporary config file
- final File tempConfigFile =
- new File(workingDir.getAbsolutePath() + File.separator
- + "torrc.tmp");
-
- // compose a modified config file, including a DirServer option with
- // false fingerprint; this is necessary, because otherwise Tor
- // would not accept that this router node might have a private IP
- // address, but connects to the public directory servers
- final List<String> copyOfConfig =
- new ArrayList<String>(configuration);
- final String fakeDirServerString =
- "DirServer "
- + nodeName
- + " 127.0.0.1:"
- + dirPort
- + " 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000";
- copyOfConfig.add(fakeDirServerString);
-
- // write config file
- try {
- final BufferedWriter bw =
- new BufferedWriter(new FileWriter(tempConfigFile));
- for (final String c : copyOfConfig) {
- bw.write(c + "\n");
- }
- bw.close();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not write configuration file!", e);
- logger.log(Level.WARNING, "Could not start Tor process!", ex);
- setCaughtException(ex);
- return;
- }
-
- // start process with option --list-fingerprint
- final ProcessBuilder processBuilder =
- new ProcessBuilder(torExecutable.getPath(),
- "--list-fingerprint", "-f", "torrc.tmp");
- processBuilder.directory(workingDir);
- processBuilder.redirectErrorStream(true);
- Process tmpProcess = null;
- try {
- tmpProcess = processBuilder.start();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not start Tor process temporarily with "
- + "--list-fingerprint option!", e);
- logger.log(Level.WARNING, "Could not start Tor process!", ex);
- setCaughtException(ex);
- return;
- }
-
- // wait for process to terminate
- int exitValue = 0;
- try {
- exitValue = tmpProcess.waitFor();
- } catch (final InterruptedException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Interrupted while waiting for Tor process to exit!",
- e);
- logger.log(Level.WARNING,
- "Temporary Tor process was interrupted!", ex);
- setCaughtException(ex);
- return;
- }
-
- if (exitValue != 0) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not start Tor process temporarily with "
- + "--list-fingerprint option! Tor exited with "
- + "exit value "
- + exitValue
- + "! Please go check the config options in "
- + tempConfigFile + " manually!");
- logger.log(Level.WARNING, "Could not start Tor process!", ex);
- setCaughtException(ex);
- return;
- }
-
- // read fingerprint from file
- final File fingerprintFile =
- new File(workingDir.getAbsolutePath() + File.separator
- + "fingerprint");
- try {
- final BufferedReader br2 =
- new BufferedReader(new FileReader(fingerprintFile));
- setFingerprint(br2.readLine());
- br2.close();
- } catch (final IOException e) {
- final PuppeTorException ex =
- new PuppeTorException(
- "Could not read fingerprint from file!", e);
- logger.log(Level.WARNING, "Could not read fingerprint file!",
- ex);
- setCaughtException(ex);
- return;
- }
-
- // delete temporary config file
- tempConfigFile.delete();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
- }
-
- /**
- * Invoked by the fingerprint thread: sets the determined fingerprint string
- *
- * @param fingerprint
- * The determined fingerprint string.
- */
- private synchronized void setFingerprint(final String fingerprint) {
-
- // log entering
- logger.entering(this.getClass().getName(), "setFingerprint",
- fingerprint);
-
- // remember fingerprint and notify all waiting threads
- this.fingerprint = fingerprint;
- notifyAll();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "setFingerprint");
- }
-
- /**
- * Invoked by the fingerprint thread: sets the exception that occurred when
- * trying to determine the fingerprint.
- *
- * @param caughtException
- * The exception that occurred when trying to determine the
- * fingerprint.
- */
- protected synchronized void setCaughtException(
- final PuppeTorException caughtException) {
-
- // log entering
- logger.entering(this.getClass().getName(), "setCaughtException",
- caughtException);
-
- // remember caught exception and notify all waiting threads
- this.caughtException = caughtException;
- notifyAll();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "setCaughtException");
- }
-
- /**
- * Port on which the Tor node will be listening for directory requests from
- * other Tor nodes.
- */
- protected int dirPort;
-
- /**
- * The IP v4 address on which the node will listen in dotted decimal
- * notation.
- */
- protected String serverIpAddress;
-
- /**
- * The fingerprint of this node that is determined as hash value of its
- * onion key. It is initialized with <code>null</code> and set by the
- * fingerprint thread as soon as it is determined.
- */
- private String fingerprint;
-
- /**
- * The exception that was caught when determining the fingerprint of this
- * node, if any.
- */
- protected PuppeTorException caughtException;
-
- /**
- * The pattern for valid IP v4 addresses in dotted decimal notation.
- */
- private static final Pattern validIpAddressPattern =
- Pattern
- .compile("([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
- + "(\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){1,3}");
-
- /**
- * Port on which the Tor node will be listening for onion requests by other
- * Tor nodes.
- */
- protected int orPort;
-
- /**
- * Creates a new <code>RouterNodeImpl</code> and adds it to the given
- * <code>network</code>, but does not yet write its configuration to disk
- * or start the corresponding Tor process.
- *
- * @param network
- * Network configuration to which this node belongs.
- * @param nodeName
- * The name of the new node which may only consist of between 1
- * and 19 alpha-numeric characters.
- * @param controlPort
- * Port on which the Tor node will be listening for us as its
- * controller. May not be negative or greater than 65535.
- * @param socksPort
- * Port on which the Tor node will be listening for SOCKS
- * connection requests. May not be negative or greater than
- * 65535.
- * @param orPort
- * Port on which the Tor node will be listening for onion
- * requests by other Tor nodes. May not be negative or greater
- * than 65535.
- * @param dirPort
- * Port on which the Tor node will be listening for directory
- * requests from other Tor nodes. May not be negative or greater
- * than 65535.
- * @param serverIpAddress
- * The IP address on which the node will listen. Must be a valid
- * IP v4 address in dotted decimal notation. May not be
- * <code>null</code>.
- * @throws IllegalArgumentException
- * If at least one of the parameters is <code>null</code> or
- * has an invalid value.
- */
- RouterNodeImpl(final NetworkImpl network, final String nodeName,
- final int controlPort, final int socksPort, final int orPort,
- final int dirPort, final String serverIpAddress) {
-
- // create superclass instance; parameter checking is done in super
- // constructor
- super(network, nodeName, controlPort, socksPort);
-
- // log entering
- logger.entering(this.getClass().getName(), "RouterNodeImpl",
- new Object[] { network, nodeName, controlPort, socksPort,
- orPort, dirPort, serverIpAddress });
-
- // check parameters
- if (orPort < 0 || orPort > 65535 || dirPort < 0 || dirPort > 65535
- || serverIpAddress == null
- || !validIpAddressPattern.matcher(serverIpAddress).matches()) {
- final IllegalArgumentException e =
- new IllegalArgumentException("nodeName=" + nodeName
- + ", controlPort=" + controlPort + ", socksPort="
- + socksPort + ", orPort=" + orPort + ", dirPort="
- + dirPort + ", serverIpAddress='" + serverIpAddress
- + "'");
- logger.throwing(this.getClass().getName(), "RouterNodeImpl", e);
- throw e;
- }
-
- // remember parameters
- this.orPort = orPort;
- this.dirPort = dirPort;
- this.serverIpAddress = serverIpAddress;
-
- // extend configuration by template configuration of router nodes
- configuration.addAll(templateConfiguration);
-
- // add further configuration to make this node a router node
- configuration.add("ORPort " + orPort);
- configuration.add("Nickname " + nodeName);
-
- // all routers mirror the directory
- configuration.add("DirPort " + dirPort);
-
- // the address of this node should be manually specified and not guessed
- // by Tor
- configuration.add("Address " + serverIpAddress);
-
- // the OR port may only be contacted locally
- configuration.add("ORListenAddress " + serverIpAddress);
-
- // offer directory only locally (either by being an authority, or by
- // mirroring it)
- configuration.add("DirListenAddress " + serverIpAddress);
-
- // start a thread to determine the node's fingerprint in the background
- determineFingerprint();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "RouterNodeImpl");
- }
-
- public synchronized String getFingerprint() throws PuppeTorException {
-
- // log entering
- logger.entering(this.getClass().getName(), "getFingerprint");
-
- // wait until either the fingerprint has been determined or an exception
- // was caught
- while (fingerprint == null && caughtException == null) {
- try {
- wait();
- } catch (final InterruptedException e) {
- // do nothing
- }
- }
-
- if (caughtException != null) {
- logger.throwing(this.getClass().getName(), "getFingerprint",
- caughtException);
- throw caughtException;
- }
-
- // log exiting
- logger
- .exiting(this.getClass().getName(), "getFingerprint",
- fingerprint);
- return fingerprint;
- }
-
- @Override
- public String toString() {
- return super.toString() + ", orPort=" + orPort + ", dirPort=" + dirPort;
- }
-
- public int getDirPort() {
- return dirPort;
- }
-
- public int getOrPort() {
- return orPort;
- }
-
- /**
- * Determines the fingerprint of this node by starting a background thread
- * that performs this operation.
- */
- protected synchronized void determineFingerprint() {
-
- // log entering
- logger.entering(this.getClass().getName(), "determineFingerprint");
-
- // start a thread to determine this node's fingerprint
- final FingerprintThread fingerprintThread = new FingerprintThread();
- fingerprintThread.setName(nodeName + " Fingerprint Resolver");
- fingerprintThread.start();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "determineFingerprint");
- }
-
- /**
- * Template configuration of router nodes.
- */
- static List<String> templateConfiguration;
-
- static {
- templateConfiguration = new ArrayList<String>();
-
- templateConfiguration.add("ContactInfo wont@xxxxxxxxx");
- templateConfiguration.add("HidServDirectoryV2 1");
-
- // TODO This is now contained in proposal 135.
- // templateConfiguration.add("ExitPolicyRejectPrivate 0");
- // templateConfiguration.add("AssumeReachable 1");
- // templateConfiguration.add("ServerDNSAllowBrokenResolvConf 1");
- }
+ /**
+ * Internal thread class that is used to determine fingerprints in parallel,
+ * which can take a few seconds.
+ */
+ private class FingerprintThread extends Thread {
+
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ // create file reference for temporary config file
+ final File tempConfigFile =
+ new File(workingDir.getAbsolutePath() + File.separator
+ + "torrc.tmp");
+
+ // compose a modified config file, including a DirServer option with
+ // false fingerprint; this is necessary, because otherwise Tor
+ // would not accept that this router node might have a private IP
+ // address, but connects to the public directory servers
+ final List<String> copyOfConfig =
+ new ArrayList<String>(configuration);
+ final String fakeDirServerString =
+ "DirServer "
+ + nodeName
+ + " 127.0.0.1:"
+ + dirPort
+ + " 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000";
+ copyOfConfig.add(fakeDirServerString);
+
+ // write config file
+ try {
+ final BufferedWriter bw =
+ new BufferedWriter(new FileWriter(tempConfigFile));
+ for (final String c : copyOfConfig) {
+ bw.write(c + "\n");
+ }
+ bw.close();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not write configuration file!", e);
+ logger.log(Level.WARNING, "Could not start Tor process!", ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ // start process with option --list-fingerprint
+ final ProcessBuilder processBuilder =
+ new ProcessBuilder(torExecutable.getPath(),
+ "--list-fingerprint", "-f", "torrc.tmp");
+ processBuilder.directory(workingDir);
+ processBuilder.redirectErrorStream(true);
+ Process tmpProcess = null;
+ try {
+ tmpProcess = processBuilder.start();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not start Tor process temporarily with "
+ + "--list-fingerprint option!", e);
+ logger.log(Level.WARNING, "Could not start Tor process!", ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ // wait for process to terminate
+ int exitValue = 0;
+ try {
+ exitValue = tmpProcess.waitFor();
+ } catch (final InterruptedException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Interrupted while waiting for Tor process to exit!",
+ e);
+ logger.log(Level.WARNING,
+ "Temporary Tor process was interrupted!", ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ if (exitValue != 0) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not start Tor process temporarily with "
+ + "--list-fingerprint option! Tor exited with "
+ + "exit value "
+ + exitValue
+ + "! Please go check the config options in "
+ + tempConfigFile + " manually!");
+ logger.log(Level.WARNING, "Could not start Tor process!", ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ // read fingerprint from file
+ final File fingerprintFile =
+ new File(workingDir.getAbsolutePath() + File.separator
+ + "fingerprint");
+ try {
+ final BufferedReader br2 =
+ new BufferedReader(new FileReader(fingerprintFile));
+ setFingerprint(br2.readLine());
+ br2.close();
+ } catch (final IOException e) {
+ final PuppeTorException ex =
+ new PuppeTorException(
+ "Could not read fingerprint from file!", e);
+ logger.log(Level.WARNING, "Could not read fingerprint file!",
+ ex);
+ setCaughtException(ex);
+ return;
+ }
+
+ // delete temporary config file
+ tempConfigFile.delete();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ }
+
+ /**
+ * Invoked by the fingerprint thread: sets the determined fingerprint string
+ *
+ * @param fingerprint
+ * The determined fingerprint string.
+ */
+ private synchronized void setFingerprint(final String fingerprint) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "setFingerprint",
+ fingerprint);
+
+ // remember fingerprint and notify all waiting threads
+ this.fingerprint = fingerprint;
+ notifyAll();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "setFingerprint");
+ }
+
+ /**
+ * Invoked by the fingerprint thread: sets the exception that occurred when
+ * trying to determine the fingerprint.
+ *
+ * @param caughtException
+ * The exception that occurred when trying to determine the
+ * fingerprint.
+ */
+ protected synchronized void setCaughtException(
+ final PuppeTorException caughtException) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "setCaughtException",
+ caughtException);
+
+ // remember caught exception and notify all waiting threads
+ this.caughtException = caughtException;
+ notifyAll();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "setCaughtException");
+ }
+
+ /**
+ * Port on which the Tor node will be listening for directory requests from
+ * other Tor nodes.
+ */
+ protected int dirPort;
+
+ /**
+ * The IP v4 address on which the node will listen in dotted decimal
+ * notation.
+ */
+ protected String serverIpAddress;
+
+ /**
+ * The fingerprint of this node that is determined as hash value of its
+ * onion key. It is initialized with <code>null</code> and set by the
+ * fingerprint thread as soon as it is determined.
+ */
+ private String fingerprint;
+
+ /**
+ * The exception that was caught when determining the fingerprint of this
+ * node, if any.
+ */
+ protected PuppeTorException caughtException;
+
+ /**
+ * The pattern for valid IP v4 addresses in dotted decimal notation.
+ */
+ private static final Pattern validIpAddressPattern =
+ Pattern
+ .compile("([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
+ + "(\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){1,3}");
+
+ /**
+ * Port on which the Tor node will be listening for onion requests by other
+ * Tor nodes.
+ */
+ protected int orPort;
+
+ /**
+ * Creates a new <code>RouterNodeImpl</code> and adds it to the given
+ * <code>network</code>, but does not yet write its configuration to disk
+ * or start the corresponding Tor process.
+ *
+ * @param network
+ * Network configuration to which this node belongs.
+ * @param nodeName
+ * The name of the new node which may only consist of between 1
+ * and 19 alpha-numeric characters.
+ * @param controlPort
+ * Port on which the Tor node will be listening for us as its
+ * controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * Port on which the Tor node will be listening for SOCKS
+ * connection requests. May not be negative or greater than
+ * 65535.
+ * @param orPort
+ * Port on which the Tor node will be listening for onion
+ * requests by other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @param dirPort
+ * Port on which the Tor node will be listening for directory
+ * requests from other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @param serverIpAddress
+ * The IP address on which the node will listen. Must be a valid
+ * IP v4 address in dotted decimal notation. May not be
+ * <code>null</code>.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
+ */
+ RouterNodeImpl(final NetworkImpl network, final String nodeName,
+ final int controlPort, final int socksPort, final int orPort,
+ final int dirPort, final String serverIpAddress) {
+
+ // create superclass instance; parameter checking is done in super
+ // constructor
+ super(network, nodeName, controlPort, socksPort);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "RouterNodeImpl",
+ new Object[] { network, nodeName, controlPort, socksPort,
+ orPort, dirPort, serverIpAddress });
+
+ // check parameters
+ if (orPort < 0 || orPort > 65535 || dirPort < 0 || dirPort > 65535
+ || serverIpAddress == null
+ || !validIpAddressPattern.matcher(serverIpAddress).matches()) {
+ final IllegalArgumentException e =
+ new IllegalArgumentException("nodeName=" + nodeName
+ + ", controlPort=" + controlPort + ", socksPort="
+ + socksPort + ", orPort=" + orPort + ", dirPort="
+ + dirPort + ", serverIpAddress='" + serverIpAddress
+ + "'");
+ logger.throwing(this.getClass().getName(), "RouterNodeImpl", e);
+ throw e;
+ }
+
+ // remember parameters
+ this.orPort = orPort;
+ this.dirPort = dirPort;
+ this.serverIpAddress = serverIpAddress;
+
+ // extend configuration by template configuration of router nodes
+ configuration.addAll(templateConfiguration);
+
+ // add further configuration to make this node a router node
+ configuration.add("ORPort " + orPort);
+ configuration.add("Nickname " + nodeName);
+
+ // all routers mirror the directory
+ configuration.add("DirPort " + dirPort);
+
+ // the address of this node should be manually specified and not guessed
+ // by Tor
+ configuration.add("Address " + serverIpAddress);
+
+ // the OR port may only be contacted locally
+ configuration.add("ORListenAddress " + serverIpAddress);
+
+ // offer directory only locally (either by being an authority, or by
+ // mirroring it)
+ configuration.add("DirListenAddress " + serverIpAddress);
+
+ // start a thread to determine the node's fingerprint in the background
+ determineFingerprint();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "RouterNodeImpl");
+ }
+
+ public synchronized String getFingerprint() throws PuppeTorException {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "getFingerprint");
+
+ // wait until either the fingerprint has been determined or an exception
+ // was caught
+ while (fingerprint == null && caughtException == null) {
+ try {
+ wait();
+ } catch (final InterruptedException e) {
+ // do nothing
+ }
+ }
+
+ if (caughtException != null) {
+ logger.throwing(this.getClass().getName(), "getFingerprint",
+ caughtException);
+ throw caughtException;
+ }
+
+ // log exiting
+ logger
+ .exiting(this.getClass().getName(), "getFingerprint",
+ fingerprint);
+ return fingerprint;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ", orPort=" + orPort + ", dirPort=" + dirPort;
+ }
+
+ public int getDirPort() {
+ return dirPort;
+ }
+
+ public int getOrPort() {
+ return orPort;
+ }
+
+ /**
+ * Determines the fingerprint of this node by starting a background thread
+ * that performs this operation.
+ */
+ protected synchronized void determineFingerprint() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "determineFingerprint");
+
+ // start a thread to determine this node's fingerprint
+ final FingerprintThread fingerprintThread = new FingerprintThread();
+ fingerprintThread.setName(nodeName + " Fingerprint Resolver");
+ fingerprintThread.start();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "determineFingerprint");
+ }
+
+ /**
+ * Template configuration of router nodes.
+ */
+ static List<String> templateConfiguration;
+
+ static {
+ templateConfiguration = new ArrayList<String>();
+
+ templateConfiguration.add("ContactInfo wont@xxxxxxxxx");
+ templateConfiguration.add("HidServDirectoryV2 1");
+
+ // TODO This is now contained in proposal 135.
+ // templateConfiguration.add("ExitPolicyRejectPrivate 0");
+ // templateConfiguration.add("AssumeReachable 1");
+ // templateConfiguration.add("ServerDNSAllowBrokenResolvConf 1");
+ }
}
diff --git a/src/org/torproject/puppetor/impl/ServerApplicationImpl.java b/src/org/torproject/puppetor/impl/ServerApplicationImpl.java
index 95e1536..c855ea5 100644
--- a/src/org/torproject/puppetor/impl/ServerApplicationImpl.java
+++ b/src/org/torproject/puppetor/impl/ServerApplicationImpl.java
@@ -25,328 +25,328 @@ import org.torproject.puppetor.ServerEventType;
*/
public class ServerApplicationImpl implements ServerApplication {
- /**
- * Internal thread class that is used to process an incoming request.
- */
- private class HandlerThread extends Thread {
-
- /**
- * Accepted socket on which the request came in.
- */
- private Socket handleSocket = null;
-
- /**
- * Creates a new thread to handle the request coming in on
- * <code>handleSocket</code>, but does not start handling it.
- *
- * @param handleSocket
- * Accepted socket on which the request came in.
- */
- public HandlerThread(final Socket handleSocket) {
-
- // log entering
- logger.entering(this.getClass().getName(), "HandlerThread",
- handleSocket);
-
- // remember parameter
- this.handleSocket = handleSocket;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "HandlerThread");
- }
-
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- try {
-
- // wait for request (don't mind the content)
- final BufferedReader in =
- new BufferedReader(new InputStreamReader(handleSocket
- .getInputStream()));
- in.read();
-
- // send event to event manager
- eventManager.observeInternalEvent(System.currentTimeMillis(),
- getServerApplicationName(),
- ServerEventType.SERVER_RECEIVING_REQUEST_SENDING_REPLY,
- "Receiving request.");
-
- // write response
- final PrintStream out =
- new PrintStream(handleSocket.getOutputStream());
- out.print("HTTP/1.0 200 OK\r\n");
-
- } catch (final IOException e) {
- logger.log(Level.SEVERE,
- "I/O exception while handling incoming request!");
- // we can't do more, because nobody takes notice of this thread.
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- return;
- // TODO do we need more?
- }
-
- // close socket
- try {
- handleSocket.close();
- } catch (final IOException e) {
- logger
- .log(Level.WARNING,
- "I/O exception while closing socket!");
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- return;
- }
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
- }
-
- /**
- * Internal thread class that is used to listen for requests.
- */
- private class ListenThread extends Thread {
-
- /**
- * Flag to remember whether this thread listens for requests at the
- * moment (<code>true</code>), or has been stopped (<code>false</code>).
- */
- private boolean connected;
-
- /**
- * Creates a new thread to listen for requests, but does not start
- * listening, yet.
- */
- ListenThread() {
-
- // log entering
- logger.entering(this.getClass().getName(), "ListenThread");
-
- // start connected
- connected = true;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "ListenThread");
- }
-
- @Override
- public void run() {
-
- // log entering
- logger.entering(this.getClass().getName(), "run");
-
- try {
-
- // create server socket
- ServerSocket serverSocket = null;
- try {
- serverSocket = new ServerSocket(serverPort);
- } catch (final IOException ioe) {
- logger.log(Level.SEVERE,
- "Can't open server socket on port " + serverPort
- + "!");
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- return;
- }
-
- // as long as we are connected, accept incoming requests
- logger.log(Level.FINE, "Listening on port " + serverPort
- + "...");
- while (connected) {
- Socket incomingConnection = null;
- try {
- incomingConnection = serverSocket.accept();
- } catch (final Exception e) {
- logger
- .log(
- Level.SEVERE,
- "Exception while accepting socket requests! Stopping listening!",
- e);
- break;
- }
- new HandlerThread(incomingConnection).start();
- }
-
- } catch (final Exception e) {
-
- // log that we have been interrupted
- logger.log(Level.WARNING, "Server has been interrupted!", e);
- }
-
- // mark as disconnected
- connected = false;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
- }
-
- /**
- * Stops listening on server socket.
- */
- public void stopListening() {
-
- // log entering
- logger.entering(this.getClass().getName(), "stopListening");
-
- // change connected state to false and interrupt thread
- connected = false;
- interrupt();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "stopListening");
- }
- }
-
- /**
- * Event manager that handles all events concerning this server application.
- */
- private final EventManagerImpl eventManager;
-
- /**
- * Logger for this server which is called "server." plus the name of this
- * server application.
- */
- private final Logger logger;
-
- /**
- * Name of this server application that is used as logger name of this node.
- */
- private final String serverApplicationName;
-
- /**
- * Port on which this server will listen for incoming requests.
- */
- private final int serverPort;
-
- /**
- * Thread that listens for requests in the background.
- */
- private Thread serverThread;
-
- /**
- * Creates a new HTTP server application within this JVM, but does not yet
- * listen for incoming requests.
- *
- * @param network
- * Network to which this HTTP server belongs; at the moment this
- * is only used to determine the event manager instance.
- * @param serverApplicationName
- * Name of this server that is used as part of the logger name.
- * @param serverPort
- * Port on which this server will listen for incoming requests.
- * @throws IllegalArgumentException
- * If at least one of the parameters is <code>null</code> or
- * has an invalid value.
- */
- ServerApplicationImpl(final NetworkImpl network,
- final String serverApplicationName, final int serverPort) {
-
- // check if serverApplicationName can be used as logger name
- if (serverApplicationName == null
- || serverApplicationName.length() == 0) {
- throw new IllegalArgumentException(
- "Invalid serverApplicationName: " + serverApplicationName);
- }
-
- // create logger
- logger = Logger.getLogger("server." + serverApplicationName);
-
- // log entering
- logger.entering(this.getClass().getName(), "ServerApplicationImpl",
- new Object[] { network, serverApplicationName, serverPort });
-
- // check parameters
- if (network == null || serverPort < 0 || serverPort > 65535) {
- final IllegalArgumentException e = new IllegalArgumentException();
- logger.throwing(this.getClass().getName(), "ServerApplicationImpl",
- e);
- throw e;
- }
-
- // remember parameters
- this.serverApplicationName = serverApplicationName;
- this.serverPort = serverPort;
-
- // obtain reference on event manager
- eventManager = network.getEventManagerImpl();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "ServerApplicationImpl");
- }
-
- public synchronized void startListening() {
-
- // log entering
- logger.entering(this.getClass().getName(), "listen");
-
- // check if we are already listening
- if (serverThread != null) {
- final IllegalStateException e =
- new IllegalStateException("We are already listening!");
- logger.throwing(this.getClass().getName(), "listen", e);
- throw e;
- }
-
- // create a thread that listens in the background
- serverThread = new ListenThread();
- serverThread.setName("Reply Thread");
- serverThread.setDaemon(true);
- serverThread.start();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "listen");
- }
-
- public synchronized void stopListening() {
-
- // log entering
- logger.entering(this.getClass().getName(), "stopListening");
-
- // check if we are listening
- if (serverThread == null) {
- final IllegalStateException e =
- new IllegalStateException("We are not listening!");
- logger.throwing(this.getClass().getName(), "stopListening", e);
- throw e;
- }
-
- // log this event
- logger.log(Level.FINE, "Shutting down server");
-
- // interrupt thread
- serverThread.interrupt();
-
- // unset listening thread
- serverThread = null;
-
- // log exiting
- logger.exiting(this.getClass().getName(), "stopListening");
- }
-
- public synchronized boolean isListening() {
- return serverThread != null;
- }
-
- @Override
- public String toString() {
- return this.getClass().getSimpleName() + ": serverApplicationName=\""
- + serverApplicationName + "\", serverPort=" + serverPort;
- }
-
- public String getServerApplicationName() {
- return serverApplicationName;
- }
-
- public int getServerPort() {
- return serverPort;
- }
+ /**
+ * Internal thread class that is used to process an incoming request.
+ */
+ private class HandlerThread extends Thread {
+
+ /**
+ * Accepted socket on which the request came in.
+ */
+ private Socket handleSocket = null;
+
+ /**
+ * Creates a new thread to handle the request coming in on
+ * <code>handleSocket</code>, but does not start handling it.
+ *
+ * @param handleSocket
+ * Accepted socket on which the request came in.
+ */
+ public HandlerThread(final Socket handleSocket) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "HandlerThread",
+ handleSocket);
+
+ // remember parameter
+ this.handleSocket = handleSocket;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "HandlerThread");
+ }
+
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ try {
+
+ // wait for request (don't mind the content)
+ final BufferedReader in =
+ new BufferedReader(new InputStreamReader(handleSocket
+ .getInputStream()));
+ in.read();
+
+ // send event to event manager
+ eventManager.observeInternalEvent(System.currentTimeMillis(),
+ getServerApplicationName(),
+ ServerEventType.SERVER_RECEIVING_REQUEST_SENDING_REPLY,
+ "Receiving request.");
+
+ // write response
+ final PrintStream out =
+ new PrintStream(handleSocket.getOutputStream());
+ out.print("HTTP/1.0 200 OK\r\n");
+
+ } catch (final IOException e) {
+ logger.log(Level.SEVERE,
+ "I/O exception while handling incoming request!");
+ // we can't do more, because nobody takes notice of this thread.
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ return;
+ // TODO do we need more?
+ }
+
+ // close socket
+ try {
+ handleSocket.close();
+ } catch (final IOException e) {
+ logger
+ .log(Level.WARNING,
+ "I/O exception while closing socket!");
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ return;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ }
+
+ /**
+ * Internal thread class that is used to listen for requests.
+ */
+ private class ListenThread extends Thread {
+
+ /**
+ * Flag to remember whether this thread listens for requests at the
+ * moment (<code>true</code>), or has been stopped (<code>false</code>).
+ */
+ private boolean connected;
+
+ /**
+ * Creates a new thread to listen for requests, but does not start
+ * listening, yet.
+ */
+ ListenThread() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "ListenThread");
+
+ // start connected
+ connected = true;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "ListenThread");
+ }
+
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ try {
+
+ // create server socket
+ ServerSocket serverSocket = null;
+ try {
+ serverSocket = new ServerSocket(serverPort);
+ } catch (final IOException ioe) {
+ logger.log(Level.SEVERE,
+ "Can't open server socket on port " + serverPort
+ + "!");
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ return;
+ }
+
+ // as long as we are connected, accept incoming requests
+ logger.log(Level.FINE, "Listening on port " + serverPort
+ + "...");
+ while (connected) {
+ Socket incomingConnection = null;
+ try {
+ incomingConnection = serverSocket.accept();
+ } catch (final Exception e) {
+ logger
+ .log(
+ Level.SEVERE,
+ "Exception while accepting socket requests! Stopping listening!",
+ e);
+ break;
+ }
+ new HandlerThread(incomingConnection).start();
+ }
+
+ } catch (final Exception e) {
+
+ // log that we have been interrupted
+ logger.log(Level.WARNING, "Server has been interrupted!", e);
+ }
+
+ // mark as disconnected
+ connected = false;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+
+ /**
+ * Stops listening on server socket.
+ */
+ public void stopListening() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "stopListening");
+
+ // change connected state to false and interrupt thread
+ connected = false;
+ interrupt();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "stopListening");
+ }
+ }
+
+ /**
+ * Event manager that handles all events concerning this server application.
+ */
+ private final EventManagerImpl eventManager;
+
+ /**
+ * Logger for this server which is called "server." plus the name of this
+ * server application.
+ */
+ private final Logger logger;
+
+ /**
+ * Name of this server application that is used as logger name of this node.
+ */
+ private final String serverApplicationName;
+
+ /**
+ * Port on which this server will listen for incoming requests.
+ */
+ private final int serverPort;
+
+ /**
+ * Thread that listens for requests in the background.
+ */
+ private Thread serverThread;
+
+ /**
+ * Creates a new HTTP server application within this JVM, but does not yet
+ * listen for incoming requests.
+ *
+ * @param network
+ * Network to which this HTTP server belongs; at the moment this
+ * is only used to determine the event manager instance.
+ * @param serverApplicationName
+ * Name of this server that is used as part of the logger name.
+ * @param serverPort
+ * Port on which this server will listen for incoming requests.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
+ */
+ ServerApplicationImpl(final NetworkImpl network,
+ final String serverApplicationName, final int serverPort) {
+
+ // check if serverApplicationName can be used as logger name
+ if (serverApplicationName == null
+ || serverApplicationName.length() == 0) {
+ throw new IllegalArgumentException(
+ "Invalid serverApplicationName: " + serverApplicationName);
+ }
+
+ // create logger
+ logger = Logger.getLogger("server." + serverApplicationName);
+
+ // log entering
+ logger.entering(this.getClass().getName(), "ServerApplicationImpl",
+ new Object[] { network, serverApplicationName, serverPort });
+
+ // check parameters
+ if (network == null || serverPort < 0 || serverPort > 65535) {
+ final IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "ServerApplicationImpl",
+ e);
+ throw e;
+ }
+
+ // remember parameters
+ this.serverApplicationName = serverApplicationName;
+ this.serverPort = serverPort;
+
+ // obtain reference on event manager
+ eventManager = network.getEventManagerImpl();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "ServerApplicationImpl");
+ }
+
+ public synchronized void startListening() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "listen");
+
+ // check if we are already listening
+ if (serverThread != null) {
+ final IllegalStateException e =
+ new IllegalStateException("We are already listening!");
+ logger.throwing(this.getClass().getName(), "listen", e);
+ throw e;
+ }
+
+ // create a thread that listens in the background
+ serverThread = new ListenThread();
+ serverThread.setName("Reply Thread");
+ serverThread.setDaemon(true);
+ serverThread.start();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "listen");
+ }
+
+ public synchronized void stopListening() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "stopListening");
+
+ // check if we are listening
+ if (serverThread == null) {
+ final IllegalStateException e =
+ new IllegalStateException("We are not listening!");
+ logger.throwing(this.getClass().getName(), "stopListening", e);
+ throw e;
+ }
+
+ // log this event
+ logger.log(Level.FINE, "Shutting down server");
+
+ // interrupt thread
+ serverThread.interrupt();
+
+ // unset listening thread
+ serverThread = null;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "stopListening");
+ }
+
+ public synchronized boolean isListening() {
+ return serverThread != null;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": serverApplicationName=\""
+ + serverApplicationName + "\", serverPort=" + serverPort;
+ }
+
+ public String getServerApplicationName() {
+ return serverApplicationName;
+ }
+
+ public int getServerPort() {
+ return serverPort;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/AbstractMasterFactory.java b/src/org/torproject/puppetor/rmi/AbstractMasterFactory.java
index 85508e3..fdd412b 100644
--- a/src/org/torproject/puppetor/rmi/AbstractMasterFactory.java
+++ b/src/org/torproject/puppetor/rmi/AbstractMasterFactory.java
@@ -18,62 +18,61 @@ import org.torproject.puppetor.rmi.tests.TestRegistration;
*/
public abstract class AbstractMasterFactory {
- /**
- * Hold the concrete RemotePuppeTorFactory that will be used to create the
- * implementation classes.
- */
- private static AbstractMasterFactory factory;
+ /**
+ * Hold the concrete RemotePuppeTorFactory that will be used to create the
+ * implementation classes.
+ */
+ private static AbstractMasterFactory factory;
- /**
- * @return a new concrete
- * <code>AbstractRemotePuppeTorFactory<code>subclass as
- * specified by the initialization
- */
- final public synchronized static AbstractMasterFactory getInstance() {
- return factory;
- }
+ /**
+ * @return a new concrete
+ * <code>AbstractRemotePuppeTorFactory<code>subclass as
+ * specified by the initialization
+ */
+ final public synchronized static AbstractMasterFactory getInstance() {
+ return factory;
+ }
- /**
- * @param factory
- * save this as the factory if this hasn't been called before.
- */
- final public synchronized static void initialize(
- final AbstractMasterFactory factory) {
- if (AbstractMasterFactory.factory != null) {
- throw new RuntimeException("Don't call initialize twice!");
- }
- AbstractMasterFactory.factory = factory;
- }
+ /**
+ * @param factory
+ * save this as the factory if this hasn't been called before.
+ */
+ final public synchronized static void initialize(
+ final AbstractMasterFactory factory) {
+ if (AbstractMasterFactory.factory != null) {
+ throw new RuntimeException("Don't call initialize twice!");
+ }
+ AbstractMasterFactory.factory = factory;
+ }
- /**
- * Override this to create a subclass of <code>RemotePuppeTor</code>
- *
- * @param slave
- * Create the server represantation for this connected slave
- * @return The new <code>RemotePuppeTor</code> instance
- */
- public abstract Master createMaster(Slave slave) throws RemoteException;
+ /**
+ * Override this to create a subclass of <code>RemotePuppeTor</code>
+ *
+ * @param slave
+ * Create the server represantation for this connected slave
+ * @return The new <code>RemotePuppeTor</code> instance
+ */
+ public abstract Master createMaster(Slave slave) throws RemoteException;
- /**
- * Override this to create a subclass of <code>TestExecutor</code>.
- *
- * @return The <code>TestExecutor</code> instance.
- */
- public abstract TestExecutor getTestExecutorInstance();
+ /**
+ * Override this to create a subclass of <code>TestExecutor</code>.
+ *
+ * @return The <code>TestExecutor</code> instance.
+ */
+ public abstract TestExecutor getTestExecutorInstance();
- /**
- * Override this to create a subclass of <code>TestRegistration</code>.
- *
- * @return The <code>TestRegistration</code> instance.
- */
- public abstract TestRegistration getTestRegistrationInstance();
-
- /**
- * XXX just for now so I don't forget.-SH
- */
- public abstract NetworkDescription createNetworkDescription();
+ /**
+ * Override this to create a subclass of <code>TestRegistration</code>.
+ *
+ * @return The <code>TestRegistration</code> instance.
+ */
+ public abstract TestRegistration getTestRegistrationInstance();
-
+ /**
+ * XXX just for now so I don't forget.-SH
+ */
+ public abstract NetworkDescription createNetworkDescription();
-// public abstract Network createNetwork(String name);
+
+// public abstract Network createNetwork(String name);
}
diff --git a/src/org/torproject/puppetor/rmi/AbstractSlaveFactory.java b/src/org/torproject/puppetor/rmi/AbstractSlaveFactory.java
index ac5b2d7..dd4c141 100644
--- a/src/org/torproject/puppetor/rmi/AbstractSlaveFactory.java
+++ b/src/org/torproject/puppetor/rmi/AbstractSlaveFactory.java
@@ -19,71 +19,71 @@ import org.torproject.puppetor.rmi.Slave.OS;
*/
public abstract class AbstractSlaveFactory {
- /**
- * Hold the concrete RemotePuppeTorFactory that will be used to create
- * <code>Slave</code> instances. Uses
- * <code>AbstractSlaveFactory.class</code> for locking.
- */
- private static AbstractSlaveFactory factory;
+ /**
+ * Hold the concrete RemotePuppeTorFactory that will be used to create
+ * <code>Slave</code> instances. Uses
+ * <code>AbstractSlaveFactory.class</code> for locking.
+ */
+ private static AbstractSlaveFactory factory;
- /**
- * Hold the remote master object. We only have one per slave. XXX Maybe this
- * entire thing is more like a SlaveManager, not a factory. Oh well. Rename
- * later, I guess -SH
- */
- private static RemoteMaster master;
+ /**
+ * Hold the remote master object. We only have one per slave. XXX Maybe this
+ * entire thing is more like a SlaveManager, not a factory. Oh well. Rename
+ * later, I guess -SH
+ */
+ private static RemoteMaster master;
- /**
- * @return a new concrete <code>AbstractSlaveFactory<code>subclass as
- * specified by the initialization
- */
- final public synchronized static AbstractSlaveFactory getInstance() {
- return factory;
- }
+ /**
+ * @return a new concrete <code>AbstractSlaveFactory<code>subclass as
+ * specified by the initialization
+ */
+ final public synchronized static AbstractSlaveFactory getInstance() {
+ return factory;
+ }
- /**
- * @param factory
- * save this as the factory if this hasn't been called before.
- * XXX - We could throw an exception here, too. I will think
- * about that.-SH
- */
- final public synchronized static void initialize(
- final AbstractSlaveFactory factory) {
- if (AbstractSlaveFactory.factory == null) {
- AbstractSlaveFactory.factory = factory;
- }
- }
+ /**
+ * @param factory
+ * save this as the factory if this hasn't been called before.
+ * XXX - We could throw an exception here, too. I will think
+ * about that.-SH
+ */
+ final public synchronized static void initialize(
+ final AbstractSlaveFactory factory) {
+ if (AbstractSlaveFactory.factory == null) {
+ AbstractSlaveFactory.factory = factory;
+ }
+ }
- /**
- * Register a new master. Note that calling this twice for different master
- * doesn't indicate an error, but trying to to set the same master again is
- * a bug. Setting this to null means the connection to the master was
- * closed.
- *
- * @param master
- * The master that should be used from now on.
- */
- final public synchronized static void setMaster(final RemoteMaster master) {
- AbstractSlaveFactory.master = master;
- }
+ /**
+ * Register a new master. Note that calling this twice for different master
+ * doesn't indicate an error, but trying to to set the same master again is
+ * a bug. Setting this to null means the connection to the master was
+ * closed.
+ *
+ * @param master
+ * The master that should be used from now on.
+ */
+ final public synchronized static void setMaster(final RemoteMaster master) {
+ AbstractSlaveFactory.master = master;
+ }
- /**
- * @return the RemoteMaster currently registered.
- */
- final public synchronized static RemoteMaster getMaster() {
- if (AbstractSlaveFactory.master == null) {
- throw new IllegalStateException("No master set yet!");
- }
- return AbstractSlaveFactory.master;
- }
+ /**
+ * @return the RemoteMaster currently registered.
+ */
+ final public synchronized static RemoteMaster getMaster() {
+ if (AbstractSlaveFactory.master == null) {
+ throw new IllegalStateException("No master set yet!");
+ }
+ return AbstractSlaveFactory.master;
+ }
- /**
- * Override this to create a subclass of <code>Slave</code>
- *
- * @return The new <code>Slave</code> instance
- */
- public abstract Slave createSlave(final String slaveName, final OS os,
- final String ip, final Set<Integer> ports,
- final Set<Integer> availableRevisions) throws NullPointerException;
+ /**
+ * Override this to create a subclass of <code>Slave</code>
+ *
+ * @return The new <code>Slave</code> instance
+ */
+ public abstract Slave createSlave(final String slaveName, final OS os,
+ final String ip, final Set<Integer> ports,
+ final Set<Integer> availableRevisions) throws NullPointerException;
}
diff --git a/src/org/torproject/puppetor/rmi/LocalMaster.java b/src/org/torproject/puppetor/rmi/LocalMaster.java
index 50dbacb..e926bec 100644
--- a/src/org/torproject/puppetor/rmi/LocalMaster.java
+++ b/src/org/torproject/puppetor/rmi/LocalMaster.java
@@ -12,25 +12,25 @@ package org.torproject.puppetor.rmi;
* @author Sebastian Hahn
*/
public interface LocalMaster {
- /**
- * @return the slave instance this connection refers to.
- */
- public Slave getSlave();
+ /**
+ * @return the slave instance this connection refers to.
+ */
+ public Slave getSlave();
- /**
- * Add a new AbstractTaskImpl for the connected slave.
- *
- * @param abstractTaskImpl
- */
- public void addTask(Task task);
+ /**
+ * Add a new AbstractTaskImpl for the connected slave.
+ *
+ * @param abstractTaskImpl
+ */
+ public void addTask(Task task);
- /**
- * @param taskId
- * The task id that we want to get
- * @return Get the TaskResult for the Task with the specified taskId.
- * @throws InterruptedException
- * if interrupted while waiting for the next TestResult
- */
- public TaskResult getTaskResult(int taskId) throws InterruptedException;
+ /**
+ * @param taskId
+ * The task id that we want to get
+ * @return Get the TaskResult for the Task with the specified taskId.
+ * @throws InterruptedException
+ * if interrupted while waiting for the next TestResult
+ */
+ public TaskResult getTaskResult(int taskId) throws InterruptedException;
}
diff --git a/src/org/torproject/puppetor/rmi/MasterConnector.java b/src/org/torproject/puppetor/rmi/MasterConnector.java
index 44ea315..0660770 100644
--- a/src/org/torproject/puppetor/rmi/MasterConnector.java
+++ b/src/org/torproject/puppetor/rmi/MasterConnector.java
@@ -17,15 +17,15 @@ import java.rmi.RemoteException;
*/
public interface MasterConnector extends Remote {
- /**
- * Called once by every connecting client so that the master knows about it
- * and has a chance to pass back a representation of itself.
- *
- * @param slave
- * A slave representation as passed from the connecting slave
- * @return The representation of the master
- * @throws RemoteException
- */
- public RemoteMaster registerClient(final Slave slave)
- throws RemoteException;
+ /**
+ * Called once by every connecting client so that the master knows about it
+ * and has a chance to pass back a representation of itself.
+ *
+ * @param slave
+ * A slave representation as passed from the connecting slave
+ * @return The representation of the master
+ * @throws RemoteException
+ */
+ public RemoteMaster registerClient(final Slave slave)
+ throws RemoteException;
}
diff --git a/src/org/torproject/puppetor/rmi/Network.java b/src/org/torproject/puppetor/rmi/Network.java
index 4f4f6c2..cd1b954 100644
--- a/src/org/torproject/puppetor/rmi/Network.java
+++ b/src/org/torproject/puppetor/rmi/Network.java
@@ -13,67 +13,67 @@ import java.util.Set;
* This class describes all Tor instances on the slaves that are used to form a
* private Tor network, or the Tor instances that are added to the public
* network and are used in a set of tests.
- *
+ *
* @author Sebastian Hahn
*/
public interface Network extends Serializable {
- /**
- * @param torInstance
- * add this <code>TorInstance</code> to the network.
- */
- public void addTorInstance(TorInstance torInstance);
-
- /**
- * @return this network's name, mainly to identify it in logs.
- */
- public String getName();
+ /**
+ * @param torInstance
+ * add this <code>TorInstance</code> to the network.
+ */
+ public void addTorInstance(TorInstance torInstance);
- /**
- * @param test
- * add this <code>test</code> to the network.
- */
- public void addTest(Test test);
+ /**
+ * @return this network's name, mainly to identify it in logs.
+ */
+ public String getName();
- /**
- * @return a link for each slave that is part of this network.
- */
- public Set<LocalMaster> getMasters();
+ /**
+ * @param test
+ * add this <code>test</code> to the network.
+ */
+ public void addTest(Test test);
- /**
- * @return all Tor instances that are authorities
- */
- public Set<TorInstance> getDirectoryAuthorities();
+ /**
+ * @return a link for each slave that is part of this network.
+ */
+ public Set<LocalMaster> getMasters();
- /**
- * @return all Tor instances that are routers, but not authorities
- */
- public Set<TorInstance> getRoutersOnly();
+ /**
+ * @return all Tor instances that are authorities
+ */
+ public Set<TorInstance> getDirectoryAuthorities();
- /**
- * @return all Tor instances that are routers (including authorities)
- */
- public Set<TorInstance> getRouters();
+ /**
+ * @return all Tor instances that are routers, but not authorities
+ */
+ public Set<TorInstance> getRoutersOnly();
- /**
- * @return all Tor instances that are proxis (but not authorities or
- * routers)
- */
- public Set<TorInstance> getProxiesOnly();
+ /**
+ * @return all Tor instances that are routers (including authorities)
+ */
+ public Set<TorInstance> getRouters();
- /**
- * @return all Tor instances that are proxies (including authorities and
- * routers)
- */
- public Set<TorInstance> getProxies();
-
- /**
- * @return all Tests that can run on this network -SH
- */
- public List<Test> getTests();
+ /**
+ * @return all Tor instances that are proxis (but not authorities or
+ * routers)
+ */
+ public Set<TorInstance> getProxiesOnly();
- /**
- * Is this a private network or part of the public one?
- */
- public boolean isPrivateNetwork();
+ /**
+ * @return all Tor instances that are proxies (including authorities and
+ * routers)
+ */
+ public Set<TorInstance> getProxies();
+
+ /**
+ * @return all Tests that can run on this network -SH
+ */
+ public List<Test> getTests();
+
+ /**
+ * Is this a private network or part of the public one?
+ */
+ public boolean isPrivateNetwork();
}
diff --git a/src/org/torproject/puppetor/rmi/NetworkDescription.java b/src/org/torproject/puppetor/rmi/NetworkDescription.java
index 1636566..7e23208 100644
--- a/src/org/torproject/puppetor/rmi/NetworkDescription.java
+++ b/src/org/torproject/puppetor/rmi/NetworkDescription.java
@@ -8,9 +8,9 @@ package org.torproject.puppetor.rmi;
import java.io.Serializable;
public interface NetworkDescription extends Serializable {
- public int necessaryProxies();
+ public int necessaryProxies();
- public int necessaryRouters();
+ public int necessaryRouters();
- public int necessaryDirectoryAuthorities();
+ public int necessaryDirectoryAuthorities();
}
diff --git a/src/org/torproject/puppetor/rmi/RemoteMaster.java b/src/org/torproject/puppetor/rmi/RemoteMaster.java
index 07a1b87..65a1412 100644
--- a/src/org/torproject/puppetor/rmi/RemoteMaster.java
+++ b/src/org/torproject/puppetor/rmi/RemoteMaster.java
@@ -23,25 +23,25 @@ import java.rmi.RemoteException;
*/
public interface RemoteMaster extends Remote {
- /**
- * Slaves that must poll because they are not reachable can use this method
- * to ask the master for new work.
- *
- * @throws RemoteException
- * RMI...
- * @throws InterruptedException
- * when interrupted while waiting for the next job to arrive.
- */
- public Task getNewTask() throws RemoteException, InterruptedException;
+ /**
+ * Slaves that must poll because they are not reachable can use this method
+ * to ask the master for new work.
+ *
+ * @throws RemoteException
+ * RMI...
+ * @throws InterruptedException
+ * when interrupted while waiting for the next job to arrive.
+ */
+ public Task getNewTask() throws RemoteException, InterruptedException;
- /**
- * Report back the result of the task to the master. If possible, add an
- * error message. XXX Maybe down the road an error object is
- * needed/wanted-SH
- *
- * @throws RemoteException
- * RMI
- */
- public void reportTaskResult(TaskResult task) throws RemoteException,
- InterruptedException;
+ /**
+ * Report back the result of the task to the master. If possible, add an
+ * error message. XXX Maybe down the road an error object is
+ * needed/wanted-SH
+ *
+ * @throws RemoteException
+ * RMI
+ */
+ public void reportTaskResult(TaskResult task) throws RemoteException,
+ InterruptedException;
}
diff --git a/src/org/torproject/puppetor/rmi/Slave.java b/src/org/torproject/puppetor/rmi/Slave.java
index 2f037a1..405a071 100644
--- a/src/org/torproject/puppetor/rmi/Slave.java
+++ b/src/org/torproject/puppetor/rmi/Slave.java
@@ -19,33 +19,33 @@ import java.util.Set;
*/
public interface Slave extends Serializable {
- public enum OS {
- UNDEFINED, LINUX_I86_32, LINUX_I86_64, MAC_OSX_PPC, MAC_OSX_I86,
- WINDOWS_XP_32, WINDOWS_XP_64, WINDOWS_VISTA_32, WINDOWS_VISTA_64
- }
-
- /**
- * @return the slave's name.
- */
- public String getName();
-
- /**
- * @return the slave's operating system as defined in <code>Slave.OS</code>.
- */
- public OS getOS();
-
- /**
- * @return the slave's IP address. XXX Test this with IPv6-SH
- */
- public InetAddress getIP();
-
- /**
- * @return the ports this slave can open
- */
- public Set<Integer> openablePorts();
-
- /**
- * @return Tor revisions available on the slave
- */
- public Set<Integer> availableRevisions();
+ public enum OS {
+ UNDEFINED, LINUX_I86_32, LINUX_I86_64, MAC_OSX_PPC, MAC_OSX_I86,
+ WINDOWS_XP_32, WINDOWS_XP_64, WINDOWS_VISTA_32, WINDOWS_VISTA_64
+ }
+
+ /**
+ * @return the slave's name.
+ */
+ public String getName();
+
+ /**
+ * @return the slave's operating system as defined in <code>Slave.OS</code>.
+ */
+ public OS getOS();
+
+ /**
+ * @return the slave's IP address. XXX Test this with IPv6-SH
+ */
+ public InetAddress getIP();
+
+ /**
+ * @return the ports this slave can open
+ */
+ public Set<Integer> openablePorts();
+
+ /**
+ * @return Tor revisions available on the slave
+ */
+ public Set<Integer> availableRevisions();
}
diff --git a/src/org/torproject/puppetor/rmi/Task.java b/src/org/torproject/puppetor/rmi/Task.java
index bb466e8..3273e65 100644
--- a/src/org/torproject/puppetor/rmi/Task.java
+++ b/src/org/torproject/puppetor/rmi/Task.java
@@ -11,28 +11,28 @@ import java.util.Collection;
public interface Task extends Serializable {
- /**
- * Execute the task. Must be called by the slave.
- *
- * @throws InterruptedException
- * if interrupted while the task is running.
- * @throws RemoteException
- * RMI
- */
- public void execute() throws InterruptedException, RemoteException;
+ /**
+ * Execute the task. Must be called by the slave.
+ *
+ * @throws InterruptedException
+ * if interrupted while the task is running.
+ * @throws RemoteException
+ * RMI
+ */
+ public void execute() throws InterruptedException, RemoteException;
- /**
- * Returns this tasks id. Task ids must be globally unique and larger than 0
- * or 0 to indicate a task that was sent out by the slave, not the master.
- */
- public int getId();
+ /**
+ * Returns this tasks id. Task ids must be globally unique and larger than 0
+ * or 0 to indicate a task that was sent out by the slave, not the master.
+ */
+ public int getId();
- /**
- * This method will be called by the <code>TestExecutor</code> to allow
- * tasks to collect additional information if they need it.
- * @param additionalInformation
- * offer this information.
- */
- public void addAdditionalInformation(
- Collection<String> additionalInformation);
+ /**
+ * This method will be called by the <code>TestExecutor</code> to allow
+ * tasks to collect additional information if they need it.
+ * @param additionalInformation
+ * offer this information.
+ */
+ public void addAdditionalInformation(
+ Collection<String> additionalInformation);
}
diff --git a/src/org/torproject/puppetor/rmi/TaskExecutionNotSuccessfulException.java b/src/org/torproject/puppetor/rmi/TaskExecutionNotSuccessfulException.java
index a37bb9a..8c47102 100644
--- a/src/org/torproject/puppetor/rmi/TaskExecutionNotSuccessfulException.java
+++ b/src/org/torproject/puppetor/rmi/TaskExecutionNotSuccessfulException.java
@@ -8,16 +8,16 @@ package org.torproject.puppetor.rmi;
import java.util.Set;
public class TaskExecutionNotSuccessfulException extends Exception {
- private static final long serialVersionUID = 1L;
- final private Set<TaskResult> taskResults;
+ private static final long serialVersionUID = 1L;
+ final private Set<TaskResult> taskResults;
- public TaskExecutionNotSuccessfulException(final Set<TaskResult> taskResults) {
- this.taskResults = taskResults;
- }
+ public TaskExecutionNotSuccessfulException(final Set<TaskResult> taskResults) {
+ this.taskResults = taskResults;
+ }
- public Set<TaskResult> getTaskResults() {
- return taskResults;
- }
+ public Set<TaskResult> getTaskResults() {
+ return taskResults;
+ }
- // XXX Add some logging capabilities -SH
+ // XXX Add some logging capabilities -SH
}
diff --git a/src/org/torproject/puppetor/rmi/TaskResult.java b/src/org/torproject/puppetor/rmi/TaskResult.java
index 7cd9f68..e697c3c 100644
--- a/src/org/torproject/puppetor/rmi/TaskResult.java
+++ b/src/org/torproject/puppetor/rmi/TaskResult.java
@@ -10,30 +10,30 @@ import java.io.Serializable;
/**
* After the completion of a <code>Task</code>, a <code>TaskResult</code> is
* created to report the result of the task as well as logging information to
- * the Master.
- *
+ * the Master.
+ *
* @author Sebastian Hahn
*/
public interface TaskResult extends Serializable {
- /**
- * @return
- * the task that we have a result for
- */
- public Task getTask();
-
- /**
- * @return
- * <code>true</code> if the task execution was successful,
- * false otherwise.
- */
- public boolean wasSuccessful();
-
- /**
- * A <code>Task</code> may optionally pass back a result that can be used
- * by the Master to manage further Task execution.
- * @return
- * the result of this task or null if no result is set.
- */
- public String getTaskResult();
-}
\ No newline at end of file
+ /**
+ * @return
+ * the task that we have a result for
+ */
+ public Task getTask();
+
+ /**
+ * @return
+ * <code>true</code> if the task execution was successful,
+ * false otherwise.
+ */
+ public boolean wasSuccessful();
+
+ /**
+ * A <code>Task</code> may optionally pass back a result that can be used
+ * by the Master to manage further Task execution.
+ * @return
+ * the result of this task or null if no result is set.
+ */
+ public String getTaskResult();
+}
diff --git a/src/org/torproject/puppetor/rmi/Test.java b/src/org/torproject/puppetor/rmi/Test.java
index c6a400f..07f66e2 100644
--- a/src/org/torproject/puppetor/rmi/Test.java
+++ b/src/org/torproject/puppetor/rmi/Test.java
@@ -16,22 +16,22 @@ import java.io.Serializable;
* @author Sebastian Hahn
*/
public interface Test extends Serializable {
- /**
- * @return
- * a description of what this test is useful for.
- */
- public String getDescription();
+ /**
+ * @return
+ * a description of what this test is useful for.
+ */
+ public String getDescription();
- /**
- * @return
- * a description of the network that this test requires to run, so the
- * </code>TestExecutor</code> can pick or set up one.
- */
- public NetworkDescription getNetworkDescription();
-
- /**
- * Call this when the network has been set up and you want to run the test
- * with the current network.
- */
- public void doTest();
+ /**
+ * @return
+ * a description of the network that this test requires to run, so the
+ * </code>TestExecutor</code> can pick or set up one.
+ */
+ public NetworkDescription getNetworkDescription();
+
+ /**
+ * Call this when the network has been set up and you want to run the test
+ * with the current network.
+ */
+ public void doTest();
}
diff --git a/src/org/torproject/puppetor/rmi/TestExecutor.java b/src/org/torproject/puppetor/rmi/TestExecutor.java
index f5ed5c6..f736685 100644
--- a/src/org/torproject/puppetor/rmi/TestExecutor.java
+++ b/src/org/torproject/puppetor/rmi/TestExecutor.java
@@ -21,94 +21,94 @@ import java.util.Set;
*/
public interface TestExecutor {
- /**
- * Register a test with the executor so it will consider it for execution.
- * Accept all submitted tests even though some may not be executable at the
- * moment of submission.
- */
- public void registerTest(Test test);
+ /**
+ * Register a test with the executor so it will consider it for execution.
+ * Accept all submitted tests even though some may not be executable at the
+ * moment of submission.
+ */
+ public void registerTest(Test test);
- /**
- * Start executing tests. Callers should make sure that the PuppeTor network
- * that is supposed to be used is ready.
- */
- public void startTesting();
+ /**
+ * Start executing tests. Callers should make sure that the PuppeTor network
+ * that is supposed to be used is ready.
+ */
+ public void startTesting();
- /**
- * Return an immutable Map of the nodes that have been run successfully
- * along with the results of the tests.
- */
- public Map<Test, TestResult> getSuccessfulTests();
+ /**
+ * Return an immutable Map of the nodes that have been run successfully
+ * along with the results of the tests.
+ */
+ public Map<Test, TestResult> getSuccessfulTests();
- /**
- * Return an immutable Map of the nodes that have been run but didn't
- * complete successfully along with the results of the tests.
- */
- public Map<Test, TestResult> getFailedTests();
+ /**
+ * Return an immutable Map of the nodes that have been run but didn't
+ * complete successfully along with the results of the tests.
+ */
+ public Map<Test, TestResult> getFailedTests();
- /**
- * Return all tests that could not be executed because the PuppeTorNetwork
- * could not match a test's preconditions.
- */
- public Set<Test> getCannotRunTests();
+ /**
+ * Return all tests that could not be executed because the PuppeTorNetwork
+ * could not match a test's preconditions.
+ */
+ public Set<Test> getCannotRunTests();
- /**
- * Register a newly connected PuppeTor slave via its
- * <code>LocalMaster</code> connection object.
- */
- public void registerLocalMaster(LocalMaster master);
+ /**
+ * Register a newly connected PuppeTor slave via its
+ * <code>LocalMaster</code> connection object.
+ */
+ public void registerLocalMaster(LocalMaster master);
- /**
- * Unregister a PuppeTor slave. Called when a slave disconnects.
- */
- public void unregisterLocalMaster(LocalMaster master);
+ /**
+ * Unregister a PuppeTor slave. Called when a slave disconnects.
+ */
+ public void unregisterLocalMaster(LocalMaster master);
- /**
- * @return
- * the currently running network.
- */
- public Network getCurrentNetwork();
+ /**
+ * @return
+ * the currently running network.
+ */
+ public Network getCurrentNetwork();
- /**
- * Execute the passed <code>Task</code> once per passed
- * <code>LocalMaster</code>. If a <code>LocalMaster</code> is passed
- * more than once, the task will be executed multiple times.
- *
- * @param masters
- * execute the task for those masters.
- * @param taskClass
- * create a task of this class and execute it.
- * @param taskResults
- * place the results of the task in this <code>Set</code> unless
- * <code>null</code> is passed.
- * @param additionalInformation TODO
- * @throws TaskExecutionNotSuccessfulException
- * Indicates a failure during task execution
- */
- public void executeTaskForMasters(final Collection<LocalMaster> masters,
- final Class<? extends Task> taskClass, final Set<TaskResult> taskResults,
- Collection<String> additionalInformation)
- throws TaskExecutionNotSuccessfulException;
+ /**
+ * Execute the passed <code>Task</code> once per passed
+ * <code>LocalMaster</code>. If a <code>LocalMaster</code> is passed
+ * more than once, the task will be executed multiple times.
+ *
+ * @param masters
+ * execute the task for those masters.
+ * @param taskClass
+ * create a task of this class and execute it.
+ * @param taskResults
+ * place the results of the task in this <code>Set</code> unless
+ * <code>null</code> is passed.
+ * @param additionalInformation TODO
+ * @throws TaskExecutionNotSuccessfulException
+ * Indicates a failure during task execution
+ */
+ public void executeTaskForMasters(final Collection<LocalMaster> masters,
+ final Class<? extends Task> taskClass, final Set<TaskResult> taskResults,
+ Collection<String> additionalInformation)
+ throws TaskExecutionNotSuccessfulException;
- /**
- * Execute the passed <code>Task</code> once per passed
- * <code>TorInstance</code>. If a <code>TorInstance</code> is passed
- * more than once, the task will be executed multiple times.
- * @param taskClass
- * create a task of this class and execute it.
- * @param taskResults
- * place the results of the task in this <code>Set</code> unless
- * <code>null</code> is passed.
- * @param additionalInformation
- * call the task's addAdditionalInformation method with this
- * parameter.
- * @param torInstances
- * execute the task for those masters.
- * @throws TaskExecutionNotSuccessfulException
- * Indicates a failure during task execution
- */
- public void executeTaskForTorInstances(Collection<TorInstance> instances,
- Class<? extends Task> taskClass, Set<TaskResult> taskResults,
- Collection<String> additionalInformation)
- throws TaskExecutionNotSuccessfulException;
+ /**
+ * Execute the passed <code>Task</code> once per passed
+ * <code>TorInstance</code>. If a <code>TorInstance</code> is passed
+ * more than once, the task will be executed multiple times.
+ * @param taskClass
+ * create a task of this class and execute it.
+ * @param taskResults
+ * place the results of the task in this <code>Set</code> unless
+ * <code>null</code> is passed.
+ * @param additionalInformation
+ * call the task's addAdditionalInformation method with this
+ * parameter.
+ * @param torInstances
+ * execute the task for those masters.
+ * @throws TaskExecutionNotSuccessfulException
+ * Indicates a failure during task execution
+ */
+ public void executeTaskForTorInstances(Collection<TorInstance> instances,
+ Class<? extends Task> taskClass, Set<TaskResult> taskResults,
+ Collection<String> additionalInformation)
+ throws TaskExecutionNotSuccessfulException;
}
diff --git a/src/org/torproject/puppetor/rmi/TestResult.java b/src/org/torproject/puppetor/rmi/TestResult.java
index 32788c1..d67b57b 100644
--- a/src/org/torproject/puppetor/rmi/TestResult.java
+++ b/src/org/torproject/puppetor/rmi/TestResult.java
@@ -11,5 +11,5 @@ import java.io.Serializable;
* XXX unused for now. this will hold the result of a /<code>Test</code> -SH
*/
public interface TestResult extends Serializable {
- public Test getJob();
+ public Test getJob();
}
diff --git a/src/org/torproject/puppetor/rmi/TorInstance.java b/src/org/torproject/puppetor/rmi/TorInstance.java
index fd9295e..fca8d61 100644
--- a/src/org/torproject/puppetor/rmi/TorInstance.java
+++ b/src/org/torproject/puppetor/rmi/TorInstance.java
@@ -13,45 +13,45 @@ import java.util.List;
* @author Sebastian Hahn
*/
public interface TorInstance {
- /**
- * Additional configuration options that a test wants to be set for a tor
- * instance. <code>TorInstance.shouldReplaceConfiguration()</code>
- * determines whether this configuration should be added to the default tor
- * configuration or replace it.
- *
- * @return An immutable list of extra configuration settings.
- */
- public List<String> getConfiguration();
-
- /**
- * @return the name by which this Tor instance will be identified at the
- * slaves. See org.torproject.puppetor.Network.getNode().
- */
- public String getName();
-
- /**
- * Whether the caller should use the result of
- * <code>TorInstance.getExtraConfiguration()</code> to append tor's
- * default configuration or replace it.
- *
- * @return true if configuration should be replaced, false if it should be
- * appended.
- */
- public boolean shouldReplaceConfiguration();
-
- public boolean isDirectoryAuthority();
-
- public boolean isBridgeAuthority();
-
- public boolean isRouter();
-
- public boolean isExit();
-
- public boolean isOnPrivateNetwork();
-
- public int getRevision();
-
- public boolean isBridge();
-
- public LocalMaster getMaster();
-}
\ No newline at end of file
+ /**
+ * Additional configuration options that a test wants to be set for a tor
+ * instance. <code>TorInstance.shouldReplaceConfiguration()</code>
+ * determines whether this configuration should be added to the default tor
+ * configuration or replace it.
+ *
+ * @return An immutable list of extra configuration settings.
+ */
+ public List<String> getConfiguration();
+
+ /**
+ * @return the name by which this Tor instance will be identified at the
+ * slaves. See org.torproject.puppetor.Network.getNode().
+ */
+ public String getName();
+
+ /**
+ * Whether the caller should use the result of
+ * <code>TorInstance.getExtraConfiguration()</code> to append tor's
+ * default configuration or replace it.
+ *
+ * @return true if configuration should be replaced, false if it should be
+ * appended.
+ */
+ public boolean shouldReplaceConfiguration();
+
+ public boolean isDirectoryAuthority();
+
+ public boolean isBridgeAuthority();
+
+ public boolean isRouter();
+
+ public boolean isExit();
+
+ public boolean isOnPrivateNetwork();
+
+ public int getRevision();
+
+ public boolean isBridge();
+
+ public LocalMaster getMaster();
+}
diff --git a/src/org/torproject/puppetor/rmi/execute/PuppeTorMasterProgram.java b/src/org/torproject/puppetor/rmi/execute/PuppeTorMasterProgram.java
index e05593a..28c24ee 100644
--- a/src/org/torproject/puppetor/rmi/execute/PuppeTorMasterProgram.java
+++ b/src/org/torproject/puppetor/rmi/execute/PuppeTorMasterProgram.java
@@ -38,157 +38,157 @@ import org.torproject.puppetor.rmi.tests.TestRegistration;
*/
public class PuppeTorMasterProgram {
- /**
- * The RMI registry.
- */
- private Registry registry;
-
- /**
- * The port the server is supposed to listen on. This port must not be
- * firewalled and must be forwarded to the machine if necessary.
- */
- final private static int serverport = 2050;
-
- /**
- * The address this server should bind on. Use 127.0.0.1 for local testing.
- * XXX Someone should check if this works with IPv6 -SH
- */
- final private static String serveraddress = "127.0.0.1";
-
- /**
- * Master application entry point
- *
- * @param args
- * Command-line arguments - ignored for now.
- * @throws NotBoundException
- * @throws RemoteException
- * @throws AccessException
- */
- public static void main(final String[] args) throws AccessException,
- RemoteException, NotBoundException {
- final PuppeTorMasterProgram server = new PuppeTorMasterProgram();
-
- final TestExecutor exec =
- AbstractMasterFactory.getInstance().getTestExecutorInstance();
- exec.startTesting();
- server.unregisterRMIRegistry();
- // Suggest a garbage collection, may increase shutdown.
- System.gc();
- }
-
- /**
- * Private constructor to set up RMI-related Java-internal variables and
- * create a <code>RemotePuppeTorImpl</code>.
- *
- * @throws NotBoundException
- * @throws RemoteException
- * @throws AccessException
- */
- private PuppeTorMasterProgram() throws AccessException, RemoteException,
- NotBoundException {
- // Set the location of the keystore where your private certificate is.
- System.setProperty("javax.net.ssl.keyStore", "res/keystore");
- // Set the password for your keystore.
- System.setProperty("javax.net.ssl.keyStorePassword", "pleasechange");
-
- /*
- * Set the location of the truststore which contains the exported
- * certificates of your slaves.
- */
- System.setProperty("javax.net.ssl.trustStore", "res/truststore");
- // Use a timeout of 45 seconds to detect disconnected clients.
- System.setProperty("java.rmi.dgc.leaseValue", "45000");
-
- // Tell the RMI system the location of the master
- System.setProperty("java.rmi.server.hostname", serveraddress);
-
- // Set up the factories we want to use
- AbstractMasterFactory.initialize(new MasterImplFactory());
-
- registerTests();
- final InnerMasterConnector master = InnerMasterConnector.getInstance();
-
- try {
- registry =
- LocateRegistry.createRegistry(serverport,
- new SslRMIClientSocketFactory(),
- new SslRMIServerSocketFactory(null, null, true));
- registry.bind("Master", master);
- } catch (final Throwable th) {
- th.printStackTrace();
- throw new RuntimeException(
- "Could not create the registry or bind"
- + "an object in it. Please check your system's configuration. "
- + th);
- }
-
- System.out.println("waiting for slaves.");
- try {
- Thread.sleep(1000 * 60 * 2);
- } catch (final InterruptedException e) {
- e.printStackTrace();
- throw new RuntimeException("This is the main thread. We don't "
- + "want to be interrupted.");
- }
- registry.unbind("Master");
- // Only unbinding is not enough, the object will still be exported.
- UnicastRemoteObject.unexportObject(master, true);
- }
-
- /**
- * Register all the tests you want to execute here.
- */
- private void registerTests() {
- final AbstractMasterFactory fact = AbstractMasterFactory.getInstance();
- final TestExecutor exec = fact.getTestExecutorInstance();
- final TestRegistration registration = fact.getTestRegistrationInstance();
- registration.registerTests(exec);
- }
-
- private void unregisterRMIRegistry() throws NoSuchObjectException {
- UnicastRemoteObject.unexportObject(registry, true);
- registry = null;
- }
-
- static class InnerMasterConnector extends UnicastRemoteObject implements
- MasterConnector {
- /**
- * Required for serialization. Needs to change for new released
- * versions.
- */
- private static final long serialVersionUID = 1L;
-
- private static InnerMasterConnector instance;
-
- static {
- try {
- instance = new InnerMasterConnector();
- } catch (final RemoteException e) {
- e.printStackTrace();
- throw new ExceptionInInitializerError(e);
- }
- }
-
- /**
- * private constructor, Singleton
- *
- * @throws RemoteException
- * RMI
- */
- private InnerMasterConnector() throws RemoteException {}
-
- public static InnerMasterConnector getInstance() {
- return instance;
- }
-
- public RemoteMaster registerClient(final Slave slave)
- throws RemoteException {
- final AbstractMasterFactory fact =
- AbstractMasterFactory.getInstance();
- final Master master = fact.createMaster(slave);
- AbstractMasterFactory.getInstance().getTestExecutorInstance()
- .registerLocalMaster((LocalMaster) master);
- return (RemoteMaster) master;
- }
- }
+ /**
+ * The RMI registry.
+ */
+ private Registry registry;
+
+ /**
+ * The port the server is supposed to listen on. This port must not be
+ * firewalled and must be forwarded to the machine if necessary.
+ */
+ final private static int serverport = 2050;
+
+ /**
+ * The address this server should bind on. Use 127.0.0.1 for local testing.
+ * XXX Someone should check if this works with IPv6 -SH
+ */
+ final private static String serveraddress = "127.0.0.1";
+
+ /**
+ * Master application entry point
+ *
+ * @param args
+ * Command-line arguments - ignored for now.
+ * @throws NotBoundException
+ * @throws RemoteException
+ * @throws AccessException
+ */
+ public static void main(final String[] args) throws AccessException,
+ RemoteException, NotBoundException {
+ final PuppeTorMasterProgram server = new PuppeTorMasterProgram();
+
+ final TestExecutor exec =
+ AbstractMasterFactory.getInstance().getTestExecutorInstance();
+ exec.startTesting();
+ server.unregisterRMIRegistry();
+ // Suggest a garbage collection, may increase shutdown.
+ System.gc();
+ }
+
+ /**
+ * Private constructor to set up RMI-related Java-internal variables and
+ * create a <code>RemotePuppeTorImpl</code>.
+ *
+ * @throws NotBoundException
+ * @throws RemoteException
+ * @throws AccessException
+ */
+ private PuppeTorMasterProgram() throws AccessException, RemoteException,
+ NotBoundException {
+ // Set the location of the keystore where your private certificate is.
+ System.setProperty("javax.net.ssl.keyStore", "res/keystore");
+ // Set the password for your keystore.
+ System.setProperty("javax.net.ssl.keyStorePassword", "pleasechange");
+
+ /*
+ * Set the location of the truststore which contains the exported
+ * certificates of your slaves.
+ */
+ System.setProperty("javax.net.ssl.trustStore", "res/truststore");
+ // Use a timeout of 45 seconds to detect disconnected clients.
+ System.setProperty("java.rmi.dgc.leaseValue", "45000");
+
+ // Tell the RMI system the location of the master
+ System.setProperty("java.rmi.server.hostname", serveraddress);
+
+ // Set up the factories we want to use
+ AbstractMasterFactory.initialize(new MasterImplFactory());
+
+ registerTests();
+ final InnerMasterConnector master = InnerMasterConnector.getInstance();
+
+ try {
+ registry =
+ LocateRegistry.createRegistry(serverport,
+ new SslRMIClientSocketFactory(),
+ new SslRMIServerSocketFactory(null, null, true));
+ registry.bind("Master", master);
+ } catch (final Throwable th) {
+ th.printStackTrace();
+ throw new RuntimeException(
+ "Could not create the registry or bind"
+ + "an object in it. Please check your system's configuration. "
+ + th);
+ }
+
+ System.out.println("waiting for slaves.");
+ try {
+ Thread.sleep(1000 * 60 * 2);
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ throw new RuntimeException("This is the main thread. We don't "
+ + "want to be interrupted.");
+ }
+ registry.unbind("Master");
+ // Only unbinding is not enough, the object will still be exported.
+ UnicastRemoteObject.unexportObject(master, true);
+ }
+
+ /**
+ * Register all the tests you want to execute here.
+ */
+ private void registerTests() {
+ final AbstractMasterFactory fact = AbstractMasterFactory.getInstance();
+ final TestExecutor exec = fact.getTestExecutorInstance();
+ final TestRegistration registration = fact.getTestRegistrationInstance();
+ registration.registerTests(exec);
+ }
+
+ private void unregisterRMIRegistry() throws NoSuchObjectException {
+ UnicastRemoteObject.unexportObject(registry, true);
+ registry = null;
+ }
+
+ static class InnerMasterConnector extends UnicastRemoteObject implements
+ MasterConnector {
+ /**
+ * Required for serialization. Needs to change for new released
+ * versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ private static InnerMasterConnector instance;
+
+ static {
+ try {
+ instance = new InnerMasterConnector();
+ } catch (final RemoteException e) {
+ e.printStackTrace();
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ /**
+ * private constructor, Singleton
+ *
+ * @throws RemoteException
+ * RMI
+ */
+ private InnerMasterConnector() throws RemoteException {}
+
+ public static InnerMasterConnector getInstance() {
+ return instance;
+ }
+
+ public RemoteMaster registerClient(final Slave slave)
+ throws RemoteException {
+ final AbstractMasterFactory fact =
+ AbstractMasterFactory.getInstance();
+ final Master master = fact.createMaster(slave);
+ AbstractMasterFactory.getInstance().getTestExecutorInstance()
+ .registerLocalMaster((LocalMaster) master);
+ return (RemoteMaster) master;
+ }
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/execute/PuppeTorSlaveProgram.java b/src/org/torproject/puppetor/rmi/execute/PuppeTorSlaveProgram.java
index 5605ed3..2e6aa02 100644
--- a/src/org/torproject/puppetor/rmi/execute/PuppeTorSlaveProgram.java
+++ b/src/org/torproject/puppetor/rmi/execute/PuppeTorSlaveProgram.java
@@ -38,179 +38,178 @@ import org.torproject.puppetor.rmi.tasks.TerminateTask;
*/
public class PuppeTorSlaveProgram {
- /**
- * The port the master server is supposed to listen on. This port must not
- * be firewalled and must be forwarded to the machine if necessary. Use the
- * same value as you used for the master's configuration.
- */
- final private static int serverport = 2050;
-
- /**
- * The address master server listens on. Use the same value as you used for
- * the master's configuration. XXX Someone should check if this works with
- * IPv6 -SH
- */
- final private static String serveraddress = "127.0.0.1";//78.47.18.109";
-
- /**
- * The address this slave listens on. Use 127.0.0.1 for slaves that do not
- * open any ports for the outside world and thus can act as Tor clients
- * only.
- */
- final private static String myaddress = "127.0.0.1";
-
- /**
- * Each slave is identified by its unique <code>slaveName</code>. Be
- * careful to prevent naming collisions between slaves.
- */
- final private static String slaveName = "slave1";
-
- /**
- * A representation of this slave node to be sent to the master.
- */
- final private Slave slave;
-
- final protected static BlockingQueue<Task> tasks =
- new LinkedBlockingQueue<Task>();
-
- /**
- * Slave application entry point
- *
- * @param args
- * Command-line arguments
- * @throws NoSuchObjectException
- */
- public static void main(final String[] args) {
- final PuppeTorSlaveProgram slave = new PuppeTorSlaveProgram();
- while(true) {
- while (slave.connectToMaster() == false) {
- try {
- Thread.sleep(60000);
- } catch (final InterruptedException e) {
- throw new RuntimeException("Bug: Nothing should " +
- "interrupt us here!");
- }
- }
-
- final Thread taskGetter = new Thread(new Runnable() {
- public void run() {
- while (true) {
- try {
- try {
- // XXX I dislike the following lines, but
- // interruption doesn't work while we wait for the
- // master. Maybe there is a better solution that
- // doesn't eat the poison pill twice. -SH
- Task task = AbstractSlaveFactory.getMaster()
- .getNewTask();
- tasks.put(task);
- if (task instanceof TerminateTask) {
- break;
- }
- } catch (final RemoteException e) {
- // Empty the task queue - we cannot send any results
- // back, anyways.
- tasks.clear();
- // A taskid of 0 indicates a local Task
- tasks.put(new TerminateTask(0,
- "local termination"));
- Thread.currentThread().interrupt();
- }
- } catch (final InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- if (Thread.interrupted()) {
- break;
- }
-
- }
- }
- });
-
- taskGetter.start();
- // XXX We use just a single Thread here. That isn't the smartest move.
- // -SH
- try {
- while (true) {
- final Task newTask = tasks.take();
- newTask.execute();
- if (Thread.interrupted()) {
- break;
- }
- }
- } catch (final InterruptedException ignored) {} catch (final RemoteException ignored) {}
- taskGetter.interrupt();
- AbstractSlaveFactory.setMaster(null);
- // We don't shut down, but want the Master to see we disconnected,
- // so hopefully a gc will happen soon.
- System.gc();
- }
-
- }
-
- /**
- * Private constructor to set up RMI-related Java-internal variables.
- */
- private PuppeTorSlaveProgram() {
- /*
- * Set the location of the keystore where your private certificate is.
- */
- System.setProperty("javax.net.ssl.keyStore", "res/keystore");
- /*
- * Set the password for your keystore.
- */
- System.setProperty("javax.net.ssl.keyStorePassword", "pleasechange");
- /*
- * Set the location of the truststore which contains the exported
- * certificates of your slaves
- */
- System.setProperty("javax.net.ssl.trustStore", "res/truststore");
- // Set up the factories we want to use
- AbstractSlaveFactory.initialize(new SlaveImplFactory());
- final AbstractSlaveFactory fac = AbstractSlaveFactory.getInstance();
-
- /*
- * Create a new slave with the properties that are relevant for the
- * computer and networking environment it runs on.
- * XXX unused for now -SH
- */
- final Set<Integer> ports = new HashSet<Integer>();
- /*for (int i = 10025; i < 20000; i++) {
- ports.add(i);
- }*/
- final Set<Integer> availableRevisions =
- new CopyOnWriteArraySet<Integer>();
- slave = fac.createSlave(slaveName, Slave.OS.UNDEFINED, myaddress,
- ports, availableRevisions);
-
- }
-
- /**
- * Attempt to make a connection to the master through RMI. If the master is
- * down, that is not a fatal condition, we want to keep trying until we can
- * reach it. Don't call this except from main().
- *
- * @return true if the connection was successful, false otherwise.
- */
- private boolean connectToMaster() {
- try {
- final Registry registry =
- LocateRegistry.getRegistry(serveraddress, serverport,
- new SslRMIClientSocketFactory());
- AbstractSlaveFactory.setMaster(((MasterConnector) registry
- .lookup("Master")).registerClient(slave));
- } catch (final NotBoundException e) {
- e.printStackTrace();
- System.out.println("We could connect, but the master has not "
- + "exported the Master Object yet." + e);
- return false;
- } catch (final RemoteException e) {
- return false;
- } catch (final IllegalArgumentException e) {
- throw new RuntimeException(
- "A slave with this name is already connected "
- + "to the server! " + e);
- }
- return true;
- }
+ /**
+ * The port the master server is supposed to listen on. This port must not
+ * be firewalled and must be forwarded to the machine if necessary. Use the
+ * same value as you used for the master's configuration.
+ */
+ final private static int serverport = 2050;
+
+ /**
+ * The address master server listens on. Use the same value as you used for
+ * the master's configuration. XXX Someone should check if this works with
+ * IPv6 -SH
+ */
+ final private static String serveraddress = "127.0.0.1";//78.47.18.109";
+
+ /**
+ * The address this slave listens on. Use 127.0.0.1 for slaves that do not
+ * open any ports for the outside world and thus can act as Tor clients
+ * only.
+ */
+ final private static String myaddress = "127.0.0.1";
+
+ /**
+ * Each slave is identified by its unique <code>slaveName</code>. Be
+ * careful to prevent naming collisions between slaves.
+ */
+ final private static String slaveName = "slave1";
+
+ /**
+ * A representation of this slave node to be sent to the master.
+ */
+ final private Slave slave;
+
+ final protected static BlockingQueue<Task> tasks =
+ new LinkedBlockingQueue<Task>();
+
+ /**
+ * Slave application entry point
+ *
+ * @param args
+ * Command-line arguments
+ * @throws NoSuchObjectException
+ */
+ public static void main(final String[] args) {
+ final PuppeTorSlaveProgram slave = new PuppeTorSlaveProgram();
+ while(true) {
+ while (slave.connectToMaster() == false) {
+ try {
+ Thread.sleep(60000);
+ } catch (final InterruptedException e) {
+ throw new RuntimeException("Bug: Nothing should " +
+ "interrupt us here!");
+ }
+ }
+
+ final Thread taskGetter = new Thread(new Runnable() {
+ public void run() {
+ while (true) {
+ try {
+ try {
+ // XXX I dislike the following lines, but
+ // interruption doesn't work while we wait for the
+ // master. Maybe there is a better solution that
+ // doesn't eat the poison pill twice. -SH
+ Task task = AbstractSlaveFactory.getMaster()
+ .getNewTask();
+ tasks.put(task);
+ if (task instanceof TerminateTask) {
+ break;
+ }
+ } catch (final RemoteException e) {
+ // Empty the task queue - we cannot send any results
+ // back, anyways.
+ tasks.clear();
+ // A taskid of 0 indicates a local Task
+ tasks.put(new TerminateTask(0,
+ "local termination"));
+ Thread.currentThread().interrupt();
+ }
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (Thread.interrupted()) {
+ break;
+ }
+ }
+ }
+ });
+
+ taskGetter.start();
+ // XXX We use just a single Thread here. That isn't the smartest move.
+ // -SH
+ try {
+ while (true) {
+ final Task newTask = tasks.take();
+ newTask.execute();
+ if (Thread.interrupted()) {
+ break;
+ }
+ }
+ } catch (final InterruptedException ignored) {} catch (final RemoteException ignored) {}
+ taskGetter.interrupt();
+ AbstractSlaveFactory.setMaster(null);
+ // We don't shut down, but want the Master to see we disconnected,
+ // so hopefully a gc will happen soon.
+ System.gc();
+ }
+
+ }
+
+ /**
+ * Private constructor to set up RMI-related Java-internal variables.
+ */
+ private PuppeTorSlaveProgram() {
+ /*
+ * Set the location of the keystore where your private certificate is.
+ */
+ System.setProperty("javax.net.ssl.keyStore", "res/keystore");
+ /*
+ * Set the password for your keystore.
+ */
+ System.setProperty("javax.net.ssl.keyStorePassword", "pleasechange");
+ /*
+ * Set the location of the truststore which contains the exported
+ * certificates of your slaves
+ */
+ System.setProperty("javax.net.ssl.trustStore", "res/truststore");
+ // Set up the factories we want to use
+ AbstractSlaveFactory.initialize(new SlaveImplFactory());
+ final AbstractSlaveFactory fac = AbstractSlaveFactory.getInstance();
+
+ /*
+ * Create a new slave with the properties that are relevant for the
+ * computer and networking environment it runs on.
+ * XXX unused for now -SH
+ */
+ final Set<Integer> ports = new HashSet<Integer>();
+ /*for (int i = 10025; i < 20000; i++) {
+ ports.add(i);
+ }*/
+ final Set<Integer> availableRevisions =
+ new CopyOnWriteArraySet<Integer>();
+ slave = fac.createSlave(slaveName, Slave.OS.UNDEFINED, myaddress,
+ ports, availableRevisions);
+
+ }
+
+ /**
+ * Attempt to make a connection to the master through RMI. If the master is
+ * down, that is not a fatal condition, we want to keep trying until we can
+ * reach it. Don't call this except from main().
+ *
+ * @return true if the connection was successful, false otherwise.
+ */
+ private boolean connectToMaster() {
+ try {
+ final Registry registry =
+ LocateRegistry.getRegistry(serveraddress, serverport,
+ new SslRMIClientSocketFactory());
+ AbstractSlaveFactory.setMaster(((MasterConnector) registry
+ .lookup("Master")).registerClient(slave));
+ } catch (final NotBoundException e) {
+ e.printStackTrace();
+ System.out.println("We could connect, but the master has not "
+ + "exported the Master Object yet." + e);
+ return false;
+ } catch (final RemoteException e) {
+ return false;
+ } catch (final IllegalArgumentException e) {
+ throw new RuntimeException(
+ "A slave with this name is already connected "
+ + "to the server! " + e);
+ }
+ return true;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/AbstractTaskImpl.java b/src/org/torproject/puppetor/rmi/impl/AbstractTaskImpl.java
index e63eb14..21d1d78 100644
--- a/src/org/torproject/puppetor/rmi/impl/AbstractTaskImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/AbstractTaskImpl.java
@@ -14,49 +14,49 @@ import org.torproject.puppetor.rmi.TaskResult;
public abstract class AbstractTaskImpl implements Task {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * A human-readable name for the task (to be included in log-messages, etc).
- */
- final protected String name;
-
- /**
- * The globally unique id for this task.
- */
- final protected int id;
-
- public AbstractTaskImpl(final int id, final String name) {
- this.name = name;
- this.id = id;
- }
-
- public int getId() {
- return id;
- }
-
- public abstract void execute() throws InterruptedException, RemoteException;
-
- protected void reportResult(final boolean success)
- throws InterruptedException, RemoteException {
- reportResult(new TaskResultImpl(success, this, null));
- }
-
- protected void reportResult(final boolean success, final String result)
- throws InterruptedException, RemoteException {
- reportResult(new TaskResultImpl(success, this, result));
- }
-
- // XXX protect against double-reporting of results -SH
- protected void reportResult( final TaskResult taskResult)
- throws InterruptedException, RemoteException {
- AbstractSlaveFactory.getMaster().reportTaskResult(taskResult);
- }
-
- public void addAdditionalInformation(
- Collection<String> additionalInformation) {}
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * A human-readable name for the task (to be included in log-messages, etc).
+ */
+ final protected String name;
+
+ /**
+ * The globally unique id for this task.
+ */
+ final protected int id;
+
+ public AbstractTaskImpl(final int id, final String name) {
+ this.name = name;
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public abstract void execute() throws InterruptedException, RemoteException;
+
+ protected void reportResult(final boolean success)
+ throws InterruptedException, RemoteException {
+ reportResult(new TaskResultImpl(success, this, null));
+ }
+
+ protected void reportResult(final boolean success, final String result)
+ throws InterruptedException, RemoteException {
+ reportResult(new TaskResultImpl(success, this, result));
+ }
+
+ // XXX protect against double-reporting of results -SH
+ protected void reportResult( final TaskResult taskResult)
+ throws InterruptedException, RemoteException {
+ AbstractSlaveFactory.getMaster().reportTaskResult(taskResult);
+ }
+
+ public void addAdditionalInformation(
+ Collection<String> additionalInformation) {}
}
diff --git a/src/org/torproject/puppetor/rmi/impl/AbstractTestImpl.java b/src/org/torproject/puppetor/rmi/impl/AbstractTestImpl.java
index 018fdc0..87757b9 100644
--- a/src/org/torproject/puppetor/rmi/impl/AbstractTestImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/AbstractTestImpl.java
@@ -13,40 +13,40 @@ import org.torproject.puppetor.rmi.TestExecutor;
/**
* Extend <code>AbstractTestImpl</code> for your own tests. Make sure you also add them
* to the TestRegistration.registerTest method.
- *
+ *
* @author Sebastian Hahn
*/
abstract public class AbstractTestImpl implements Test {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * A test description for log messages.
- */
- final private String description;
-
- /**
- * The network that must exist for the test to be executed.
- */
- final private NetworkDescription networkDescription;
-
- final protected TestExecutor exec;
-
- public AbstractTestImpl(final String description, final NetworkDescription network) {
- this.description = description;
- networkDescription = network;
- exec = AbstractMasterFactory.getInstance().
- getTestExecutorInstance();
- }
-
- public final NetworkDescription getNetworkDescription() {
- return networkDescription;
- }
-
- public String getDescription() {
- return description;
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * A test description for log messages.
+ */
+ final private String description;
+
+ /**
+ * The network that must exist for the test to be executed.
+ */
+ final private NetworkDescription networkDescription;
+
+ final protected TestExecutor exec;
+
+ public AbstractTestImpl(final String description, final NetworkDescription network) {
+ this.description = description;
+ networkDescription = network;
+ exec = AbstractMasterFactory.getInstance().
+ getTestExecutorInstance();
+ }
+
+ public final NetworkDescription getNetworkDescription() {
+ return networkDescription;
+ }
+
+ public String getDescription() {
+ return description;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/MasterImpl.java b/src/org/torproject/puppetor/rmi/impl/MasterImpl.java
index 5550486..c1df8f1 100644
--- a/src/org/torproject/puppetor/rmi/impl/MasterImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/MasterImpl.java
@@ -27,79 +27,79 @@ import org.torproject.puppetor.rmi.TaskResult;
* @author Sebastian Hahn
*/
public class MasterImpl extends UnicastRemoteObject implements LocalMaster,
- RemoteMaster, Master, Unreferenced {
-
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Store the reference to the connected slave
- */
- private final Slave slave;
-
- private final BlockingQueue<Task> tasks;
-
- private final BlockingQueue<TaskResult> completedTasks;
-
- private final Object completedTasksLock = new Object();
-
- public Slave getSlave() {
- return slave;
- }
-
- /**
- * Check the slave object for validity and save it for further reference
- *
- * @throws RemoteException
- * RMI
- */
- public MasterImpl(final Slave slave) throws RemoteException {
- if (slave.getName() == null) {
- throw new NullPointerException("The slave's name must not be null!");
- }
- this.slave = slave;
- tasks = new LinkedBlockingQueue<Task>();
- completedTasks = new LinkedBlockingQueue<TaskResult>();
- }
-
- public Task getNewTask() throws RemoteException, InterruptedException {
- return tasks.take();
- }
-
- public void reportTaskResult(final TaskResult task) throws RemoteException,
- InterruptedException {
- synchronized (completedTasksLock) {
- completedTasks.put(task);
- completedTasksLock.notifyAll();
- }
- }
-
- public TaskResult getTaskResult(final int taskId)
- throws InterruptedException {
-
- synchronized (completedTasksLock) {
- TaskResult res;
- while ((res = completedTasks.peek()) == null
- || res.getTask().getId() != taskId) {
- completedTasksLock.wait();
- }
- return completedTasks.take();
- }
- }
-
- /**
- * Remove the slave from the Map of slaves and destroy its workqueues.
- * Inform the TestExecutor that all still-running tests failed because the
- * slave went away.
- */
- public void unreferenced() {
- AbstractMasterFactory.getInstance().getTestExecutorInstance()
- .unregisterLocalMaster(this);
- }
-
- public void addTask(final Task task) {
- tasks.add(task);
- }
+ RemoteMaster, Master, Unreferenced {
+
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Store the reference to the connected slave
+ */
+ private final Slave slave;
+
+ private final BlockingQueue<Task> tasks;
+
+ private final BlockingQueue<TaskResult> completedTasks;
+
+ private final Object completedTasksLock = new Object();
+
+ public Slave getSlave() {
+ return slave;
+ }
+
+ /**
+ * Check the slave object for validity and save it for further reference
+ *
+ * @throws RemoteException
+ * RMI
+ */
+ public MasterImpl(final Slave slave) throws RemoteException {
+ if (slave.getName() == null) {
+ throw new NullPointerException("The slave's name must not be null!");
+ }
+ this.slave = slave;
+ tasks = new LinkedBlockingQueue<Task>();
+ completedTasks = new LinkedBlockingQueue<TaskResult>();
+ }
+
+ public Task getNewTask() throws RemoteException, InterruptedException {
+ return tasks.take();
+ }
+
+ public void reportTaskResult(final TaskResult task) throws RemoteException,
+ InterruptedException {
+ synchronized (completedTasksLock) {
+ completedTasks.put(task);
+ completedTasksLock.notifyAll();
+ }
+ }
+
+ public TaskResult getTaskResult(final int taskId)
+ throws InterruptedException {
+
+ synchronized (completedTasksLock) {
+ TaskResult res;
+ while ((res = completedTasks.peek()) == null
+ || res.getTask().getId() != taskId) {
+ completedTasksLock.wait();
+ }
+ return completedTasks.take();
+ }
+ }
+
+ /**
+ * Remove the slave from the Map of slaves and destroy its workqueues.
+ * Inform the TestExecutor that all still-running tests failed because the
+ * slave went away.
+ */
+ public void unreferenced() {
+ AbstractMasterFactory.getInstance().getTestExecutorInstance()
+ .unregisterLocalMaster(this);
+ }
+
+ public void addTask(final Task task) {
+ tasks.add(task);
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/MasterImplFactory.java b/src/org/torproject/puppetor/rmi/impl/MasterImplFactory.java
index f260982..d758785 100644
--- a/src/org/torproject/puppetor/rmi/impl/MasterImplFactory.java
+++ b/src/org/torproject/puppetor/rmi/impl/MasterImplFactory.java
@@ -21,36 +21,36 @@ import org.torproject.puppetor.rmi.tests.TestRegistration;
*/
public class MasterImplFactory extends AbstractMasterFactory {
- @Override
- public Master createMaster(final Slave slave) throws RemoteException {
- return new MasterImpl(slave);
- }
-
- @Override
- public TestExecutor getTestExecutorInstance() {
- return TestExecutorImpl.getInstance();
- }
-
- @Override
- public TestRegistration getTestRegistrationInstance() {
- return TestRegistration.getInstance();
- }
-
-/* @Override
- public Test createPublicNetworkTestForClientsOnly(final String description) {
- return null;
- return new AbstractTestImpl(description, new NetworkDescriptionImpl(1, 0, 0));
- }*/
-
- /*@Override
- public Network createNetwork(final String name) {
- return new NetworkImpl(name);
- }*/
-
- @Override
- public NetworkDescription createNetworkDescription() {
- // XXX implement -SH
- return null;
- }
+ @Override
+ public Master createMaster(final Slave slave) throws RemoteException {
+ return new MasterImpl(slave);
+ }
+
+ @Override
+ public TestExecutor getTestExecutorInstance() {
+ return TestExecutorImpl.getInstance();
+ }
+
+ @Override
+ public TestRegistration getTestRegistrationInstance() {
+ return TestRegistration.getInstance();
+ }
+
+/* @Override
+ public Test createPublicNetworkTestForClientsOnly(final String description) {
+ return null;
+ return new AbstractTestImpl(description, new NetworkDescriptionImpl(1, 0, 0));
+ }*/
+
+ /*@Override
+ public Network createNetwork(final String name) {
+ return new NetworkImpl(name);
+ }*/
+
+ @Override
+ public NetworkDescription createNetworkDescription() {
+ // XXX implement -SH
+ return null;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/NetworkDescriptionImpl.java b/src/org/torproject/puppetor/rmi/impl/NetworkDescriptionImpl.java
index e13614e..a148861 100644
--- a/src/org/torproject/puppetor/rmi/impl/NetworkDescriptionImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/NetworkDescriptionImpl.java
@@ -12,33 +12,33 @@ import org.torproject.puppetor.rmi.NetworkDescription;
public class NetworkDescriptionImpl implements NetworkDescription {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- private final AtomicInteger numProxies;
- private final AtomicInteger numRouters;
- private final AtomicInteger numDirectoryAuthorities;
-
- public int necessaryProxies() {
- return numProxies.get();
- }
-
- public int necessaryRouters() {
- return numRouters.get();
- }
-
- public int necessaryDirectoryAuthorities() {
- return numDirectoryAuthorities.get();
- }
-
- public NetworkDescriptionImpl(final int numProxies, final int numRouters,
- final int numDirectoryAuthorities) {
- this.numProxies = new AtomicInteger(numProxies);
- this.numRouters = new AtomicInteger(numRouters);
- this.numDirectoryAuthorities =
- new AtomicInteger(numDirectoryAuthorities);
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ private final AtomicInteger numProxies;
+ private final AtomicInteger numRouters;
+ private final AtomicInteger numDirectoryAuthorities;
+
+ public int necessaryProxies() {
+ return numProxies.get();
+ }
+
+ public int necessaryRouters() {
+ return numRouters.get();
+ }
+
+ public int necessaryDirectoryAuthorities() {
+ return numDirectoryAuthorities.get();
+ }
+
+ public NetworkDescriptionImpl(final int numProxies, final int numRouters,
+ final int numDirectoryAuthorities) {
+ this.numProxies = new AtomicInteger(numProxies);
+ this.numRouters = new AtomicInteger(numRouters);
+ this.numDirectoryAuthorities =
+ new AtomicInteger(numDirectoryAuthorities);
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/NetworkImpl.java b/src/org/torproject/puppetor/rmi/impl/NetworkImpl.java
index aa8fd01..5c69a42 100644
--- a/src/org/torproject/puppetor/rmi/impl/NetworkImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/NetworkImpl.java
@@ -20,107 +20,107 @@ import org.torproject.puppetor.rmi.TorInstance;
public class NetworkImpl implements Network {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The name of the network, so we can identify it in logs etc.
- */
- final private String name;
-
- /**
- * All the tests that will run with this network. The individual Tor
- * instances will have the tests they need to execute broken down further.
- */
- private final List<Test> tests;
-
- /**
- * All the Tor instances running at the slaves that are linked to this
- * network.
- */
- private final Set<TorInstance> torInstances;
-
- private final boolean privateNetwork;
-
- public NetworkImpl(final String name, boolean privateNetwork) {
- this.name = name;
- tests = new CopyOnWriteArrayList<Test>();
- torInstances = new CopyOnWriteArraySet<TorInstance>();
- this.privateNetwork = privateNetwork;
- }
-
- public void addTorInstance(final TorInstance torInstance) {
- torInstances.add(torInstance);
- }
-
- public String getName() {
- return name;
- }
-
- public void addTest(final Test test) {
- tests.add(test);
- }
-
- public Set<LocalMaster> getMasters() {
- final Set<LocalMaster> masters = new HashSet<LocalMaster>();
- for (final TorInstance torInstance : torInstances) {
- masters.add(torInstance.getMaster());
- }
- return Collections.unmodifiableSet(masters);
- }
-
- public Set<TorInstance> getDirectoryAuthorities() {
- final Set<TorInstance> authorities = new HashSet<TorInstance>();
- for (final TorInstance torInstance : torInstances) {
- if (torInstance.isDirectoryAuthority()) {
- authorities.add(torInstance);
- }
- }
- return Collections.unmodifiableSet(authorities);
- }
-
- public Set<TorInstance> getProxies() {
- return Collections.unmodifiableSet(torInstances);
- }
-
- public Set<TorInstance> getProxiesOnly() {
- final Set<TorInstance> proxies = new HashSet<TorInstance>();
- for (final TorInstance torInstance : torInstances) {
- if (!torInstance.isRouter()) {
- proxies.add(torInstance);
- }
- }
- return Collections.unmodifiableSet(proxies);
- }
-
- public Set<TorInstance> getRouters() {
- final Set<TorInstance> routers = new HashSet<TorInstance>();
- for (final TorInstance torInstance : torInstances) {
- if (!torInstance.isRouter()) {
- routers.add(torInstance);
- }
- }
- return Collections.unmodifiableSet(routers);
- }
-
- public Set<TorInstance> getRoutersOnly() {
- final Set<TorInstance> routers = new HashSet<TorInstance>();
- for (final TorInstance torInstance : torInstances) {
- if (torInstance.isRouter() && !torInstance.isDirectoryAuthority()) {
- routers.add(torInstance);
- }
- }
- return Collections.unmodifiableSet(routers);
- }
-
- public List<Test> getTests() {
- return Collections.unmodifiableList(tests);
- }
-
- public boolean isPrivateNetwork() {
- return privateNetwork;
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The name of the network, so we can identify it in logs etc.
+ */
+ final private String name;
+
+ /**
+ * All the tests that will run with this network. The individual Tor
+ * instances will have the tests they need to execute broken down further.
+ */
+ private final List<Test> tests;
+
+ /**
+ * All the Tor instances running at the slaves that are linked to this
+ * network.
+ */
+ private final Set<TorInstance> torInstances;
+
+ private final boolean privateNetwork;
+
+ public NetworkImpl(final String name, boolean privateNetwork) {
+ this.name = name;
+ tests = new CopyOnWriteArrayList<Test>();
+ torInstances = new CopyOnWriteArraySet<TorInstance>();
+ this.privateNetwork = privateNetwork;
+ }
+
+ public void addTorInstance(final TorInstance torInstance) {
+ torInstances.add(torInstance);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void addTest(final Test test) {
+ tests.add(test);
+ }
+
+ public Set<LocalMaster> getMasters() {
+ final Set<LocalMaster> masters = new HashSet<LocalMaster>();
+ for (final TorInstance torInstance : torInstances) {
+ masters.add(torInstance.getMaster());
+ }
+ return Collections.unmodifiableSet(masters);
+ }
+
+ public Set<TorInstance> getDirectoryAuthorities() {
+ final Set<TorInstance> authorities = new HashSet<TorInstance>();
+ for (final TorInstance torInstance : torInstances) {
+ if (torInstance.isDirectoryAuthority()) {
+ authorities.add(torInstance);
+ }
+ }
+ return Collections.unmodifiableSet(authorities);
+ }
+
+ public Set<TorInstance> getProxies() {
+ return Collections.unmodifiableSet(torInstances);
+ }
+
+ public Set<TorInstance> getProxiesOnly() {
+ final Set<TorInstance> proxies = new HashSet<TorInstance>();
+ for (final TorInstance torInstance : torInstances) {
+ if (!torInstance.isRouter()) {
+ proxies.add(torInstance);
+ }
+ }
+ return Collections.unmodifiableSet(proxies);
+ }
+
+ public Set<TorInstance> getRouters() {
+ final Set<TorInstance> routers = new HashSet<TorInstance>();
+ for (final TorInstance torInstance : torInstances) {
+ if (!torInstance.isRouter()) {
+ routers.add(torInstance);
+ }
+ }
+ return Collections.unmodifiableSet(routers);
+ }
+
+ public Set<TorInstance> getRoutersOnly() {
+ final Set<TorInstance> routers = new HashSet<TorInstance>();
+ for (final TorInstance torInstance : torInstances) {
+ if (torInstance.isRouter() && !torInstance.isDirectoryAuthority()) {
+ routers.add(torInstance);
+ }
+ }
+ return Collections.unmodifiableSet(routers);
+ }
+
+ public List<Test> getTests() {
+ return Collections.unmodifiableList(tests);
+ }
+
+ public boolean isPrivateNetwork() {
+ return privateNetwork;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/SlaveImpl.java b/src/org/torproject/puppetor/rmi/impl/SlaveImpl.java
index ca532b7..d930161 100644
--- a/src/org/torproject/puppetor/rmi/impl/SlaveImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/SlaveImpl.java
@@ -24,109 +24,109 @@ import org.torproject.puppetor.rmi.Slave;
*/
public final class SlaveImpl implements Slave {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The slave's name
- */
- protected final String name;
-
- /**
- * The slave's ip address
- */
- protected final InetAddress ip;
-
- /**
- * The operating system of the slave. See <code>Slave.OS</code>.
- */
- protected final OS os;
-
- /**
- * The ports this slave can open. Currently, we choose to use 256 as a
- * maximum that "should be" enough so we don't transfer so much data when
- * serializing. See the constructor. Make sure this is immutable.
- */
- protected final Set<Integer> ports;
-
- /**
- * The different revisions of Tor clients this slave can execute.
- */
- protected final Set<Integer> availableRevisions;
-
- /**
- * Create a new <code>Slave</code> with the metrics we currently use,
- * meaning it's operating system, it's IP, and the ports it can open. We may
- * in the future include other things like Tor executable version numbers
- * and the ability to run certain extra scripts.
- *
- * @param slaveName
- * the slave's name. Each slave must have it's own unique name in
- * a given PuppeTor network.
- * @param os
- * the slave's operating system.
- * @param ip
- * A String representation of the slave's IP (v4 or v6).
- * @param ports
- * All the ports this slave can open. Currently, we pick 256 out
- * of those at random.
- * @throws NullPointerException
- * if the slavename is null
- */
- public SlaveImpl(final String slaveName, final OS os, final String ip,
- final Set<Integer> ports, final Set<Integer> availableRevisions)
- throws NullPointerException {
- if (slaveName == null) {
- throw new NullPointerException("slaveName must not be null");
- }
- name = slaveName;
- this.os = os;
- try {
- this.ip = InetAddress.getByName(ip);
- } catch (final UnknownHostException e) {
- e.printStackTrace();
- throw new RuntimeException("You specified an invalid IP address!");
- }
-
- if (ports.size() > 256) {
- final Set<Integer> tmp = new CopyOnWriteArraySet<Integer>();
- int i = 0;
- for (final Integer j : tmp) {
- if (i++ == 256) {
- break;
- }
- tmp.add(j);
- }
- this.ports = Collections.unmodifiableSet(tmp);
- } else {
- this.ports =
- Collections
- .unmodifiableSet(new CopyOnWriteArraySet<Integer>(
- ports));
- }
- this.availableRevisions =
- Collections.unmodifiableSet(availableRevisions);
- }
-
- public String getName() {
- return name;
- }
-
- public OS getOS() {
- return os;
- }
-
- public InetAddress getIP() {
- return ip;
- }
-
- public Set<Integer> openablePorts() {
- return ports;
- }
-
- public Set<Integer> availableRevisions() {
- return availableRevisions;
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The slave's name
+ */
+ protected final String name;
+
+ /**
+ * The slave's ip address
+ */
+ protected final InetAddress ip;
+
+ /**
+ * The operating system of the slave. See <code>Slave.OS</code>.
+ */
+ protected final OS os;
+
+ /**
+ * The ports this slave can open. Currently, we choose to use 256 as a
+ * maximum that "should be" enough so we don't transfer so much data when
+ * serializing. See the constructor. Make sure this is immutable.
+ */
+ protected final Set<Integer> ports;
+
+ /**
+ * The different revisions of Tor clients this slave can execute.
+ */
+ protected final Set<Integer> availableRevisions;
+
+ /**
+ * Create a new <code>Slave</code> with the metrics we currently use,
+ * meaning it's operating system, it's IP, and the ports it can open. We may
+ * in the future include other things like Tor executable version numbers
+ * and the ability to run certain extra scripts.
+ *
+ * @param slaveName
+ * the slave's name. Each slave must have it's own unique name in
+ * a given PuppeTor network.
+ * @param os
+ * the slave's operating system.
+ * @param ip
+ * A String representation of the slave's IP (v4 or v6).
+ * @param ports
+ * All the ports this slave can open. Currently, we pick 256 out
+ * of those at random.
+ * @throws NullPointerException
+ * if the slavename is null
+ */
+ public SlaveImpl(final String slaveName, final OS os, final String ip,
+ final Set<Integer> ports, final Set<Integer> availableRevisions)
+ throws NullPointerException {
+ if (slaveName == null) {
+ throw new NullPointerException("slaveName must not be null");
+ }
+ name = slaveName;
+ this.os = os;
+ try {
+ this.ip = InetAddress.getByName(ip);
+ } catch (final UnknownHostException e) {
+ e.printStackTrace();
+ throw new RuntimeException("You specified an invalid IP address!");
+ }
+
+ if (ports.size() > 256) {
+ final Set<Integer> tmp = new CopyOnWriteArraySet<Integer>();
+ int i = 0;
+ for (final Integer j : tmp) {
+ if (i++ == 256) {
+ break;
+ }
+ tmp.add(j);
+ }
+ this.ports = Collections.unmodifiableSet(tmp);
+ } else {
+ this.ports =
+ Collections
+ .unmodifiableSet(new CopyOnWriteArraySet<Integer>(
+ ports));
+ }
+ this.availableRevisions =
+ Collections.unmodifiableSet(availableRevisions);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public OS getOS() {
+ return os;
+ }
+
+ public InetAddress getIP() {
+ return ip;
+ }
+
+ public Set<Integer> openablePorts() {
+ return ports;
+ }
+
+ public Set<Integer> availableRevisions() {
+ return availableRevisions;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/SlaveImplFactory.java b/src/org/torproject/puppetor/rmi/impl/SlaveImplFactory.java
index 0448d69..b5e7912 100644
--- a/src/org/torproject/puppetor/rmi/impl/SlaveImplFactory.java
+++ b/src/org/torproject/puppetor/rmi/impl/SlaveImplFactory.java
@@ -19,14 +19,14 @@ import org.torproject.puppetor.rmi.Slave.OS;
*/
public class SlaveImplFactory extends AbstractSlaveFactory {
- /**
- * @return a new <code>RemotePuppeTorImpl</code> instance.
- */
- @Override
- public Slave createSlave(final String slaveName, final OS os,
- final String ip, final Set<Integer> ports,
- final Set<Integer> availableRevisions) throws NullPointerException {
- return new SlaveImpl(slaveName, os, ip, ports, availableRevisions);
- }
+ /**
+ * @return a new <code>RemotePuppeTorImpl</code> instance.
+ */
+ @Override
+ public Slave createSlave(final String slaveName, final OS os,
+ final String ip, final Set<Integer> ports,
+ final Set<Integer> availableRevisions) throws NullPointerException {
+ return new SlaveImpl(slaveName, os, ip, ports, availableRevisions);
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/TaskResultImpl.java b/src/org/torproject/puppetor/rmi/impl/TaskResultImpl.java
index 2c66f9f..82ac6b5 100644
--- a/src/org/torproject/puppetor/rmi/impl/TaskResultImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/TaskResultImpl.java
@@ -10,42 +10,42 @@ import org.torproject.puppetor.rmi.TaskResult;
public class TaskResultImpl implements TaskResult {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The task this result is used for.
- */
- final private Task task;
-
- /**
- * Store the result of the <code>task</code>, or <code>null</code> if no
- * result is necessary.
- */
- final private String result;
-
- /**
- * Whether the task execution was successful.
- */
- final private boolean wasSuccessful;
-
- public TaskResultImpl(final boolean success, final Task task, final String result) {
- wasSuccessful = success;
- this.task = task;
- this.result = result;
- }
-
- public Task getTask() {
- return task;
- }
-
- public boolean wasSuccessful() {
- return wasSuccessful;
- }
-
- public String getTaskResult() {
- return result;
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The task this result is used for.
+ */
+ final private Task task;
+
+ /**
+ * Store the result of the <code>task</code>, or <code>null</code> if no
+ * result is necessary.
+ */
+ final private String result;
+
+ /**
+ * Whether the task execution was successful.
+ */
+ final private boolean wasSuccessful;
+
+ public TaskResultImpl(final boolean success, final Task task, final String result) {
+ wasSuccessful = success;
+ this.task = task;
+ this.result = result;
+ }
+
+ public Task getTask() {
+ return task;
+ }
+
+ public boolean wasSuccessful() {
+ return wasSuccessful;
+ }
+
+ public String getTaskResult() {
+ return result;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/TestExecutorImpl.java b/src/org/torproject/puppetor/rmi/impl/TestExecutorImpl.java
index ddf7065..86f59c3 100644
--- a/src/org/torproject/puppetor/rmi/impl/TestExecutorImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/TestExecutorImpl.java
@@ -53,503 +53,503 @@ import org.torproject.puppetor.rmi.tasks.TerminateTask;
*/
public final class TestExecutorImpl implements TestExecutor {
- /**
- * The TestExecutor instance that we'll use
- */
- private static final TestExecutor instance = new TestExecutorImpl();
-
- /**
- * Store all local representations of connections to slaves. Use the
- * slave's name as key.
- */
- private static final ConcurrentMap<String, LocalMaster> masters =
- new ConcurrentHashMap<String, LocalMaster>();
-
- /**
- * Store all registered tests until they are started.
- */
- private static final List<Test> newTests = new Vector<Test>();
-
- /**
- * Store all currently running tests.
- */
- // private static final List<Test> runningTests = new Vector<Test>();
- /**
- * Store all tests that cannot run because the slave's cannot build such a
- * network.
- */
- private static final Set<Test> cannotRunTests =
- new CopyOnWriteArraySet<Test>();
-
- /**
- * Store the networks that are created out of the NetworkDescriptions.
- */
- private static final Set<Network> networks =
- new CopyOnWriteArraySet<Network>();
-
- /**
- * Store the currently active network when executing a test. Null indicates
- * that either testing hasn't started yet, or is already finished.
- */
- private static Network currentNetwork = null;
-
- /**
- * Store all failed tests.
- */
- private static final Map<Test, TestResult> failedTests =
- new ConcurrentHashMap<Test, TestResult>();
-
- /**
- * Store all successfully completed tests.
- */
- private static final Map<Test, TestResult> successfulTests =
- new ConcurrentHashMap<Test, TestResult>();
-
- /**
- * Whether testing has started. This cannot be reset.
- */
- private static AtomicBoolean startedTesting = new AtomicBoolean(false);
-
- /**
- * Store the id for the next task. Every task gets its own unique id > 0. A
- * task id equal to 0 indicates that the task was created by the slave to
- * stop execution.
- */
- private static AtomicInteger nextTaskId = new AtomicInteger(1);
-
- /**
- * Singleton
- */
- private TestExecutorImpl() {}
-
- public static TestExecutor getInstance() {
- return instance;
- }
-
- public void registerLocalMaster(final LocalMaster master) {
- if (startedTesting.get() == true) {
- throw new RuntimeException("Bug: Testing has started already.");
- }
- System.out.println(master.getSlave().getName() + " registered");
- if (null != masters.putIfAbsent(master.getSlave().getName(), master)) {
- throw new IllegalArgumentException(master.getSlave().getName()
- + " has already registered with this Server");
- }
- }
-
- public void unregisterLocalMaster(final LocalMaster master) {
- // XXX Don't forget to mark all tests as failed that depended on this
- // slave if we have already started with testing-SH
- try {
- UnicastRemoteObject.unexportObject((RemoteMaster) master, true);
- } catch (final NoSuchObjectException e) {
- throw new RuntimeException(
- "This is a bug. The master should have been exported.");
- }
- if (masters.remove(master.getSlave().getName()) == null) {
- throw new RuntimeException(
- "This is a bug. unregisterLocalMaster must never be " +
- "called twice for the same master.");
- }
- }
-
- /**
- * Evaluate which tests can be run with the currently connected slaves.
- * Cancel all currently running tests and report them as failed if they
- * cannot be restarted with the new (reduced) set of connected slaves,
- * restart those tests otherwise. XXX This should be merged with
- * makeNetworks -SH
- */
- protected void evaluateNetwork() {
- if (startedTesting.get() == false) {
- throw new RuntimeException("Bug: Testing has not been started.");
- // XXX We need to actually check the network.-SH
- }
- }
-
- public void startTesting() {
- if (startedTesting.get() == true) {
- throw new RuntimeException("Bug: Testing has started already.");
- }
- startedTesting.set(true);
- // check which tests we can actually execute
- evaluateNetwork();
- for (final Test test : newTests) {
- makeNetworks(test);
- }
- // XXX cancelled networks will still appear here...=SH
- for (final Network nw : networks) {
- synchronized(TestExecutorImpl.class) {
- currentNetwork = nw;
- }
- try {
- executeTaskForMasters(nw.getMasters(),
- CreateNetworkTask.class, null, null);
- // The network has been created at the slaves. Set up
- // authorities, routers and proxies.
-
- Set<TaskResult> authorityResults =
- new CopyOnWriteArraySet<TaskResult>();
- executeTaskForTorInstances(nw.getDirectoryAuthorities(),
- CreateDirectoryAuthorityTask.class, authorityResults,
- null);
- executeTaskForTorInstances(nw.getRoutersOnly(),
- CreateRouterTask.class, null, null);
- executeTaskForTorInstances(nw.getProxiesOnly(),
- CreateProxyTask.class, null, null);
- if(nw.isPrivateNetwork()) {
- List<String> authorities = new LinkedList<String>();
- for(TaskResult result : authorityResults) {
- authorities.add(result.getTaskResult());
- }
- executeTaskForMasters(nw.getMasters(),
- ConfigureAsPrivateTask.class, null, authorities);
- }
- // Start the nodes ...
- executeTaskForMasters(nw.getMasters(), StartNodesTask.class,
- null, null);
- // ... and build circuits. This may take some time.
- executeTaskForMasters(nw.getMasters(), BuildCircuitsTask.class,
- null, null);
-
- // Start using the individual tests that were set up for this
- // network.
- for (final Test test : nw.getTests()) {
- test.doTest();
- }
-
- // We don't need the network anymore, make sure it's shut down
- // properly.
- executeTaskForMasters(nw.getMasters(), ShutdownNodesTask.class,
- null, null);
-
- } catch (final TaskExecutionNotSuccessfulException e) {
- e.printStackTrace();
- // XXX Log this properly. -SH
- }
-
- }
- // The terminate Task interrupts the slave's main process to
- // indicate that it should disconnect.
- synchronized(TestExecutorImpl.class) {
- currentNetwork = null;
- }
- try {
- executeTaskForMasters(masters.values(), TerminateTask.class, null,
- null);
- } catch (TaskExecutionNotSuccessfulException e) {
- e.printStackTrace();
- // XXX Log this properly. -SH
- }
- }
-
- //XXX This method and the next look very similar. See what we can do. -SH
- public void executeTaskForMasters(final Collection<LocalMaster> masters,
- final Class<? extends Task> taskClass,
- final Set<TaskResult> taskResults,
- Collection<String> additionalInformation)
- throws TaskExecutionNotSuccessfulException {
-
- if (masters.isEmpty()) {
- return;
- }
- final Set<MasterTask> mTasks = new HashSet<MasterTask>();
- Constructor<? extends Task> ctor = null;
- try {
- ctor = taskClass.getConstructor(int.class, String.class);
- String networkName = "";
- synchronized(TestExecutorImpl.class) {
- if(currentNetwork == null) {
- networkName = "";
- } else {
- networkName = currentNetwork.getName();
- }
- }
- for (final LocalMaster master : masters) {
- Task task = ctor.newInstance(
- nextTaskId.getAndIncrement(), networkName);
- task.addAdditionalInformation(additionalInformation);
- mTasks.add(new MasterTask(master, task));
- }
-
- final TaskManager man = new TaskManager(mTasks);
- final FutureTask<Boolean> futureTask =
- new FutureTask<Boolean>(man);
- new Thread(futureTask).start();
- try {
- if (futureTask.get() == false) {
- throw new TaskExecutionNotSuccessfulException(man
- .getTaskResults());
- }
- } catch (final InterruptedException e) {
- throw new TaskExecutionNotSuccessfulException(null);
- } catch (final ExecutionException e) {
- // XXX Log this with the cause. Should not happen. -SH
- e.printStackTrace();
- throw new TaskExecutionNotSuccessfulException(null);
- }
- if(taskResults != null) {
- taskResults.addAll(man.getTaskResults());
- }
- } catch (final SecurityException e) {
- throw new RuntimeException(
- "BUG: We're not using a security manager, so where " +
- "does this exception come from?");
- } catch (final NoSuchMethodException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Expected constructor undefined!");
- } catch (final IllegalArgumentException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Expected constructor undefined!");
- } catch (final InstantiationException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: InstantiationException.");
- } catch (final IllegalAccessException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Expected constructor undefined!");
- } catch (final InvocationTargetException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Constructor threw an exception.");
- }
- }
-
- public Network getCurrentNetwork() {
- synchronized(TestExecutorImpl.class) {
- if(currentNetwork == null) {
- throw new RuntimeException("There is no network currently!");
- }
- return currentNetwork;
- }
- }
-
- public void executeTaskForTorInstances(
- final Collection<TorInstance> torInstances,
- final Class<? extends Task> taskClass,
- final Set<TaskResult> taskResults,
- Collection<String> additionalInformation)
- throws TaskExecutionNotSuccessfulException {
-
- if (torInstances.isEmpty()) {
- return;
- }
- final Set<MasterTask> mTasks = new HashSet<MasterTask>();
- Constructor<? extends Task> ctor = null;
- try {
- ctor = taskClass.getConstructor(int.class, String.class,
- String.class);
- String networkName = "";
- synchronized(TestExecutorImpl.class) {
- if(currentNetwork == null) {
- networkName = "";
- } else {
- networkName = currentNetwork.getName();
- }
- }
- for (final TorInstance torInstance : torInstances) {
- Task task = ctor.newInstance(nextTaskId.getAndIncrement(),
- networkName, torInstance.getName());
- task.addAdditionalInformation(additionalInformation);
- mTasks.add(new MasterTask(torInstance.getMaster(), task));
- }
-
- final TaskManager man = new TaskManager(mTasks);
- final FutureTask<Boolean> futureTask =
- new FutureTask<Boolean>(man);
- new Thread(futureTask).start();
- try {
- if (futureTask.get() == false) {
- throw new TaskExecutionNotSuccessfulException(man
- .getTaskResults());
- }
- } catch (final InterruptedException e) {
- throw new TaskExecutionNotSuccessfulException(null);
- } catch (final ExecutionException e) {
- // XXX Log this with the cause. Should not happen. -SH
- e.printStackTrace();
- throw new TaskExecutionNotSuccessfulException(null);
- }
- if(taskResults != null) {
- taskResults.addAll(man.getTaskResults());
- }
- } catch (final SecurityException e) {
- throw new RuntimeException(
- "BUG: We're not using a security manager, " +
- "so where does this exception come from?");
- } catch (final NoSuchMethodException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Expected constructor undefined!");
- } catch (final IllegalArgumentException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Expected constructor undefined!");
- } catch (final InstantiationException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: InstantiationException.");
- } catch (final IllegalAccessException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Expected constructor undefined!");
- } catch (final InvocationTargetException e) {
- e.printStackTrace();
- throw new RuntimeException("BUG: Constructor threw an exception.");
- }
- }
-
- protected void makeNetworks(final Test test) {
- final NetworkDescription nd = test.getNetworkDescription();
- // XXX we want to do something much smarter here.-SH
-
- // XXX obviously, the following code adds the specified amount of
- // authorities, routers, and proxies for each slave, regardless of
- // capabilities. That isn't good. -SH
- for (final LocalMaster master : masters.values()) {
- int necessaryDirectoryAuthorities =
- nd.necessaryDirectoryAuthorities();
- boolean onPrivateNetwork = (necessaryDirectoryAuthorities > 0);
- // XXX the name choosing doesn't make sense. -SH
- final Network nw =
- new NetworkImpl(test.getDescription() + " slavename:"
- + master.getSlave().getName(), onPrivateNetwork);
- while (necessaryDirectoryAuthorities >= 1) {
- TorInstanceImpl authority = new TorInstanceImpl(master,
- "Authority" + necessaryDirectoryAuthorities);
- authority.setDirectoryAuthority(true);
- authority.setOnPrivateNetwork(onPrivateNetwork);
- nw.addTorInstance(authority);
- necessaryDirectoryAuthorities--;
- }
- int necessaryRouters = nd.necessaryRouters();
- while (necessaryRouters >= 1) {
- TorInstanceImpl router = new TorInstanceImpl(master, "Router" +
- necessaryRouters);
- router.setRouter(true);
- router.setOnPrivateNetwork(onPrivateNetwork);
- nw.addTorInstance(router);
- necessaryRouters--;
- }
- int necessaryProxies = nd.necessaryProxies();
- while (necessaryProxies >= 1) {
- TorInstanceImpl proxy = new TorInstanceImpl(master, "Proxy" +
- necessaryProxies);
- proxy.setOnPrivateNetwork(onPrivateNetwork);
- nw.addTorInstance(proxy);
- necessaryProxies--;
- }
- nw.addTest(test);
- networks.add(nw);
- }
- }
-
- public Map<Test, TestResult> getFailedTests() {
- return failedTests;
- }
-
- public Set<Test> getCannotRunTests() {
- return cannotRunTests;
- }
-
- public Map<Test, TestResult> getSuccessfulTests() {
- return successfulTests;
- }
-
- public void registerTest(final Test test) {
- if (startedTesting.get() == true) {
- throw new RuntimeException("Bug: Testing has started already.");
- }
- if (test == null) {
- throw new NullPointerException("tests must not be null");
- }
- newTests.add(test);
- }
-
- private static class TaskManager implements Callable<Boolean> {
-
- final private Set<TaskResult> taskResults =
- new CopyOnWriteArraySet<TaskResult>();
-
- final private Object taskResultsLock = new Object();
-
- final private Set<MasterTask> tasks;
-
- TaskManager(final Set<MasterTask> tasks) {
- if (tasks.isEmpty()) {
- throw new IllegalArgumentException("No tasks passed!");
- }
- this.tasks =
- Collections.synchronizedSet(
- new HashSet<MasterTask>(tasks));
- }
-
- public Boolean call() {
- for (final MasterTask task : tasks) {
- task.getMaster().addTask(task.getTask());
- // XXX Asking for trouble here. task could throw an exception!
- // -SH
- new Thread(new TaskCollector(task)).start();
- }
- try {
- synchronized (taskResultsLock) {
- // XXX See above. This needs more thinking -SH
- while (tasks.size() != taskResults.size()) {
- taskResultsLock.wait();
- }
- // XXX We want some logic here.-SH
- for (final TaskResult taskResult : taskResults) {
- if (!taskResult.wasSuccessful()) {
- return false;
- }
- }
- return true;
- }
- } catch (final InterruptedException e) {
- // XXX figure out a better solution here -SH
- e.printStackTrace();
- }
- return false;
- }
-
- public Set<TaskResult> getTaskResults() {
- return taskResults;
- }
-
- private class TaskCollector implements Runnable {
- private final MasterTask task;
-
- public void run() {
- try {
- final TaskResult taskResult =
- task.getMaster().getTaskResult(
- task.getTask().getId());
- synchronized (taskResultsLock) {
- taskResults.add(taskResult);
- taskResultsLock.notifyAll();
- }
- } catch (final InterruptedException e) {
- e.printStackTrace();
- Thread.currentThread().interrupt();
- }
-
- }
-
- protected TaskCollector(final MasterTask task) {
- this.task = task;
- }
- }
- }
-
- private static class MasterTask {
- final private LocalMaster master;
- final private Task task;
-
- MasterTask(final LocalMaster master, final Task task) {
- this.master = master;
- this.task = task;
- }
-
- public LocalMaster getMaster() {
- return master;
- }
-
- public Task getTask() {
- return task;
- }
- }
+ /**
+ * The TestExecutor instance that we'll use
+ */
+ private static final TestExecutor instance = new TestExecutorImpl();
+
+ /**
+ * Store all local representations of connections to slaves. Use the
+ * slave's name as key.
+ */
+ private static final ConcurrentMap<String, LocalMaster> masters =
+ new ConcurrentHashMap<String, LocalMaster>();
+
+ /**
+ * Store all registered tests until they are started.
+ */
+ private static final List<Test> newTests = new Vector<Test>();
+
+ /**
+ * Store all currently running tests.
+ */
+ // private static final List<Test> runningTests = new Vector<Test>();
+ /**
+ * Store all tests that cannot run because the slave's cannot build such a
+ * network.
+ */
+ private static final Set<Test> cannotRunTests =
+ new CopyOnWriteArraySet<Test>();
+
+ /**
+ * Store the networks that are created out of the NetworkDescriptions.
+ */
+ private static final Set<Network> networks =
+ new CopyOnWriteArraySet<Network>();
+
+ /**
+ * Store the currently active network when executing a test. Null indicates
+ * that either testing hasn't started yet, or is already finished.
+ */
+ private static Network currentNetwork = null;
+
+ /**
+ * Store all failed tests.
+ */
+ private static final Map<Test, TestResult> failedTests =
+ new ConcurrentHashMap<Test, TestResult>();
+
+ /**
+ * Store all successfully completed tests.
+ */
+ private static final Map<Test, TestResult> successfulTests =
+ new ConcurrentHashMap<Test, TestResult>();
+
+ /**
+ * Whether testing has started. This cannot be reset.
+ */
+ private static AtomicBoolean startedTesting = new AtomicBoolean(false);
+
+ /**
+ * Store the id for the next task. Every task gets its own unique id > 0. A
+ * task id equal to 0 indicates that the task was created by the slave to
+ * stop execution.
+ */
+ private static AtomicInteger nextTaskId = new AtomicInteger(1);
+
+ /**
+ * Singleton
+ */
+ private TestExecutorImpl() {}
+
+ public static TestExecutor getInstance() {
+ return instance;
+ }
+
+ public void registerLocalMaster(final LocalMaster master) {
+ if (startedTesting.get() == true) {
+ throw new RuntimeException("Bug: Testing has started already.");
+ }
+ System.out.println(master.getSlave().getName() + " registered");
+ if (null != masters.putIfAbsent(master.getSlave().getName(), master)) {
+ throw new IllegalArgumentException(master.getSlave().getName()
+ + " has already registered with this Server");
+ }
+ }
+
+ public void unregisterLocalMaster(final LocalMaster master) {
+ // XXX Don't forget to mark all tests as failed that depended on this
+ // slave if we have already started with testing-SH
+ try {
+ UnicastRemoteObject.unexportObject((RemoteMaster) master, true);
+ } catch (final NoSuchObjectException e) {
+ throw new RuntimeException(
+ "This is a bug. The master should have been exported.");
+ }
+ if (masters.remove(master.getSlave().getName()) == null) {
+ throw new RuntimeException(
+ "This is a bug. unregisterLocalMaster must never be " +
+ "called twice for the same master.");
+ }
+ }
+
+ /**
+ * Evaluate which tests can be run with the currently connected slaves.
+ * Cancel all currently running tests and report them as failed if they
+ * cannot be restarted with the new (reduced) set of connected slaves,
+ * restart those tests otherwise. XXX This should be merged with
+ * makeNetworks -SH
+ */
+ protected void evaluateNetwork() {
+ if (startedTesting.get() == false) {
+ throw new RuntimeException("Bug: Testing has not been started.");
+ // XXX We need to actually check the network.-SH
+ }
+ }
+
+ public void startTesting() {
+ if (startedTesting.get() == true) {
+ throw new RuntimeException("Bug: Testing has started already.");
+ }
+ startedTesting.set(true);
+ // check which tests we can actually execute
+ evaluateNetwork();
+ for (final Test test : newTests) {
+ makeNetworks(test);
+ }
+ // XXX cancelled networks will still appear here...=SH
+ for (final Network nw : networks) {
+ synchronized(TestExecutorImpl.class) {
+ currentNetwork = nw;
+ }
+ try {
+ executeTaskForMasters(nw.getMasters(),
+ CreateNetworkTask.class, null, null);
+ // The network has been created at the slaves. Set up
+ // authorities, routers and proxies.
+
+ Set<TaskResult> authorityResults =
+ new CopyOnWriteArraySet<TaskResult>();
+ executeTaskForTorInstances(nw.getDirectoryAuthorities(),
+ CreateDirectoryAuthorityTask.class, authorityResults,
+ null);
+ executeTaskForTorInstances(nw.getRoutersOnly(),
+ CreateRouterTask.class, null, null);
+ executeTaskForTorInstances(nw.getProxiesOnly(),
+ CreateProxyTask.class, null, null);
+ if(nw.isPrivateNetwork()) {
+ List<String> authorities = new LinkedList<String>();
+ for(TaskResult result : authorityResults) {
+ authorities.add(result.getTaskResult());
+ }
+ executeTaskForMasters(nw.getMasters(),
+ ConfigureAsPrivateTask.class, null, authorities);
+ }
+ // Start the nodes ...
+ executeTaskForMasters(nw.getMasters(), StartNodesTask.class,
+ null, null);
+ // ... and build circuits. This may take some time.
+ executeTaskForMasters(nw.getMasters(), BuildCircuitsTask.class,
+ null, null);
+
+ // Start using the individual tests that were set up for this
+ // network.
+ for (final Test test : nw.getTests()) {
+ test.doTest();
+ }
+
+ // We don't need the network anymore, make sure it's shut down
+ // properly.
+ executeTaskForMasters(nw.getMasters(), ShutdownNodesTask.class,
+ null, null);
+
+ } catch (final TaskExecutionNotSuccessfulException e) {
+ e.printStackTrace();
+ // XXX Log this properly. -SH
+ }
+
+ }
+ // The terminate Task interrupts the slave's main process to
+ // indicate that it should disconnect.
+ synchronized(TestExecutorImpl.class) {
+ currentNetwork = null;
+ }
+ try {
+ executeTaskForMasters(masters.values(), TerminateTask.class, null,
+ null);
+ } catch (TaskExecutionNotSuccessfulException e) {
+ e.printStackTrace();
+ // XXX Log this properly. -SH
+ }
+ }
+
+ //XXX This method and the next look very similar. See what we can do. -SH
+ public void executeTaskForMasters(final Collection<LocalMaster> masters,
+ final Class<? extends Task> taskClass,
+ final Set<TaskResult> taskResults,
+ Collection<String> additionalInformation)
+ throws TaskExecutionNotSuccessfulException {
+
+ if (masters.isEmpty()) {
+ return;
+ }
+ final Set<MasterTask> mTasks = new HashSet<MasterTask>();
+ Constructor<? extends Task> ctor = null;
+ try {
+ ctor = taskClass.getConstructor(int.class, String.class);
+ String networkName = "";
+ synchronized(TestExecutorImpl.class) {
+ if(currentNetwork == null) {
+ networkName = "";
+ } else {
+ networkName = currentNetwork.getName();
+ }
+ }
+ for (final LocalMaster master : masters) {
+ Task task = ctor.newInstance(
+ nextTaskId.getAndIncrement(), networkName);
+ task.addAdditionalInformation(additionalInformation);
+ mTasks.add(new MasterTask(master, task));
+ }
+
+ final TaskManager man = new TaskManager(mTasks);
+ final FutureTask<Boolean> futureTask =
+ new FutureTask<Boolean>(man);
+ new Thread(futureTask).start();
+ try {
+ if (futureTask.get() == false) {
+ throw new TaskExecutionNotSuccessfulException(man
+ .getTaskResults());
+ }
+ } catch (final InterruptedException e) {
+ throw new TaskExecutionNotSuccessfulException(null);
+ } catch (final ExecutionException e) {
+ // XXX Log this with the cause. Should not happen. -SH
+ e.printStackTrace();
+ throw new TaskExecutionNotSuccessfulException(null);
+ }
+ if(taskResults != null) {
+ taskResults.addAll(man.getTaskResults());
+ }
+ } catch (final SecurityException e) {
+ throw new RuntimeException(
+ "BUG: We're not using a security manager, so where " +
+ "does this exception come from?");
+ } catch (final NoSuchMethodException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Expected constructor undefined!");
+ } catch (final IllegalArgumentException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Expected constructor undefined!");
+ } catch (final InstantiationException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: InstantiationException.");
+ } catch (final IllegalAccessException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Expected constructor undefined!");
+ } catch (final InvocationTargetException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Constructor threw an exception.");
+ }
+ }
+
+ public Network getCurrentNetwork() {
+ synchronized(TestExecutorImpl.class) {
+ if(currentNetwork == null) {
+ throw new RuntimeException("There is no network currently!");
+ }
+ return currentNetwork;
+ }
+ }
+
+ public void executeTaskForTorInstances(
+ final Collection<TorInstance> torInstances,
+ final Class<? extends Task> taskClass,
+ final Set<TaskResult> taskResults,
+ Collection<String> additionalInformation)
+ throws TaskExecutionNotSuccessfulException {
+
+ if (torInstances.isEmpty()) {
+ return;
+ }
+ final Set<MasterTask> mTasks = new HashSet<MasterTask>();
+ Constructor<? extends Task> ctor = null;
+ try {
+ ctor = taskClass.getConstructor(int.class, String.class,
+ String.class);
+ String networkName = "";
+ synchronized(TestExecutorImpl.class) {
+ if(currentNetwork == null) {
+ networkName = "";
+ } else {
+ networkName = currentNetwork.getName();
+ }
+ }
+ for (final TorInstance torInstance : torInstances) {
+ Task task = ctor.newInstance(nextTaskId.getAndIncrement(),
+ networkName, torInstance.getName());
+ task.addAdditionalInformation(additionalInformation);
+ mTasks.add(new MasterTask(torInstance.getMaster(), task));
+ }
+
+ final TaskManager man = new TaskManager(mTasks);
+ final FutureTask<Boolean> futureTask =
+ new FutureTask<Boolean>(man);
+ new Thread(futureTask).start();
+ try {
+ if (futureTask.get() == false) {
+ throw new TaskExecutionNotSuccessfulException(man
+ .getTaskResults());
+ }
+ } catch (final InterruptedException e) {
+ throw new TaskExecutionNotSuccessfulException(null);
+ } catch (final ExecutionException e) {
+ // XXX Log this with the cause. Should not happen. -SH
+ e.printStackTrace();
+ throw new TaskExecutionNotSuccessfulException(null);
+ }
+ if(taskResults != null) {
+ taskResults.addAll(man.getTaskResults());
+ }
+ } catch (final SecurityException e) {
+ throw new RuntimeException(
+ "BUG: We're not using a security manager, " +
+ "so where does this exception come from?");
+ } catch (final NoSuchMethodException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Expected constructor undefined!");
+ } catch (final IllegalArgumentException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Expected constructor undefined!");
+ } catch (final InstantiationException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: InstantiationException.");
+ } catch (final IllegalAccessException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Expected constructor undefined!");
+ } catch (final InvocationTargetException e) {
+ e.printStackTrace();
+ throw new RuntimeException("BUG: Constructor threw an exception.");
+ }
+ }
+
+ protected void makeNetworks(final Test test) {
+ final NetworkDescription nd = test.getNetworkDescription();
+ // XXX we want to do something much smarter here.-SH
+
+ // XXX obviously, the following code adds the specified amount of
+ // authorities, routers, and proxies for each slave, regardless of
+ // capabilities. That isn't good. -SH
+ for (final LocalMaster master : masters.values()) {
+ int necessaryDirectoryAuthorities =
+ nd.necessaryDirectoryAuthorities();
+ boolean onPrivateNetwork = (necessaryDirectoryAuthorities > 0);
+ // XXX the name choosing doesn't make sense. -SH
+ final Network nw =
+ new NetworkImpl(test.getDescription() + " slavename:"
+ + master.getSlave().getName(), onPrivateNetwork);
+ while (necessaryDirectoryAuthorities >= 1) {
+ TorInstanceImpl authority = new TorInstanceImpl(master,
+ "Authority" + necessaryDirectoryAuthorities);
+ authority.setDirectoryAuthority(true);
+ authority.setOnPrivateNetwork(onPrivateNetwork);
+ nw.addTorInstance(authority);
+ necessaryDirectoryAuthorities--;
+ }
+ int necessaryRouters = nd.necessaryRouters();
+ while (necessaryRouters >= 1) {
+ TorInstanceImpl router = new TorInstanceImpl(master, "Router" +
+ necessaryRouters);
+ router.setRouter(true);
+ router.setOnPrivateNetwork(onPrivateNetwork);
+ nw.addTorInstance(router);
+ necessaryRouters--;
+ }
+ int necessaryProxies = nd.necessaryProxies();
+ while (necessaryProxies >= 1) {
+ TorInstanceImpl proxy = new TorInstanceImpl(master, "Proxy" +
+ necessaryProxies);
+ proxy.setOnPrivateNetwork(onPrivateNetwork);
+ nw.addTorInstance(proxy);
+ necessaryProxies--;
+ }
+ nw.addTest(test);
+ networks.add(nw);
+ }
+ }
+
+ public Map<Test, TestResult> getFailedTests() {
+ return failedTests;
+ }
+
+ public Set<Test> getCannotRunTests() {
+ return cannotRunTests;
+ }
+
+ public Map<Test, TestResult> getSuccessfulTests() {
+ return successfulTests;
+ }
+
+ public void registerTest(final Test test) {
+ if (startedTesting.get() == true) {
+ throw new RuntimeException("Bug: Testing has started already.");
+ }
+ if (test == null) {
+ throw new NullPointerException("tests must not be null");
+ }
+ newTests.add(test);
+ }
+
+ private static class TaskManager implements Callable<Boolean> {
+
+ final private Set<TaskResult> taskResults =
+ new CopyOnWriteArraySet<TaskResult>();
+
+ final private Object taskResultsLock = new Object();
+
+ final private Set<MasterTask> tasks;
+
+ TaskManager(final Set<MasterTask> tasks) {
+ if (tasks.isEmpty()) {
+ throw new IllegalArgumentException("No tasks passed!");
+ }
+ this.tasks =
+ Collections.synchronizedSet(
+ new HashSet<MasterTask>(tasks));
+ }
+
+ public Boolean call() {
+ for (final MasterTask task : tasks) {
+ task.getMaster().addTask(task.getTask());
+ // XXX Asking for trouble here. task could throw an exception!
+ // -SH
+ new Thread(new TaskCollector(task)).start();
+ }
+ try {
+ synchronized (taskResultsLock) {
+ // XXX See above. This needs more thinking -SH
+ while (tasks.size() != taskResults.size()) {
+ taskResultsLock.wait();
+ }
+ // XXX We want some logic here.-SH
+ for (final TaskResult taskResult : taskResults) {
+ if (!taskResult.wasSuccessful()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ } catch (final InterruptedException e) {
+ // XXX figure out a better solution here -SH
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ public Set<TaskResult> getTaskResults() {
+ return taskResults;
+ }
+
+ private class TaskCollector implements Runnable {
+ private final MasterTask task;
+
+ public void run() {
+ try {
+ final TaskResult taskResult =
+ task.getMaster().getTaskResult(
+ task.getTask().getId());
+ synchronized (taskResultsLock) {
+ taskResults.add(taskResult);
+ taskResultsLock.notifyAll();
+ }
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ Thread.currentThread().interrupt();
+ }
+
+ }
+
+ protected TaskCollector(final MasterTask task) {
+ this.task = task;
+ }
+ }
+ }
+
+ private static class MasterTask {
+ final private LocalMaster master;
+ final private Task task;
+
+ MasterTask(final LocalMaster master, final Task task) {
+ this.master = master;
+ this.task = task;
+ }
+
+ public LocalMaster getMaster() {
+ return master;
+ }
+
+ public Task getTask() {
+ return task;
+ }
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/impl/TorInstanceImpl.java b/src/org/torproject/puppetor/rmi/impl/TorInstanceImpl.java
index eba41fa..4fea8e9 100644
--- a/src/org/torproject/puppetor/rmi/impl/TorInstanceImpl.java
+++ b/src/org/torproject/puppetor/rmi/impl/TorInstanceImpl.java
@@ -22,154 +22,154 @@ import org.torproject.puppetor.rmi.TorInstance;
*/
public class TorInstanceImpl implements TorInstance {
- /**
- * Saves configuration options in an "option value" format.
- */
- private final List<String> configuration = new LinkedList<String>();
-
- /**
- * The name of this node.
- */
- private final String name;
-
- /**
- * The svn revision of the Tor build. 0 means no specified revision.
- */
- private final AtomicInteger revision = new AtomicInteger(0);
-
- /**
- * Whether we are a bridge authority.
- */
- private final AtomicBoolean bridgeAuthority = new AtomicBoolean(false);
-
- /**
- * Whether we are a directory authority.
- */
- final private AtomicBoolean directoryAuthority = new AtomicBoolean(false);
-
- /**
- * Whether we are an exit.
- */
- private final AtomicBoolean exit = new AtomicBoolean(false);
-
- /**
- * Whether we are a relay.
- */
- private final AtomicBoolean router = new AtomicBoolean(false);
-
- /**
- * Whether we are a bridge.
- */
- private final AtomicBoolean bridge = new AtomicBoolean(false);
-
- /**
- * Whether we are on a private network.
- */
- private AtomicBoolean privateNetwork = new AtomicBoolean(false);
-
- /**
- * Whether the configuration of the tor instance should be replaced by the
- * config returned from <code>this.getConfiguration()</code>.
- */
- private AtomicBoolean replaceConfiguration = new AtomicBoolean(false);
-
- /**
- * Provide a link to the slave where this torInstance will run.
- */
- private final LocalMaster master;
-
- /**
- * @param master
- * the <code>LocalMaster</code> that represents the slave on which
- * this Tor instance is running.
- * @param name
- * A name to identify the node.
- * XXX think about duplicates, we need a unique name to identify the
- * node, but is it smart to use that name as the Tor proxy's name as
- * well? -SH
- */
- TorInstanceImpl(final LocalMaster master, final String name) {
- this.master = master;
- this.name = name;
- }
-
- public synchronized List<String> getConfiguration() {
- return Collections.unmodifiableList(configuration);
- }
-
- public synchronized void addConfiguration(List<String> newConfig) {
- configuration.addAll(newConfig);
- }
-
- public int getRevision() {
- return revision.get();
- }
-
- public void setRevision(final int revision) {
- this.revision.set(revision);
- }
-
- public boolean isBridgeAuthority() {
- return bridgeAuthority.get();
- }
-
- public void setBridgeAuthority(boolean isBridgeAuthority) {
- bridgeAuthority.set(isBridgeAuthority);
- }
-
- public boolean isDirectoryAuthority() {
- return directoryAuthority.get();
- }
-
- public void setDirectoryAuthority(boolean isDirectoryAuthority) {
- if(isDirectoryAuthority) {
- setRouter(true);
- }
- directoryAuthority.set(isDirectoryAuthority);
- }
-
- public boolean isExit() {
- return exit.get();
- }
-
- public boolean isRouter() {
- return router.get();
- }
-
- public void setRouter(boolean isRouter) {
- if(!isRouter) {
- setDirectoryAuthority(false);
- }
- router.set(isRouter);
- }
-
- public boolean isOnPrivateNetwork() {
- return privateNetwork.get();
- }
-
- public void setOnPrivateNetwork(boolean onPrivateNetwork) {
- privateNetwork.set(onPrivateNetwork);
- }
-
- public boolean shouldReplaceConfiguration() {
- return replaceConfiguration.get();
- }
-
- public void setShouldReplaceConfiguration(
- boolean shouldReplaceConfiguration) {
- replaceConfiguration.set(shouldReplaceConfiguration);
- }
-
- public boolean isBridge() {
- return bridge.get();
- }
-
- public LocalMaster getMaster() {
- return master;
- }
-
- public synchronized String getName() {
- return name;
- }
+ /**
+ * Saves configuration options in an "option value" format.
+ */
+ private final List<String> configuration = new LinkedList<String>();
+
+ /**
+ * The name of this node.
+ */
+ private final String name;
+
+ /**
+ * The svn revision of the Tor build. 0 means no specified revision.
+ */
+ private final AtomicInteger revision = new AtomicInteger(0);
+
+ /**
+ * Whether we are a bridge authority.
+ */
+ private final AtomicBoolean bridgeAuthority = new AtomicBoolean(false);
+
+ /**
+ * Whether we are a directory authority.
+ */
+ final private AtomicBoolean directoryAuthority = new AtomicBoolean(false);
+
+ /**
+ * Whether we are an exit.
+ */
+ private final AtomicBoolean exit = new AtomicBoolean(false);
+
+ /**
+ * Whether we are a relay.
+ */
+ private final AtomicBoolean router = new AtomicBoolean(false);
+
+ /**
+ * Whether we are a bridge.
+ */
+ private final AtomicBoolean bridge = new AtomicBoolean(false);
+
+ /**
+ * Whether we are on a private network.
+ */
+ private AtomicBoolean privateNetwork = new AtomicBoolean(false);
+
+ /**
+ * Whether the configuration of the tor instance should be replaced by the
+ * config returned from <code>this.getConfiguration()</code>.
+ */
+ private AtomicBoolean replaceConfiguration = new AtomicBoolean(false);
+
+ /**
+ * Provide a link to the slave where this torInstance will run.
+ */
+ private final LocalMaster master;
+
+ /**
+ * @param master
+ * the <code>LocalMaster</code> that represents the slave on which
+ * this Tor instance is running.
+ * @param name
+ * A name to identify the node.
+ * XXX think about duplicates, we need a unique name to identify the
+ * node, but is it smart to use that name as the Tor proxy's name as
+ * well? -SH
+ */
+ TorInstanceImpl(final LocalMaster master, final String name) {
+ this.master = master;
+ this.name = name;
+ }
+
+ public synchronized List<String> getConfiguration() {
+ return Collections.unmodifiableList(configuration);
+ }
+
+ public synchronized void addConfiguration(List<String> newConfig) {
+ configuration.addAll(newConfig);
+ }
+
+ public int getRevision() {
+ return revision.get();
+ }
+
+ public void setRevision(final int revision) {
+ this.revision.set(revision);
+ }
+
+ public boolean isBridgeAuthority() {
+ return bridgeAuthority.get();
+ }
+
+ public void setBridgeAuthority(boolean isBridgeAuthority) {
+ bridgeAuthority.set(isBridgeAuthority);
+ }
+
+ public boolean isDirectoryAuthority() {
+ return directoryAuthority.get();
+ }
+
+ public void setDirectoryAuthority(boolean isDirectoryAuthority) {
+ if(isDirectoryAuthority) {
+ setRouter(true);
+ }
+ directoryAuthority.set(isDirectoryAuthority);
+ }
+
+ public boolean isExit() {
+ return exit.get();
+ }
+
+ public boolean isRouter() {
+ return router.get();
+ }
+
+ public void setRouter(boolean isRouter) {
+ if(!isRouter) {
+ setDirectoryAuthority(false);
+ }
+ router.set(isRouter);
+ }
+
+ public boolean isOnPrivateNetwork() {
+ return privateNetwork.get();
+ }
+
+ public void setOnPrivateNetwork(boolean onPrivateNetwork) {
+ privateNetwork.set(onPrivateNetwork);
+ }
+
+ public boolean shouldReplaceConfiguration() {
+ return replaceConfiguration.get();
+ }
+
+ public void setShouldReplaceConfiguration(
+ boolean shouldReplaceConfiguration) {
+ replaceConfiguration.set(shouldReplaceConfiguration);
+ }
+
+ public boolean isBridge() {
+ return bridge.get();
+ }
+
+ public LocalMaster getMaster() {
+ return master;
+ }
+
+ public synchronized String getName() {
+ return name;
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/AccessGoogleTask.java b/src/org/torproject/puppetor/rmi/tasks/AccessGoogleTask.java
index e2dae7d..d866223 100644
--- a/src/org/torproject/puppetor/rmi/tasks/AccessGoogleTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/AccessGoogleTask.java
@@ -18,57 +18,57 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class AccessGoogleTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
- /**
- * The name of this tor node.
- */
- private final String nodeName;
-
- public AccessGoogleTask(final int id, final String networkName,
- final String nodeName) {
- super(id, networkName);
- this.nodeName = nodeName;
- }
+ /**
+ * The name of this tor node.
+ */
+ private final String nodeName;
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
-
- final ClientApplication client =
- network.createClient("client", "www.google.com", 80, network.getNode(nodeName)
- .getSocksPort());
+ public AccessGoogleTask(final int id, final String networkName,
+ final String nodeName) {
+ super(id, networkName);
+ this.nodeName = nodeName;
+ }
- // create event listener to listen for client application events
- final EventListener clientEventListener = new EventListener() {
-
- // remember time when request was sent
- //private long before;
-
- public void handleEvent(Event event) {
- if (event.getType() == ClientEventType.CLIENT_SENDING_REQUEST) {
- //before = System.currentTimeMillis();
- } else if (event.getType() == ClientEventType.CLIENT_REPLY_RECEIVED) {
- // XXX Log how long requests took, see whether we need this all -SH
- ;
- }
- }
- };
-
- // obtain reference to event manager to be able to respond to events
- final EventManager manager = network.getEventManager();
-
- manager.addEventListener(client.getClientApplicationName(),
- clientEventListener);
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
- // perform at most three request with a timeout of 20 seconds each
- client.startRequests(3, 20000, true);
-
- // block this thread as long as client requests are running, but don't wait forever.
- reportResult(manager.waitForAnyOccurence(client.getClientApplicationName(),
- ClientEventType.CLIENT_REQUESTS_PERFORMED, 75000));
- }
+ final ClientApplication client =
+ network.createClient("client", "www.google.com", 80, network.getNode(nodeName)
+ .getSocksPort());
+
+ // create event listener to listen for client application events
+ final EventListener clientEventListener = new EventListener() {
+
+ // remember time when request was sent
+ //private long before;
+
+ public void handleEvent(Event event) {
+ if (event.getType() == ClientEventType.CLIENT_SENDING_REQUEST) {
+ //before = System.currentTimeMillis();
+ } else if (event.getType() == ClientEventType.CLIENT_REPLY_RECEIVED) {
+ // XXX Log how long requests took, see whether we need this all -SH
+ ;
+ }
+ }
+ };
+
+ // obtain reference to event manager to be able to respond to events
+ final EventManager manager = network.getEventManager();
+
+ manager.addEventListener(client.getClientApplicationName(),
+ clientEventListener);
+
+ // perform at most three request with a timeout of 20 seconds each
+ client.startRequests(3, 20000, true);
+
+ // block this thread as long as client requests are running, but don't wait forever.
+ reportResult(manager.waitForAnyOccurence(client.getClientApplicationName(),
+ ClientEventType.CLIENT_REQUESTS_PERFORMED, 75000));
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/AddHiddenServiceTask.java b/src/org/torproject/puppetor/rmi/tasks/AddHiddenServiceTask.java
index cf206bb..7305c32 100644
--- a/src/org/torproject/puppetor/rmi/tasks/AddHiddenServiceTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/AddHiddenServiceTask.java
@@ -24,83 +24,83 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class AddHiddenServiceTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The name of this tor node.
- */
- private final String nodeName;
-
- public AddHiddenServiceTask(final int id, final String networkName,
- final String nodeName) {
- super(id, networkName);
- this.nodeName = nodeName;
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- ProxyNode node = network.getNode(nodeName);
- try {
- // add hidden service
- final HiddenService hidServ = node.addHiddenService("hidServ");
- node.writeConfiguration();
- node.hup();
- final EventManager manager = network.getEventManager();
-
- // wait for 6 minutes that the proxy has published its first RSD
- if (!manager.waitForAnyOccurence(node.getNodeName(),
- HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED,
- 6L * 60L * 1000L)) {
- // failed to publish an RSD
- reportResult(false);
- return;
- }
-
- // create server application
- final ServerApplication server =
- network.createServer("server", hidServ.getServicePort());
-
- // create client application, pick one of the nodes.
- // XXX fix this so we can choose which node we want. -SH
- Set<String> nodes = network.getAllNodes().keySet();
- String[] localNodeNames = new String[10];
- localNodeNames = nodes.toArray(localNodeNames);
- final ClientApplication client =
- network.createClient("client",
- hidServ.determineOnionAddress(), hidServ
- .getVirtualPort(), network.getNode(localNodeNames[0]).getSocksPort());
-
- // register event listener
- final EventListener clientAndServerEventListener = new EventListener() {
- public void handleEvent(Event event) {
- // XXX log -SH
- }
- };
- manager.addEventListener(client.getClientApplicationName(),
- clientAndServerEventListener);
- manager.addEventListener(server.getServerApplicationName(),
- clientAndServerEventListener);
-
- // start server
- server.startListening();
-
- // perform at most five request with a timeout of 45 seconds each
- client.startRequests(5, 45000, true);
-
- // wait for request to be performed
- manager.waitForAnyOccurence(client.getClientApplicationName(),
- ClientEventType.CLIENT_REQUESTS_PERFORMED);
- reportResult(true);
- } catch (final PuppeTorException e) {
- e.printStackTrace();
- reportResult(false);
- }
-
-
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The name of this tor node.
+ */
+ private final String nodeName;
+
+ public AddHiddenServiceTask(final int id, final String networkName,
+ final String nodeName) {
+ super(id, networkName);
+ this.nodeName = nodeName;
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ ProxyNode node = network.getNode(nodeName);
+ try {
+ // add hidden service
+ final HiddenService hidServ = node.addHiddenService("hidServ");
+ node.writeConfiguration();
+ node.hup();
+ final EventManager manager = network.getEventManager();
+
+ // wait for 6 minutes that the proxy has published its first RSD
+ if (!manager.waitForAnyOccurence(node.getNodeName(),
+ HiddenServiceEventType.BOB_DESC_PUBLISHED_RECEIVED,
+ 6L * 60L * 1000L)) {
+ // failed to publish an RSD
+ reportResult(false);
+ return;
+ }
+
+ // create server application
+ final ServerApplication server =
+ network.createServer("server", hidServ.getServicePort());
+
+ // create client application, pick one of the nodes.
+ // XXX fix this so we can choose which node we want. -SH
+ Set<String> nodes = network.getAllNodes().keySet();
+ String[] localNodeNames = new String[10];
+ localNodeNames = nodes.toArray(localNodeNames);
+ final ClientApplication client =
+ network.createClient("client",
+ hidServ.determineOnionAddress(), hidServ
+ .getVirtualPort(), network.getNode(localNodeNames[0]).getSocksPort());
+
+ // register event listener
+ final EventListener clientAndServerEventListener = new EventListener() {
+ public void handleEvent(Event event) {
+ // XXX log -SH
+ }
+ };
+ manager.addEventListener(client.getClientApplicationName(),
+ clientAndServerEventListener);
+ manager.addEventListener(server.getServerApplicationName(),
+ clientAndServerEventListener);
+
+ // start server
+ server.startListening();
+
+ // perform at most five request with a timeout of 45 seconds each
+ client.startRequests(5, 45000, true);
+
+ // wait for request to be performed
+ manager.waitForAnyOccurence(client.getClientApplicationName(),
+ ClientEventType.CLIENT_REQUESTS_PERFORMED);
+ reportResult(true);
+ } catch (final PuppeTorException e) {
+ e.printStackTrace();
+ reportResult(false);
+ }
+
+
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/BuildCircuitsTask.java b/src/org/torproject/puppetor/rmi/tasks/BuildCircuitsTask.java
index 85d0b86..58181df 100644
--- a/src/org/torproject/puppetor/rmi/tasks/BuildCircuitsTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/BuildCircuitsTask.java
@@ -15,27 +15,27 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class BuildCircuitsTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- public BuildCircuitsTask(final int id, final String networkName) {
- super(id, networkName);
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- try {
- if (!network.hupUntilUp(50, 10000)) {
- reportResult(false);
- }
- } catch (final PuppeTorException e) {
- e.printStackTrace();
- reportResult(false);
- }
- reportResult(true);
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ public BuildCircuitsTask(final int id, final String networkName) {
+ super(id, networkName);
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ try {
+ if (!network.hupUntilUp(50, 10000)) {
+ reportResult(false);
+ }
+ } catch (final PuppeTorException e) {
+ e.printStackTrace();
+ reportResult(false);
+ }
+ reportResult(true);
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/ConfigureAsPrivateTask.java b/src/org/torproject/puppetor/rmi/tasks/ConfigureAsPrivateTask.java
index 2c6aa20..462a921 100644
--- a/src/org/torproject/puppetor/rmi/tasks/ConfigureAsPrivateTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/ConfigureAsPrivateTask.java
@@ -18,33 +18,33 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class ConfigureAsPrivateTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- final List<String> authorityInformation = new LinkedList<String>();
-
- public ConfigureAsPrivateTask(final int id, final String networkName) {
- super(id, networkName);
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- network.configureAsPartOfPrivateNetwork(authorityInformation);
- try {
- network.writeConfigurations();
- reportResult(true);
- } catch (final PuppeTorException e) {
- e.printStackTrace();
- reportResult(false);
- }
- }
-
- @Override
- public void addAdditionalInformation(
- Collection<String> additionalInformation) {
- authorityInformation.addAll(additionalInformation);
- }
-}
\ No newline at end of file
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ final List<String> authorityInformation = new LinkedList<String>();
+
+ public ConfigureAsPrivateTask(final int id, final String networkName) {
+ super(id, networkName);
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ network.configureAsPartOfPrivateNetwork(authorityInformation);
+ try {
+ network.writeConfigurations();
+ reportResult(true);
+ } catch (final PuppeTorException e) {
+ e.printStackTrace();
+ reportResult(false);
+ }
+ }
+
+ @Override
+ public void addAdditionalInformation(
+ Collection<String> additionalInformation) {
+ authorityInformation.addAll(additionalInformation);
+ }
+}
diff --git a/src/org/torproject/puppetor/rmi/tasks/CreateDirectoryAuthorityTask.java b/src/org/torproject/puppetor/rmi/tasks/CreateDirectoryAuthorityTask.java
index e3bd07c..89eb437 100644
--- a/src/org/torproject/puppetor/rmi/tasks/CreateDirectoryAuthorityTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/CreateDirectoryAuthorityTask.java
@@ -16,33 +16,33 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class CreateDirectoryAuthorityTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The name of this Tor authority.
- */
- private final String authorityName;
-
- public CreateDirectoryAuthorityTask(final int id, final String networkName,
- final String authorityName) {
- super(id, networkName);
- this.authorityName = authorityName;
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- DirectoryNode node = network.createDirectory(authorityName);
- // write configuration of proxy node
- try {
- network.writeConfigurations();
- reportResult(true, node.getDirServerString());
- } catch (final PuppeTorException e) {
- e.printStackTrace();
- reportResult(false);
- }
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The name of this Tor authority.
+ */
+ private final String authorityName;
+
+ public CreateDirectoryAuthorityTask(final int id, final String networkName,
+ final String authorityName) {
+ super(id, networkName);
+ this.authorityName = authorityName;
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ DirectoryNode node = network.createDirectory(authorityName);
+ // write configuration of proxy node
+ try {
+ network.writeConfigurations();
+ reportResult(true, node.getDirServerString());
+ } catch (final PuppeTorException e) {
+ e.printStackTrace();
+ reportResult(false);
+ }
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/CreateNetworkTask.java b/src/org/torproject/puppetor/rmi/tasks/CreateNetworkTask.java
index 31fea77..d3246bb 100644
--- a/src/org/torproject/puppetor/rmi/tasks/CreateNetworkTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/CreateNetworkTask.java
@@ -13,19 +13,19 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class CreateNetworkTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- public CreateNetworkTask(final int id, final String name) {
- super(id, name);
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- NetworkFactory.createNetwork(name);
- reportResult(true);
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ public CreateNetworkTask(final int id, final String name) {
+ super(id, name);
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ NetworkFactory.createNetwork(name);
+ reportResult(true);
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/CreateProxyTask.java b/src/org/torproject/puppetor/rmi/tasks/CreateProxyTask.java
index 5f4f5c0..64b84b0 100644
--- a/src/org/torproject/puppetor/rmi/tasks/CreateProxyTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/CreateProxyTask.java
@@ -15,34 +15,34 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class CreateProxyTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The name of this tor proxy.
- */
- private final String proxyName;
-
- public CreateProxyTask(final int id, final String networkName,
- final String proxyName) {
- super(id, networkName);
- this.proxyName = proxyName;
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- network.createProxy(proxyName);
-
- // write configuration of proxy node
- try {
- network.writeConfigurations();
- reportResult(true);
- } catch (final PuppeTorException e) {
- e.printStackTrace();
- reportResult(false);
- }
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The name of this tor proxy.
+ */
+ private final String proxyName;
+
+ public CreateProxyTask(final int id, final String networkName,
+ final String proxyName) {
+ super(id, networkName);
+ this.proxyName = proxyName;
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ network.createProxy(proxyName);
+
+ // write configuration of proxy node
+ try {
+ network.writeConfigurations();
+ reportResult(true);
+ } catch (final PuppeTorException e) {
+ e.printStackTrace();
+ reportResult(false);
+ }
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/CreateRouterTask.java b/src/org/torproject/puppetor/rmi/tasks/CreateRouterTask.java
index 09b74cf..c328f7f 100644
--- a/src/org/torproject/puppetor/rmi/tasks/CreateRouterTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/CreateRouterTask.java
@@ -15,34 +15,34 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class CreateRouterTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The name of this router.
- */
- private final String routerName;
-
- public CreateRouterTask(final int id, final String networkName,
- final String routerName) {
- super(id, networkName);
- this.routerName = routerName;
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- network.createRouter(routerName);
- // write configuration of router node
- try {
- network.writeConfigurations();
- reportResult(true);
- } catch (final PuppeTorException e) {
- e.printStackTrace();
- reportResult(false);
- }
-
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The name of this router.
+ */
+ private final String routerName;
+
+ public CreateRouterTask(final int id, final String networkName,
+ final String routerName) {
+ super(id, networkName);
+ this.routerName = routerName;
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ network.createRouter(routerName);
+ // write configuration of router node
+ try {
+ network.writeConfigurations();
+ reportResult(true);
+ } catch (final PuppeTorException e) {
+ e.printStackTrace();
+ reportResult(false);
+ }
+
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/ShutdownNodesTask.java b/src/org/torproject/puppetor/rmi/tasks/ShutdownNodesTask.java
index 7837d5b..f50e0b5 100644
--- a/src/org/torproject/puppetor/rmi/tasks/ShutdownNodesTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/ShutdownNodesTask.java
@@ -15,24 +15,24 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class ShutdownNodesTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- public ShutdownNodesTask(final int id, final String name) {
- super(id, name);
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- try {
- network.shutdownNodes();
- reportResult(true);
- } catch (final PuppeTorException e) {
- reportResult(false);
- }
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ public ShutdownNodesTask(final int id, final String name) {
+ super(id, name);
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ try {
+ network.shutdownNodes();
+ reportResult(true);
+ } catch (final PuppeTorException e) {
+ reportResult(false);
+ }
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/StartNodesTask.java b/src/org/torproject/puppetor/rmi/tasks/StartNodesTask.java
index 1049cd5..abc1cd1 100644
--- a/src/org/torproject/puppetor/rmi/tasks/StartNodesTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/StartNodesTask.java
@@ -15,28 +15,28 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class StartNodesTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- public StartNodesTask(final int id, final String networkName) {
- super(id, networkName);
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- final Network network = NetworkFactory.getNetworkByName(name);
- try {
- if (!network.startNodes(5000)) {
- // failed to start the proxy
- reportResult(false);
- }
- } catch (final PuppeTorException e) {
- e.printStackTrace();
- reportResult(false);
- }
- reportResult(true);
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ public StartNodesTask(final int id, final String networkName) {
+ super(id, networkName);
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ final Network network = NetworkFactory.getNetworkByName(name);
+ try {
+ if (!network.startNodes(5000)) {
+ // failed to start the proxy
+ reportResult(false);
+ }
+ } catch (final PuppeTorException e) {
+ e.printStackTrace();
+ reportResult(false);
+ }
+ reportResult(true);
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tasks/TerminateTask.java b/src/org/torproject/puppetor/rmi/tasks/TerminateTask.java
index c2e1ac7..4aa194d 100644
--- a/src/org/torproject/puppetor/rmi/tasks/TerminateTask.java
+++ b/src/org/torproject/puppetor/rmi/tasks/TerminateTask.java
@@ -12,19 +12,19 @@ import org.torproject.puppetor.rmi.impl.AbstractTaskImpl;
public class TerminateTask extends AbstractTaskImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- public TerminateTask(final int id, final String name) {
- super(id, name);
- }
-
- @Override
- public void execute() throws InterruptedException, RemoteException {
- Thread.currentThread().interrupt();
- reportResult(true);
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ public TerminateTask(final int id, final String name) {
+ super(id, name);
+ }
+
+ @Override
+ public void execute() throws InterruptedException, RemoteException {
+ Thread.currentThread().interrupt();
+ reportResult(true);
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tests/AccessGoogleOverPublicTorNetwork.java b/src/org/torproject/puppetor/rmi/tests/AccessGoogleOverPublicTorNetwork.java
index 4eb6b8a..9391024 100644
--- a/src/org/torproject/puppetor/rmi/tests/AccessGoogleOverPublicTorNetwork.java
+++ b/src/org/torproject/puppetor/rmi/tests/AccessGoogleOverPublicTorNetwork.java
@@ -16,25 +16,25 @@ import org.torproject.puppetor.rmi.tasks.AccessGoogleTask;
public class AccessGoogleOverPublicTorNetwork extends AbstractTestImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- public AccessGoogleOverPublicTorNetwork() {
- super("Use the public Tor network to connect to google.com and wait" +
- " for a response", new NetworkDescriptionImpl(1, 0, 0));
- }
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
- public void doTest() {
- Network nw = exec.getCurrentNetwork();
- Set<TorInstance> proxies = nw.getProxies();
- try {
- exec.executeTaskForTorInstances(proxies, AccessGoogleTask.class, null, null);
- System.out.println("Accessing google succeeded");
- } catch (TaskExecutionNotSuccessfulException e) {
- System.out.println("Accessing google failed");
- // Log this properly, especially where we failed
- }
- }
-}
\ No newline at end of file
+ public AccessGoogleOverPublicTorNetwork() {
+ super("Use the public Tor network to connect to google.com and wait" +
+ " for a response", new NetworkDescriptionImpl(1, 0, 0));
+ }
+
+ public void doTest() {
+ Network nw = exec.getCurrentNetwork();
+ Set<TorInstance> proxies = nw.getProxies();
+ try {
+ exec.executeTaskForTorInstances(proxies, AccessGoogleTask.class, null, null);
+ System.out.println("Accessing google succeeded");
+ } catch (TaskExecutionNotSuccessfulException e) {
+ System.out.println("Accessing google failed");
+ // Log this properly, especially where we failed
+ }
+ }
+}
diff --git a/src/org/torproject/puppetor/rmi/tests/StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest.java b/src/org/torproject/puppetor/rmi/tests/StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest.java
index b11a7c3..3195270 100644
--- a/src/org/torproject/puppetor/rmi/tests/StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest.java
+++ b/src/org/torproject/puppetor/rmi/tests/StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest.java
@@ -16,26 +16,26 @@ import org.torproject.puppetor.rmi.tasks.AddHiddenServiceTask;
public class StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest extends
- AbstractTestImpl {
- /**
- * Required for serialization. Needs to change for new released versions.
- */
- private static final long serialVersionUID = 1L;
-
- public StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest() {
- super("Create a private Tor network, set up a hidden service, " +
- "and access it", new NetworkDescriptionImpl(1, 3, 2));
- }
-
- public void doTest() {
- Network nw = exec.getCurrentNetwork();
- Set<TorInstance> proxies = nw.getProxiesOnly();
- try {
- exec.executeTaskForTorInstances(proxies, AddHiddenServiceTask.class, null, null);
- System.out.println("Accessing the hidden service succeeded.");
- } catch (TaskExecutionNotSuccessfulException e) {
- System.out.println("Accessing the hidden service failed.");
- // Log this properly, especially where we failed
- }
- }
+ AbstractTestImpl {
+ /**
+ * Required for serialization. Needs to change for new released versions.
+ */
+ private static final long serialVersionUID = 1L;
+
+ public StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest() {
+ super("Create a private Tor network, set up a hidden service, " +
+ "and access it", new NetworkDescriptionImpl(1, 3, 2));
+ }
+
+ public void doTest() {
+ Network nw = exec.getCurrentNetwork();
+ Set<TorInstance> proxies = nw.getProxiesOnly();
+ try {
+ exec.executeTaskForTorInstances(proxies, AddHiddenServiceTask.class, null, null);
+ System.out.println("Accessing the hidden service succeeded.");
+ } catch (TaskExecutionNotSuccessfulException e) {
+ System.out.println("Accessing the hidden service failed.");
+ // Log this properly, especially where we failed
+ }
+ }
}
diff --git a/src/org/torproject/puppetor/rmi/tests/TestRegistration.java b/src/org/torproject/puppetor/rmi/tests/TestRegistration.java
index 0260fdd..85e100d 100644
--- a/src/org/torproject/puppetor/rmi/tests/TestRegistration.java
+++ b/src/org/torproject/puppetor/rmi/tests/TestRegistration.java
@@ -9,25 +9,25 @@ import org.torproject.puppetor.rmi.TestExecutor;
public class TestRegistration {
- private static TestRegistration instance = new TestRegistration();
-
- public void registerTests(TestExecutor testExecutor) {
- testExecutor.registerTest(new AccessGoogleOverPublicTorNetwork());
- testExecutor.registerTest(new
- StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest());
- }
-
- /**
- * Singleton
- */
- private TestRegistration() {}
-
- /**
- * @return
- * the <code>TestRegistration</code> instance.
- */
- public static TestRegistration getInstance() {
- return instance;
- }
+ private static TestRegistration instance = new TestRegistration();
+
+ public void registerTests(TestExecutor testExecutor) {
+ testExecutor.registerTest(new AccessGoogleOverPublicTorNetwork());
+ testExecutor.registerTest(new
+ StartingAndAccessingHiddenServiceOverPrivateTorNetworkTest());
+ }
+
+ /**
+ * Singleton
+ */
+ private TestRegistration() {}
+
+ /**
+ * @return
+ * the <code>TestRegistration</code> instance.
+ */
+ public static TestRegistration getInstance() {
+ return instance;
+ }
}
--
1.5.6.5