+ * Tor behaves as though it had just read each of the key-value pairs + * from its configuration file. Keywords with no corresponding values have + * their configuration values reset to their defaults. setConf is +- * all-or-nothing: if there is an error in any of the configuration settings, +- * Tor sets none of them. +- * ++ * all-or-nothing: if there is an error in any of the configuration ++ * settings, Tor sets none of them. ++ *
+ * When a configuration option takes multiple values, or when multiple +- * configuration keys form a context-sensitive group (see getConf below), then +- * setting any of the options in a setConf command is taken to reset all of +- * the others. For example, if two ORBindAddress values are configured, and a +- * command arrives containing a single ORBindAddress value, the new +- * command's value replaces the two old values. +- * ++ * configuration keys form a context-sensitive group (see getConf below), ++ * then setting any of the options in a setConf command is taken to reset ++ * all of the others. For example, if two ORBindAddress values are ++ * configured, and a command arrives containing a single ORBindAddress ++ * value, the new command's value replaces the two old values. ++ *
+ * To remove all settings for a given option entirely (and go back to its
+- * default value), include a String in kvList containing the key and no value.
++ * default value), include a String in kvList containing the key and
++ * no value.
+ */
+ public void setConf(Collection
+ * If an option appears multiple times in the configuration, all of its
+ * key-value pairs are returned in order.
+- *
++ *
+ * Some options are context-sensitive, and depend on other options with
+ * different keywords. These cannot be fetched directly. Currently there
+ * is only one such option: clients should use the "HiddenServiceOptions"
+ * virtual keyword to get all HiddenServiceDir, HiddenServicePort,
+ * HiddenServiceNodes, and HiddenServiceExcludeNodes option settings.
+ */
+- public List
+ * Any events not listed in the events are turned off; thus, calling
+- * setEvents with an empty events argument turns off all event reporting.
++ * setEvents with an empty events argument turns off all event
++ * reporting.
+ */
+ public void setEvents(List
+ * By default, the current Tor implementation trusts all local users, and
+- * the controller can authenticate itself by calling authenticate(new byte[0]).
+- *
+- * If the 'CookieAuthentication' option is true, Tor writes a "magic cookie"
+- * file named "control_auth_cookie" into its data directory. To authenticate,
+- * the controller must send the contents of this file in auth.
+- *
+- * If the 'HashedControlPassword' option is set, auth must contain the salted
+- * hash of a secret password. The salted hash is computed according to the
+- * S2K algorithm in RFC 2440 (OpenPGP), and prefixed with the s2k specifier.
+- * This is then encoded in hexadecimal, prefixed by the indicator sequence
+- * "16:".
+- *
++ * the controller can authenticate itself by calling
++ * authenticate(new byte[0]).
++ *
++ * If the 'CookieAuthentication' option is true, Tor writes a "magic
++ * cookie" file named "control_auth_cookie" into its data directory. To
++ * authenticate, the controller must send the contents of this file in
++ * auth.
++ *
++ * If the 'HashedControlPassword' option is set, auth must contain
++ * the salted hash of a secret password. The salted hash is computed
++ * according to the S2K algorithm in RFC 2440 (OpenPGP), and prefixed with
++ * the s2k specifier. This is then encoded in hexadecimal, prefixed by the
++ * indicator sequence "16:".
++ *
+ * You can generate the salt of a password by calling
+- * 'tor --hash-password
+ * To authenticate under this scheme, the controller sends Tor the original
+ * secret that was used to generate the password.
+ */
+@@ -476,7 +450,8 @@
+ sendAndWaitForResponse(cmd, null);
+ }
+
+- /** Instructs the server to write out its configuration options into its torrc.
++ /** Instructs the server to write out its configuration options into its
++ * torrc.
+ */
+ public void saveConf() throws IOException {
+ sendAndWaitForResponse("SAVECONF\r\n", null);
+@@ -503,234 +478,239 @@
+ public void shutdownTor(String signal) throws IOException {
+ String s = "SIGNAL " + signal + "\r\n";
+ Waiter w = new Waiter();
+- if (debugOutput != null)
+- debugOutput.print(">> "+s);
+- if (this.thread != null) {
+- this.thread.stopListening();
+- }
+- synchronized (waiters) {
++ if(debugOutput != null) debugOutput.print(">> " + s);
++ synchronized(waiters) {
+ output.write(s);
+ output.flush();
+ waiters.addLast(w); // Prevent react() from finding the list empty
+ }
+ }
+
+- /** Tells the Tor server that future SOCKS requests for connections to a set of original
+- * addresses should be replaced with connections to the specified replacement
+- * addresses. Each element of kvLines is a String of the form
+- * "old-address new-address". This function returns the new address mapping.
+- *
++ /** Tells the Tor server that future SOCKS requests for connections to a
++ * set of original addresses should be replaced with connections to the
++ * specified replacement addresses. Each element of kvLines is a
++ * String of the form "old-address new-address". This function returns the
++ * new address mapping.
++ *
+ * The client may decline to provide a body for the original address, and
+- * instead send a special null address ("0.0.0.0" for IPv4, "::0" for IPv6, or
+- * "." for hostname), signifying that the server should choose the original
+- * address itself, and return that address in the reply. The server
+- * should ensure that it returns an element of address space that is unlikely
+- * to be in actual use. If there is already an address mapped to the
+- * destination address, the server may reuse that mapping.
+- *
+- * If the original address is already mapped to a different address, the old
+- * mapping is removed. If the original address and the destination address
+- * are the same, the server removes any mapping in place for the original
+- * address.
+- *
+- * Mappings set by the controller last until the Tor process exits:
+- * they never expire. If the controller wants the mapping to last only
+- * a certain time, then it must explicitly un-map the address when that
+- * time has elapsed.
++ * instead send a special null address ("0.0.0.0" for IPv4, "::0" for IPv6,
++ * or "." for hostname), signifying that the server should choose the
++ * original address itself, and return that address in the reply. The
++ * server should ensure that it returns an element of address space that is
++ * unlikely to be in actual use. If there is already an address mapped to
++ * the destination address, the server may reuse that mapping.
++ *
++ * If the original address is already mapped to a different address, the
++ * old mapping is removed. If the original address and the destination
++ * address are the same, the server removes any mapping in place for the
++ * original address.
++ *
++ * Mappings set by the controller last until the Tor process exits: they
++ * never expire. If the controller wants the mapping to last only a certain
++ * time, then it must explicitly un-map the address when that time has
++ * elapsed.
+ */
+- public Map
+ * Recognized keys include:
+ *
++ * If successful, returns the Circuit ID of the (maybe newly created)
++ * circuit.
+ */
+ public String extendCircuit(String circID, String path) throws IOException {
+- List
++ * Each stream may be associated with at most one circuit, and multiple
++ * streams may share the same circuit. Streams can only be attached to
++ * completed circuits (that is, circuits that have sent a circuit status
++ * "BUILT" event or are listed as built in a getInfo circuit-status
++ * request).
++ *
+ * If circID is 0, responsibility for attaching the given stream is
+ * returned to Tor.
+- *
+- * By default, Tor automatically attaches streams to
+- * circuits itself, unless the configuration variable
+- * "__LeaveStreamsUnattached" is set to "1". Attempting to attach streams
+- * via TC when "__LeaveStreamsUnattached" is false may cause a race between
+- * Tor and the controller, as both attempt to attach streams to circuits.
++ *
++ * By default, Tor automatically attaches streams to circuits itself,
++ * unless the configuration variable "__LeaveStreamsUnattached" is set to
++ * "1". Attempting to attach streams via TC when
++ * "__LeaveStreamsUnattached" is false may cause a race between Tor and the
++ * controller, as both attempt to attach streams to circuits.
+ */
+ public void attachStream(String streamID, String circID)
+ throws IOException {
+- sendAndWaitForResponse("ATTACHSTREAM "+streamID+" "+circID+"\r\n", null);
++ String cmd = "ATTACHSTREAM " + streamID + " " + circID + "\r\n";
++ sendAndWaitForResponse(cmd, null);
+ }
+
+ /** Tells Tor about the server descriptor in desc.
+- *
++ *
+ * The descriptor, when parsed, must contain a number of well-specified
+ * fields, including fields for its nickname and identity.
+ */
+ // More documentation here on format of desc?
+ // No need for return value? control-spec.txt says reply is merely "250 OK" on success...
+ public String postDescriptor(String desc) throws IOException {
+- List
++ * To be sure that the modified address will be used, this event must be
++ * sent after a new stream event is received, and before attaching this
++ * stream to a circuit.
++ */
++ public void redirectStream(String streamID, String address)
++ throws IOException {
++ String cmd = "REDIRECTSTREAM " + streamID + " " + address + "\r\n";
++ sendAndWaitForResponse(cmd, null);
+ }
+
+ /** Tells Tor to close the stream identified by streamID.
+- * reason should be one of the Tor RELAY_END reasons given in tor-spec.txt, as a decimal:
++ * reason should be one of the Tor RELAY_END reasons given in
++ * tor-spec.txt, as a decimal:
+ *
+ *
+ */
+- public Map
+ *
+- *
+- * Tor may hold the stream open for a while to flush any data that is pending.
++ * Tor may hold the stream open for a while to flush any data that is
++ * pending.
+ */
+- public void closeStream(String streamID, byte reason)
+- throws IOException {
+- sendAndWaitForResponse("CLOSESTREAM "+streamID+" "+reason+"\r\n",null);
++ public void closeStream(String streamID, byte reason) throws IOException {
++ String cmd = "CLOSESTREAM " + streamID + " " + reason + "\r\n";
++ sendAndWaitForResponse(cmd, null);
+ }
+
+ /** Tells Tor to close the circuit identified by circID.
+- * If ifUnused is true, do not close the circuit unless it is unused.
++ * If ifUnused is true, do not close the circuit unless it is
++ * unused.
+ */
+- public void closeCircuit(String circID, boolean ifUnused) throws IOException {
+- sendAndWaitForResponse("CLOSECIRCUIT "+circID+
+- (ifUnused?" IFUNUSED":"")+"\r\n", null);
++ public void closeCircuit(String circID, boolean ifUnused)
++ throws IOException {
++ String cmd;
++ if(ifUnused) cmd = "CLOSECIRCUIT " + circID + " IFUNUSED\r\n";
++ else cmd = "CLOSECIRCUIT " + circID + "\r\n";
++ sendAndWaitForResponse(cmd, null);
+ }
+ }
+
+diff -Bbur jtorctl/net/freehaven/tor/control/TorControlError.java jtorctl-briar/net/freehaven/tor/control/TorControlError.java
+--- jtorctl/net/freehaven/tor/control/TorControlError.java 2013-04-24 16:46:08.000000000 +0100
++++ jtorctl-briar/net/freehaven/tor/control/TorControlError.java 2013-05-16 19:56:30.000000000 +0100
+@@ -2,13 +2,15 @@
+ // See LICENSE file for copying information
+ package net.freehaven.tor.control;
+
+-/**
+- * An exception raised when Tor tells us about an error.
+- */
+-public class TorControlError extends RuntimeException {
+- static final long serialVersionUID = 2;
++import java.io.IOException;
++
++/** An exception raised when Tor tells us about an error. */
++public class TorControlError extends IOException {
++
++ private static final long serialVersionUID = 2;
++
++ private final int errorType;
+
+- int errorType;
+ public TorControlError(int type, String s) {
+ super(s);
+ errorType = type;
+@@ -19,13 +23,13 @@
+ public int getErrorType() {
+ return errorType;
+ }
++
+ public String getErrorMsg() {
+ try {
+- if (errorType == -1)
+- return null;
++ if(errorType == -1) return null;
+ return TorControlCommands.ERROR_MSGS[errorType];
+- } catch (ArrayIndexOutOfBoundsException ex) {
+- return "Unrecongized error #"+errorType;
++ } catch(ArrayIndexOutOfBoundsException ex) {
++ return "Unrecongized error #" + errorType;
+ }
+ }
+ }
+diff -Bbur jtorctl/net/freehaven/tor/control/TorControlSyntaxError.java jtorctl-briar/net/freehaven/tor/control/TorControlSyntaxError.java
+--- jtorctl/net/freehaven/tor/control/TorControlSyntaxError.java 2013-04-24 16:46:08.000000000 +0100
++++ jtorctl-briar/net/freehaven/tor/control/TorControlSyntaxError.java 2013-05-16 19:56:30.000000000 +0100
+@@ -2,12 +2,15 @@
+ // See LICENSE file for copying information
+ package net.freehaven.tor.control;
+
+-/**
+- * An exception raised when Tor behaves in an unexpected way.
+- */
+-public class TorControlSyntaxError extends RuntimeException {
+- static final long serialVersionUID = 2;
++import java.io.IOException;
+
+- public TorControlSyntaxError(String s) { super(s); }
++/** An exception raised when Tor behaves in an unexpected way. */
++public class TorControlSyntaxError extends IOException {
++
++ private static final long serialVersionUID = 2;
++
++ public TorControlSyntaxError(String s) {
++ super(s);
++ }
+ }
+