From 12192aea4319f67d23b6ea5a01c255b11b3ebed8 Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Thu, 16 May 2013 20:02:48 +0100 Subject: [PATCH] Patched jtorctl so a control connection can be used by multiple threads. Various thread safety fixes, saner use of exceptions, and code reformatting. The Tor plugin now creates a single control connection at startup and closes it at shutdown. Fixes issue #3611962. --- briar-core/.classpath | 2 +- briar-core/libs/jtorctl-briar.jar | Bin 0 -> 15930 bytes briar-core/libs/jtorctl.jar | Bin 15567 -> 0 bytes .../libs/source/jtorctl-briar-source.jar | Bin 0 -> 19137 bytes briar-core/libs/source/jtorctl-source.jar | Bin 16208 -> 0 bytes .../net/sf/briar/plugins/tor/TorPlugin.java | 77 +- jtorctl.patch | 1686 +++++++++++++++++ 7 files changed, 1718 insertions(+), 47 deletions(-) create mode 100644 briar-core/libs/jtorctl-briar.jar delete mode 100644 briar-core/libs/jtorctl.jar create mode 100644 briar-core/libs/source/jtorctl-briar-source.jar delete mode 100644 briar-core/libs/source/jtorctl-source.jar create mode 100644 jtorctl.patch diff --git a/briar-core/.classpath b/briar-core/.classpath index c7e16820b1..770f9ed479 100644 --- a/briar-core/.classpath +++ b/briar-core/.classpath @@ -12,7 +12,7 @@ <classpathentry kind="lib" path="libs/bluecove-2.1.1-SNAPSHOT-briar.jar"/> <classpathentry kind="lib" path="libs/bluecove-gpl-2.1.1-SNAPSHOT.jar"/> <classpathentry kind="lib" path="libs/javax.inject.jar"/> - <classpathentry kind="lib" path="libs/jtorctl.jar" sourcepath="libs/source/jtorctl-source.jar"/> + <classpathentry kind="lib" path="/home/someone/workspace/prototype/briar-core/libs/jtorctl-briar.jar" sourcepath="libs/source/jtorctl-briar-source.jar"/> <classpathentry kind="lib" path="libs/jsocks.jar" sourcepath="libs/source/jsocks-source.jar"/> <classpathentry combineaccessrules="false" kind="src" path="/briar-api"/> <classpathentry kind="lib" path="/briar-api/libs/android.jar"/> diff --git a/briar-core/libs/jtorctl-briar.jar b/briar-core/libs/jtorctl-briar.jar new file mode 100644 index 0000000000000000000000000000000000000000..6e1dadeb3f2818337c46f4784c6e21c6f85006a3 GIT binary patch literal 15930 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 V`T^Jj0D$}WSbe0QX0~5{{XZUyP{IHJ literal 0 HcmV?d00001 diff --git a/briar-core/libs/jtorctl.jar b/briar-core/libs/jtorctl.jar deleted file mode 100644 index cf757254a690075e14efd36cb7e437d86abeb413..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15567 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 diff --git a/briar-core/libs/source/jtorctl-briar-source.jar b/briar-core/libs/source/jtorctl-briar-source.jar new file mode 100644 index 0000000000000000000000000000000000000000..082613caffc87c78850e27def7ea5aeb73f83fbf GIT binary patch literal 19137 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 literal 0 HcmV?d00001 diff --git a/briar-core/libs/source/jtorctl-source.jar b/briar-core/libs/source/jtorctl-source.jar deleted file mode 100644 index 1550912ea87917dc236fd11a23cd1301cc14b9fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16208 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 a_P^7Zf;1%59~AiCNAqu@4CMav?f(F9R)rA& diff --git a/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java b/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java index cdf0999a82..14e63cf70b 100644 --- a/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java +++ b/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java @@ -73,6 +73,8 @@ class TorPlugin implements DuplexPlugin, EventHandler { private volatile Process tor = null; private volatile int pid = -1; private volatile ServerSocket socket = null; + private volatile Socket controlSocket = null; + private volatile TorControlConnection controlConnection = null; TorPlugin(Executor pluginExecutor, Context appContext, ShutdownManager shutdownManager, DuplexPluginCallback callback, @@ -113,9 +115,8 @@ class TorPlugin implements DuplexPlugin, EventHandler { return false; } // Try to connect to an existing Tor process if there is one - Socket s; try { - s = new Socket("127.0.0.1", CONTROL_PORT); // FIXME: Never closed + controlSocket = new Socket("127.0.0.1", CONTROL_PORT); if(LOG.isLoggable(INFO)) LOG.info("Tor is already running"); } catch(IOException e) { // Install the binary, GeoIP database and config file if necessary @@ -168,7 +169,7 @@ class TorPlugin implements DuplexPlugin, EventHandler { return false; } // Now we should be able to connect to the new process - s = new Socket("127.0.0.1", CONTROL_PORT); // FIXME: Never closed + controlSocket = new Socket("127.0.0.1", CONTROL_PORT); } // Read the PID of the Tor process so we can kill it if necessary try { @@ -187,12 +188,11 @@ class TorPlugin implements DuplexPlugin, EventHandler { } }); // Open a control connection and authenticate using the cookie file - TorControlConnection control = new TorControlConnection(s); - control.launchThread(true); - control.authenticate(read(cookieFile)); + controlConnection = new TorControlConnection(controlSocket); + controlConnection.authenticate(read(cookieFile)); // Register to receive events from the Tor process - control.setEventHandler(this); - control.setEvents(Arrays.asList("NOTICE", "WARN", "ERR")); + controlConnection.setEventHandler(this); + controlConnection.setEvents(Arrays.asList("NOTICE", "WARN", "ERR")); running = true; // Bind a server socket to receive incoming hidden service connections pluginExecutor.execute(new Runnable() { @@ -306,6 +306,11 @@ class TorPlugin implements DuplexPlugin, EventHandler { } } + private void listFiles(File f) { + if(f.isDirectory()) for(File f1 : f.listFiles()) listFiles(f1); + else if(LOG.isLoggable(INFO)) LOG.info(f.getAbsolutePath()); + } + private byte[] read(File f) throws IOException { byte[] b = new byte[(int) f.length()]; FileInputStream in = new FileInputStream(f); @@ -376,17 +381,12 @@ class TorPlugin implements DuplexPlugin, EventHandler { CountDownLatch latch = new CountDownLatch(1); FileObserver obs = new WriteObserver(hostnameFile, latch); obs.startWatching(); - // Open a control connection and update the Tor config + // Use the control connection to update the Tor config List<String> config = Arrays.asList( "HiddenServiceDir " + torDirectory.getAbsolutePath(), "HiddenServicePort 80 127.0.0.1:" + port); - // FIXME: Socket isn't closed - Socket s = new Socket("127.0.0.1", CONTROL_PORT); - TorControlConnection control = new TorControlConnection(s); - control.launchThread(true); - control.authenticate(read(cookieFile)); - control.setConf(config); - control.saveConf(); + controlConnection.setConf(config); + controlConnection.saveConf(); // Wait for the hostname file to be created/updated if(!latch.await(HOSTNAME_TIMEOUT, MILLISECONDS)) { if(LOG.isLoggable(WARNING)) @@ -437,12 +437,14 @@ class TorPlugin implements DuplexPlugin, EventHandler { if(socket != null) tryToClose(socket); try { if(LOG.isLoggable(INFO)) LOG.info("Stopping Tor"); - // FIXME: Socket isn't closed - Socket s = new Socket("127.0.0.1", CONTROL_PORT); - TorControlConnection control = new TorControlConnection(s); - control.launchThread(true); - control.authenticate(read(cookieFile)); - control.shutdownTor("TERM"); + if(controlSocket == null) + controlSocket = new Socket("127.0.0.1", CONTROL_PORT); + if(controlConnection == null) { + controlConnection = new TorControlConnection(controlSocket); + controlConnection.authenticate(read(cookieFile)); + } + controlConnection.shutdownTor("TERM"); + controlSocket.close(); } catch(IOException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(INFO)) LOG.info("Killing Tor"); @@ -515,38 +517,21 @@ class TorPlugin implements DuplexPlugin, EventHandler { throw new UnsupportedOperationException(); } - private void listFiles(File f) { - if(f.isDirectory()) for(File f1 : f.listFiles()) listFiles(f1); - else if(LOG.isLoggable(INFO)) LOG.info(f.getAbsolutePath()); - } - - public void circuitStatus(String status, String circID, String path) { - if(LOG.isLoggable(INFO)) LOG.info("Circuit status"); - } + public void circuitStatus(String status, String circID, String path) {} - public void streamStatus(String status, String streamID, String target) { - if(LOG.isLoggable(INFO)) LOG.info("Stream status"); - } + public void streamStatus(String status, String streamID, String target) {} - public void orConnStatus(String status, String orName) { - if(LOG.isLoggable(INFO)) LOG.info("OR connection status"); - } + public void orConnStatus(String status, String orName) {} - public void bandwidthUsed(long read, long written) { - if(LOG.isLoggable(INFO)) LOG.info("Bandwidth used"); - } + public void bandwidthUsed(long read, long written) {} - public void newDescriptors(List<String> orList) { - if(LOG.isLoggable(INFO)) LOG.info("New descriptors"); - } + public void newDescriptors(List<String> orList) {} public void message(String severity, String msg) { - if(LOG.isLoggable(INFO)) LOG.info("Message: " + severity + " " + msg); + if(LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); } - public void unrecognized(String type, String msg) { - if(LOG.isLoggable(INFO)) LOG.info("Unrecognized"); - } + public void unrecognized(String type, String msg) {} private static class WriteObserver extends FileObserver { diff --git a/jtorctl.patch b/jtorctl.patch new file mode 100644 index 0000000000..f50af04820 --- /dev/null +++ b/jtorctl.patch @@ -0,0 +1,1686 @@ +diff -Bbur jtorctl/net/freehaven/tor/control/Bytes.java jtorctl-briar/net/freehaven/tor/control/Bytes.java +--- jtorctl/net/freehaven/tor/control/Bytes.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/Bytes.java 2013-05-16 19:56:30.000000000 +0100 +@@ -16,46 +16,43 @@ + /** Write the two-byte value in 's' into the byte array 'ba', starting at + * the index 'pos'. */ + public static void setU16(byte[] ba, int pos, short s) { +- ba[pos] = (byte)((s >> 8) & 0xff); +- ba[pos+1] = (byte)((s ) & 0xff); ++ ba[pos] = (byte) ((s >> 8) & 0xff); ++ ba[pos + 1] = (byte) (s & 0xff); + } + + /** Write the four-byte value in 'i' into the byte array 'ba', starting at + * the index 'pos'. */ + public static void setU32(byte[] ba, int pos, int i) { +- ba[pos] = (byte)((i >> 24) & 0xff); +- ba[pos+1] = (byte)((i >> 16) & 0xff); +- ba[pos+2] = (byte)((i >> 8) & 0xff); +- ba[pos+3] = (byte)((i ) & 0xff); ++ ba[pos] = (byte) ((i >> 24) & 0xff); ++ ba[pos + 1] = (byte) ((i >> 16) & 0xff); ++ ba[pos + 2] = (byte) ((i >> 8) & 0xff); ++ ba[pos + 3] = (byte) (i & 0xff); + } + + /** Return the four-byte value starting at index 'pos' within 'ba' */ + public static int getU32(byte[] ba, int pos) { +- return +- ((ba[pos ]&0xff)<<24) | +- ((ba[pos+1]&0xff)<<16) | +- ((ba[pos+2]&0xff)<< 8) | +- ((ba[pos+3]&0xff)); ++ return ((ba[pos] & 0xff) << 24) | ++ ((ba[pos + 1] & 0xff) << 16) | ++ ((ba[pos + 2] & 0xff) << 8) | ++ ((ba[pos + 3] & 0xff)); + } + + public static String getU32S(byte[] ba, int pos) { +- return String.valueOf( (getU32(ba,pos))&0xffffffffL ); ++ return String.valueOf((getU32(ba, pos)) & 0xffffffffL); + } + + /** Return the two-byte value starting at index 'pos' within 'ba' */ + public static int getU16(byte[] ba, int pos) { +- return +- ((ba[pos ]&0xff)<<8) | +- ((ba[pos+1]&0xff)); ++ return ((ba[pos] & 0xff) << 8) | ++ ((ba[pos + 1] & 0xff)); + } + + /** Return the string starting at position 'pos' of ba and extending + * until a zero byte or the end of the string. */ + public static String getNulTerminatedStr(byte[] ba, int pos) { +- int len, maxlen = ba.length-pos; +- for (len=0; len<maxlen; ++len) { +- if (ba[pos+len] == 0) +- break; ++ int len, maxlen = ba.length - pos; ++ for(len = 0; len < maxlen; ++len) { ++ if(ba[pos + len] == 0) break; + } + return new String(ba, pos, len); + } +@@ -64,18 +61,16 @@ + * Read bytes from 'ba' starting at 'pos', dividing them into strings + * along the character in 'split' and writing them into 'lst' + */ +- public static void splitStr(List<String> lst, byte[] ba, int pos, byte split) { +- while (pos < ba.length && ba[pos] != 0) { ++ public static void splitStr(List<String> lst, byte[] ba, int pos, ++ byte split) { ++ while(pos < ba.length && ba[pos] != 0) { + int len; +- for (len=0; pos+len < ba.length; ++len) { +- if (ba[pos+len] == 0 || ba[pos+len] == split) +- break; ++ for(len = 0; pos + len < ba.length; ++len) { ++ if(ba[pos + len] == 0 || ba[pos + len] == split) break; + } +- if (len>0) +- lst.add(new String(ba, pos, len)); ++ if(len > 0) lst.add(new String(ba, pos, len)); + pos += len; +- if (ba[pos] == split) +- ++pos; ++ if(ba[pos] == split) ++pos; + } + } + +@@ -86,11 +81,8 @@ + public static List<String> splitStr(List<String> lst, String str) { + // split string on spaces, include trailing/leading + String[] tokenArray = str.split(" ", -1); +- if (lst == null) { +- lst = Arrays.asList( tokenArray ); +- } else { +- lst.addAll( Arrays.asList( tokenArray ) ); +- } ++ if(lst == null) lst = Arrays.asList(tokenArray); ++ else lst.addAll(Arrays.asList(tokenArray)); + return lst; + } + +@@ -101,10 +93,10 @@ + + public static final String hex(byte[] ba) { + StringBuffer buf = new StringBuffer(); +- for (int i = 0; i < ba.length; ++i) { +- int b = (ba[i]) & 0xff; ++ for(int i = 0; i < ba.length; ++i) { ++ int b = ba[i] & 0xff; + buf.append(NYBBLES[b >> 4]); +- buf.append(NYBBLES[b&0x0f]); ++ buf.append(NYBBLES[b & 0x0f]); + } + return buf.toString(); + } +diff -Bbur jtorctl/net/freehaven/tor/control/ConfigEntry.java jtorctl-briar/net/freehaven/tor/control/ConfigEntry.java +--- jtorctl/net/freehaven/tor/control/ConfigEntry.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/ConfigEntry.java 2013-05-16 19:56:30.000000000 +0100 +@@ -4,6 +4,11 @@ + + /** A single key-value pair from Tor's configuration. */ + public class ConfigEntry { ++ ++ public final String key; ++ public final String value; ++ public final boolean is_default; ++ + public ConfigEntry(String k, String v) { + key = k; + value = v; +@@ -14,7 +20,4 @@ + value = ""; + is_default = true; + } +- public final String key; +- public final String value; +- public final boolean is_default; + } +diff -Bbur jtorctl/net/freehaven/tor/control/EventHandler.java jtorctl-briar/net/freehaven/tor/control/EventHandler.java +--- jtorctl/net/freehaven/tor/control/EventHandler.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/EventHandler.java 2013-05-16 19:56:30.000000000 +0100 +@@ -9,9 +9,10 @@ + * @see TorControlConnection#setEvents + */ + public interface EventHandler { ++ + /** +- * Invoked when a circuit's status has changed. +- * Possible values for <b>status</b> are: ++ * Invoked when a circuit's status has changed. Possible values for ++ * <b>status</b> are: + * <ul> + * <li>"LAUNCHED" : circuit ID assigned to new circuit</li> + * <li>"BUILT" : all hops finished, can now accept streams</li> +@@ -19,7 +20,6 @@ + * <li>"FAILED" : circuit closed (was not built)</li> + * <li>"CLOSED" : circuit closed (was built)</li> + * </ul> +- * + * <b>circID</b> is the alphanumeric identifier of the affected circuit, + * and <b>path</b> is a comma-separated list of alphanumeric ServerIDs. + */ +@@ -24,9 +24,10 @@ + * and <b>path</b> is a comma-separated list of alphanumeric ServerIDs. + */ + public void circuitStatus(String status, String circID, String path); ++ + /** +- * Invoked when a stream's status has changed. +- * Possible values for <b>status</b> are: ++ * Invoked when a stream's status has changed. Possible values for ++ * <b>status</b> are: + * <ul> + * <li>"NEW" : New request to connect</li> + * <li>"NEWRESOLVE" : New request to resolve an address</li> +@@ -37,7 +38,6 @@ + * <li>"CLOSED" : Stream closed</li> + * <li>"DETACHED" : Detached from circuit; still retriable.</li> + * </ul> +- * + * <b>streamID</b> is the alphanumeric identifier of the affected stream, + * and its <b>target</b> is specified as address:port. + */ +@@ -42,18 +42,21 @@ + * and its <b>target</b> is specified as address:port. + */ + public void streamStatus(String status, String streamID, String target); ++ + /** +- * Invoked when the status of a connection to an OR has changed. +- * Possible values for <b>status</b> are ["LAUNCHED" | "CONNECTED" | "FAILED" | "CLOSED"]. +- * <b>orName</b> is the alphanumeric identifier of the OR affected. ++ * Invoked when the status of a connection to an OR has changed. Possible ++ * values for <b>status</b> are ["LAUNCHED" | "CONNECTED" | "FAILED" | ++ * "CLOSED"]. <b>orName</b> is the alphanumeric identifier of the OR ++ * affected. + */ + public void orConnStatus(String status, String orName); ++ + /** +- * Invoked once per second. <b>read</b> and <b>written</b> are +- * the number of bytes read and written, respectively, in +- * the last second. ++ * Invoked once per second. <b>read</b> and <b>written</b> are the number ++ * of bytes read and written, respectively, in the last second. + */ + public void bandwidthUsed(long read, long written); ++ + /** + * Invoked whenever Tor learns about new ORs. The <b>orList</b> object + * contains the alphanumeric ServerIDs associated with the new ORs. +@@ -59,17 +62,18 @@ + * contains the alphanumeric ServerIDs associated with the new ORs. + */ + public void newDescriptors(java.util.List<String> orList); ++ + /** +- * Invoked when Tor logs a message. +- * <b>severity</b> is one of ["DEBUG" | "INFO" | "NOTICE" | "WARN" | "ERR"], +- * and <b>msg</b> is the message string. ++ * Invoked when Tor logs a message. <b>severity</b> is one of ["DEBUG" | ++ * "INFO" | "NOTICE" | "WARN" | "ERR"], and <b>msg</b> is the message ++ * string. + */ + public void message(String severity, String msg); ++ + /** +- * Invoked when an unspecified message is received. +- * <type> is the message type, and <msg> is the message string. ++ * Invoked when an unspecified message is received. <type> is the message ++ * type, and <msg> is the message string. + */ + public void unrecognized(String type, String msg); +- + } + +diff -Bbur jtorctl/net/freehaven/tor/control/examples/DebuggingEventHandler.java jtorctl-briar/net/freehaven/tor/control/examples/DebuggingEventHandler.java +--- jtorctl/net/freehaven/tor/control/examples/DebuggingEventHandler.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/examples/DebuggingEventHandler.java 2013-05-16 19:56:30.000000000 +0100 +@@ -3,42 +3,48 @@ + package net.freehaven.tor.control.examples; + + import java.io.PrintWriter; +-import java.util.Iterator; ++import java.util.List; ++ + import net.freehaven.tor.control.EventHandler; + + public class DebuggingEventHandler implements EventHandler { + +- protected PrintWriter out; ++ private final PrintWriter out; + +- public DebuggingEventHandler(PrintWriter p) { +- out = p; ++ public DebuggingEventHandler(PrintWriter out) { ++ this.out = out; + } + + public void circuitStatus(String status, String circID, String path) { +- out.println("Circuit "+circID+" is now "+status+" (path="+path+")"); ++ out.println("Circuit " + circID + " is now " + status + ++ " (path=" + path + ")"); + } ++ + public void streamStatus(String status, String streamID, String target) { +- out.println("Stream "+streamID+" is now "+status+" (target="+target+")"); ++ out.println("Stream " + streamID + " is now " + status + ++ " (target=" + target + ")"); + } ++ + public void orConnStatus(String status, String orName) { +- out.println("OR connection to "+orName+" is now "+status); ++ out.println("OR connection to " + orName + " is now " + status); + } ++ + public void bandwidthUsed(long read, long written) { +- out.println("Bandwidth usage: "+read+" bytes read; "+ +- written+" bytes written."); ++ out.println("Bandwidth usage: " + read + " bytes read; " + ++ written +" bytes written."); + } +- public void newDescriptors(java.util.List<String> orList) { ++ ++ public void newDescriptors(List<String> orList) { + out.println("New descriptors for routers:"); +- for (Iterator<String> i = orList.iterator(); i.hasNext(); ) +- out.println(" "+i.next()); ++ for(String or : orList) out.println(" " + or); + } ++ + public void message(String type, String msg) { +- out.println("["+type+"] "+msg.trim()); ++ out.println("[" + type + "] " + msg.trim()); + } + + public void unrecognized(String type, String msg) { +- out.println("unrecognized event ["+type+"] "+msg.trim()); ++ out.println("unrecognized event [" + type + "] " + msg.trim()); + } +- + } + +diff -Bbur jtorctl/net/freehaven/tor/control/examples/Main.java jtorctl-briar/net/freehaven/tor/control/examples/Main.java +--- jtorctl/net/freehaven/tor/control/examples/Main.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/examples/Main.java 2013-05-16 19:56:30.000000000 +0100 +@@ -2,59 +2,60 @@ + // See LICENSE file for copying information + package net.freehaven.tor.control.examples; + +-import net.freehaven.tor.control.*; +-import java.io.PrintWriter; ++import java.io.EOFException; + import java.io.IOException; ++import java.io.PrintWriter; ++import java.net.Socket; + import java.util.ArrayList; +-import java.util.List; + import java.util.Arrays; ++import java.util.List; + import java.util.Map; +-import java.util.Iterator; ++ ++import net.freehaven.tor.control.ConfigEntry; ++import net.freehaven.tor.control.PasswordDigest; ++import net.freehaven.tor.control.TorControlCommands; ++import net.freehaven.tor.control.TorControlConnection; ++import net.freehaven.tor.control.TorControlError; + + public class Main implements TorControlCommands { + + public static void main(String args[]) { +- if (args.length < 1) { ++ if(args.length < 1) { + System.err.println("No command given."); + return; + } + try { +- if (args[0].equals("set-config")) { ++ if(args[0].equals("set-config")) { + setConfig(args); +- } else if (args[0].equals("get-config")) { ++ } else if(args[0].equals("get-config")) { + getConfig(args); +- } else if (args[0].equals("get-info")) { ++ } else if(args[0].equals("get-info")) { + getInfo(args); +- } else if (args[0].equals("listen")) { ++ } else if(args[0].equals("listen")) { + listenForEvents(args); +- } else if (args[0].equals("signal")) { ++ } else if(args[0].equals("signal")) { + signal(args); +- } else if (args[0].equals("auth")) { ++ } else if(args[0].equals("auth")) { + authDemo(args); + } else { + System.err.println("Unrecognized command: "+args[0]); + } +- } catch (java.io.EOFException ex) { ++ } catch(EOFException ex) { + System.out.println("Control socket closed by Tor."); +- } catch (IOException ex) { +- System.err.println("IO exception when talking to Tor process: "+ ++ } catch(TorControlError ex) { ++ System.err.println("Error from Tor process: " + ++ ex + " [" + ex.getErrorMsg() + "]"); ++ } catch(IOException ex) { ++ System.err.println("IO exception when talking to Tor process: " + + ex); + ex.printStackTrace(System.err); +- } catch (TorControlError ex) { +- System.err.println("Error from Tor process: "+ +- ex+" ["+ex.getErrorMsg()+"]"); + } + } + + private static TorControlConnection getConnection(String[] args, +- boolean daemon) +- throws IOException { +- TorControlConnection conn = TorControlConnection.getConnection( +- new java.net.Socket("127.0.0.1", 9100)); +- //if (conn instanceof TorControlConnection1) { +- // System.err.println("Debugging"); +- // ((TorControlConnection1)conn).setDebugging(System.err); +- //} ++ boolean daemon) throws IOException { ++ Socket s = new Socket("127.0.0.1", 9100); ++ TorControlConnection conn = new TorControlConnection(s); + conn.launchThread(daemon); + conn.authenticate(new byte[0]); + return conn; +@@ -71,57 +72,52 @@ + ArrayList<String> lst = new ArrayList<String>(); + int i = 1; + boolean save = false; +- if (args[i].equals("-save")) { ++ if(args[i].equals("-save")) { + save = true; + ++i; + } +- for (; i < args.length; i +=2) { +- lst.add(args[i]+" "+args[i+1]); ++ for(; i < args.length; i +=2) { ++ lst.add(args[i] + " " + args[i + 1]); + } + conn.setConf(lst); +- if (save) { +- conn.saveConf(); +- } ++ if(save) conn.saveConf(); + } + + public static void getConfig(String[] args) throws IOException { + // Usage: get-config key key key + TorControlConnection conn = getConnection(args); +- List<ConfigEntry> lst = conn.getConf(Arrays.asList(args).subList(1,args.length)); +- for (Iterator<ConfigEntry> i = lst.iterator(); i.hasNext(); ) { +- ConfigEntry e = i.next(); +- System.out.println("KEY: "+e.key); +- System.out.println("VAL: "+e.value); ++ List<String> keys = Arrays.asList(args).subList(1, args.length); ++ List<ConfigEntry> lst = conn.getConf(keys); ++ for(ConfigEntry e : lst) { ++ System.out.println("KEY: " + e.key); ++ System.out.println("VAL: " + e.value); + } + } + + public static void getInfo(String[] args) throws IOException { + TorControlConnection conn = getConnection(args); +- Map<String,String> m = conn.getInfo(Arrays.asList(args).subList(1,args.length)); +- for (Iterator<Map.Entry<String, String>> i = m.entrySet().iterator(); i.hasNext(); ) { +- Map.Entry<String,String> e = i.next(); +- System.out.println("KEY: "+e.getKey()); +- System.out.println("VAL: "+e.getValue()); ++ List<String> keys = Arrays.asList(args).subList(1, args.length); ++ Map<String, String> m = conn.getInfo(keys); ++ for(Map.Entry<String, String> e : m.entrySet()) { ++ System.out.println("KEY: " + e.getKey()); ++ System.out.println("VAL: " + e.getValue()); + } + } + + public static void listenForEvents(String[] args) throws IOException { + // Usage: listen [circ|stream|orconn|bw|newdesc|info|notice|warn|error]* + TorControlConnection conn = getConnection(args, false); +- ArrayList<String> lst = new ArrayList<String>(); +- for (int i = 1; i < args.length; ++i) { +- lst.add(args[i]); +- } ++ List<String> events = Arrays.asList(args).subList(1, args.length); + conn.setEventHandler( + new DebuggingEventHandler(new PrintWriter(System.out, true))); +- conn.setEvents(lst); ++ conn.setEvents(events); + } + + public static void signal(String[] args) throws IOException { + // Usage signal [reload|shutdown|dump|debug|halt] + TorControlConnection conn = getConnection(args, false); + // distinguish shutdown signal from other signals +- if ("SHUTDOWN".equalsIgnoreCase(args[1]) ++ if("SHUTDOWN".equalsIgnoreCase(args[1]) + || "HALT".equalsIgnoreCase(args[1])) { + conn.shutdownTor(args[1].toUpperCase()); + } else { +@@ -130,17 +126,13 @@ + } + + public static void authDemo(String[] args) throws IOException { +- + PasswordDigest pwd = PasswordDigest.generateDigest(); +- java.net.Socket s = new java.net.Socket("127.0.0.1", 9100); +- TorControlConnection conn = TorControlConnection.getConnection(s); ++ Socket s = new Socket("127.0.0.1", 9100); ++ TorControlConnection conn = new TorControlConnection(s); + conn.launchThread(true); + conn.authenticate(new byte[0]); +- + conn.setConf("HashedControlPassword", pwd.getHashedPassword()); +- +- conn = TorControlConnection.getConnection( +- new java.net.Socket("127.0.0.1", 9100)); ++ conn = new TorControlConnection(new Socket("127.0.0.1", 9100)); + conn.launchThread(true); + conn.authenticate(pwd.getSecret()); + } +diff -Bbur jtorctl/net/freehaven/tor/control/PasswordDigest.java jtorctl-briar/net/freehaven/tor/control/PasswordDigest.java +--- jtorctl/net/freehaven/tor/control/PasswordDigest.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/PasswordDigest.java 2013-05-16 19:56:30.000000000 +0100 +@@ -2,19 +2,20 @@ + // See LICENSE file for copying information + package net.freehaven.tor.control; + ++import java.security.NoSuchAlgorithmException; + import java.security.SecureRandom; + import java.security.MessageDigest; + + /** +- * A hashed digest of a secret password (used to set control connection ++ * A hashed digest of a secret password(used to set control connection + * security.) + * + * For the actual hashing algorithm, see RFC2440's secret-to-key conversion. + */ + public class PasswordDigest { + +- byte[] secret; +- String hashedKey; ++ private final byte[] secret; ++ private final String hashedKey; + + /** Return a new password digest with a random secret and salt. */ + public static PasswordDigest generateDigest() { +@@ -35,17 +36,16 @@ + */ + public PasswordDigest(byte[] secret, byte[] specifier) { + this.secret = secret.clone(); +- if (specifier == null) { ++ if(specifier == null) { + specifier = new byte[9]; + SecureRandom rng = new SecureRandom(); + rng.nextBytes(specifier); + specifier[8] = 96; + } +- hashedKey = "16:"+encodeBytes(secretToKey(secret, specifier)); ++ hashedKey = "16:" + Bytes.hex(secretToKey(secret, specifier)); + } + +- /** Return the secret used to generate this password hash. +- */ ++ /** Return the secret used to generate this password hash. */ + public byte[] getSecret() { + return secret.clone(); + } +@@ -63,17 +63,17 @@ + MessageDigest d; + try { + d = MessageDigest.getInstance("SHA-1"); +- } catch (java.security.NoSuchAlgorithmException ex) { ++ } catch(NoSuchAlgorithmException ex) { + throw new RuntimeException("Can't run without sha-1."); + } +- int c = (specifier[8])&0xff; +- int count = (16 + (c&15)) << ((c>>4) + EXPBIAS); ++ int c = specifier[8] & 0xff; ++ int count = (16 + (c & 15)) << ((c >> 4) + EXPBIAS); + +- byte[] tmp = new byte[8+secret.length]; ++ byte[] tmp = new byte[8 + secret.length]; + System.arraycopy(specifier, 0, tmp, 0, 8); + System.arraycopy(secret, 0, tmp, 8, secret.length); +- while (count > 0) { +- if (count >= tmp.length) { ++ while(count > 0) { ++ if(count >= tmp.length) { + d.update(tmp); + count -= tmp.length; + } else { +@@ -81,17 +81,9 @@ + count = 0; + } + } +- byte[] key = new byte[20+9]; ++ byte[] key = new byte[20 + 9]; + System.arraycopy(d.digest(), 0, key, 9, 20); + System.arraycopy(specifier, 0, key, 0, 9); + return key; + } +- +- /** Return a hexadecimal encoding of a byte array. */ +- // XXX There must be a better way to do this in Java. +- private static final String encodeBytes(byte[] ba) { +- return Bytes.hex(ba); +- } +- + } +- +diff -Bbur jtorctl/net/freehaven/tor/control/TorControlCommands.java jtorctl-briar/net/freehaven/tor/control/TorControlCommands.java +--- jtorctl/net/freehaven/tor/control/TorControlCommands.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/TorControlCommands.java 2013-05-16 19:56:30.000000000 +0100 +@@ -119,7 +119,10 @@ + public static final byte OR_CONN_STATUS_CLOSED = 0x03; + + public static final String[] OR_CONN_STATUS_NAMES = { +- "LAUNCHED","CONNECTED","FAILED","CLOSED" ++ "LAUNCHED", ++ "CONNECTED", ++ "FAILED", ++ "CLOSED" + }; + + public static final byte SIGNAL_HUP = 0x01; +diff -Bbur jtorctl/net/freehaven/tor/control/TorControlConnection.java jtorctl-briar/net/freehaven/tor/control/TorControlConnection.java +--- jtorctl/net/freehaven/tor/control/TorControlConnection.java 2013-04-24 16:46:08.000000000 +0100 ++++ jtorctl-briar/net/freehaven/tor/control/TorControlConnection.java 2013-05-16 19:56:30.000000000 +0100 +@@ -2,120 +2,107 @@ + // See LICENSE file for copying information + package net.freehaven.tor.control; + ++import java.io.BufferedReader; + import java.io.IOException; +-import java.net.SocketException; ++import java.io.InputStream; ++import java.io.InputStreamReader; ++import java.io.OutputStream; ++import java.io.OutputStreamWriter; ++import java.io.PrintStream; ++import java.io.PrintWriter; ++import java.io.Reader; ++import java.io.Writer; ++import java.net.Socket; + import java.util.ArrayList; ++import java.util.Arrays; + import java.util.Collection; + import java.util.HashMap; +-import java.util.Iterator; + import java.util.LinkedList; + import java.util.List; + import java.util.Map; + import java.util.StringTokenizer; +-import java.util.concurrent.CancellationException; + + /** A connection to a running Tor process as specified in control-spec.txt. */ +-public class TorControlConnection implements TorControlCommands +-{ ++public class TorControlConnection implements TorControlCommands { + +- protected EventHandler handler; ++ private final LinkedList<Waiter> waiters; ++ private final BufferedReader input; ++ private final Writer output; + +- protected LinkedList<Waiter> waiters; ++ private ControlParseThread thread; // Locking: this + +- protected ControlParseThread thread; ++ private volatile EventHandler handler; ++ private volatile PrintWriter debugOutput; ++ private volatile IOException parseThreadException; + +- protected java.io.BufferedReader input; ++ private static class Waiter { + +- protected java.io.Writer output; +- +- protected java.io.PrintWriter debugOutput; +- +- static class Waiter { + List<ReplyLine> response; +- public synchronized List<ReplyLine> getResponse() { +- try { +- while (response == null) { +- wait(); +- } +- } catch (InterruptedException ex) { +- throw new CancellationException( +- "Please don't interrupt library calls."); +- } ++ ++ synchronized List<ReplyLine> getResponse() throws InterruptedException { ++ while(response == null) wait(); + return response; + } +- public synchronized void setResponse(List<ReplyLine> response) { ++ ++ synchronized void setResponse(List<ReplyLine> response) { + this.response = response; + notifyAll(); + } + } + +- static class ReplyLine { +- public String status; +- public String msg; +- public String rest; ++ private static class ReplyLine { ++ ++ final String status; ++ final String msg; ++ final String rest; + + ReplyLine(String status, String msg, String rest) { +- this.status = status; this.msg = msg; this.rest = rest; +- } ++ this.status = status; ++ this.msg = msg; ++ this.rest = rest; + } +- +- public static TorControlConnection getConnection(java.net.Socket sock) +- throws IOException +- { +- return new TorControlConnection(sock); + } + + /** Create a new TorControlConnection to communicate with Tor over + * a given socket. After calling this constructor, it is typical to + * call launchThread and authenticate. */ +- public TorControlConnection(java.net.Socket connection) +- throws IOException { +- this(connection.getInputStream(), connection.getOutputStream()); ++ public TorControlConnection(Socket s) throws IOException { ++ this(s.getInputStream(), s.getOutputStream()); + } + + /** Create a new TorControlConnection to communicate with Tor over + * an arbitrary pair of data streams. + */ +- public TorControlConnection(java.io.InputStream i, java.io.OutputStream o) { +- this(new java.io.InputStreamReader(i), +- new java.io.OutputStreamWriter(o)); ++ public TorControlConnection(InputStream i, OutputStream o) { ++ this(new InputStreamReader(i), new OutputStreamWriter(o)); + } + +- public TorControlConnection(java.io.Reader i, java.io.Writer o) { +- this.output = o; +- if (i instanceof java.io.BufferedReader) +- this.input = (java.io.BufferedReader) i; +- else +- this.input = new java.io.BufferedReader(i); +- +- this.waiters = new LinkedList<Waiter>(); ++ public TorControlConnection(Reader i, Writer o) { ++ if(i instanceof BufferedReader) input = (BufferedReader) i; ++ else input = new BufferedReader(i); ++ output = o; ++ waiters = new LinkedList<Waiter>(); + } + +- protected final void writeEscaped(String s) throws IOException { ++ private void writeEscaped(String s) throws IOException { + StringTokenizer st = new StringTokenizer(s, "\n"); +- while (st.hasMoreTokens()) { ++ while(st.hasMoreTokens()) { + String line = st.nextToken(); +- if (line.startsWith(".")) +- line = "."+line; +- if (line.endsWith("\r")) +- line += "\n"; +- else +- line += "\r\n"; +- if (debugOutput != null) +- debugOutput.print(">> "+line); ++ if(line.startsWith(".")) line = "." + line; ++ if(line.endsWith("\r")) line += "\n"; ++ else line += "\r\n"; ++ if(debugOutput != null) debugOutput.print(">> " + line); + output.write(line); + } + output.write(".\r\n"); +- if (debugOutput != null) +- debugOutput.print(">> .\n"); ++ if(debugOutput != null) debugOutput.print(">> .\n"); + } + +- protected static final String quote(String s) { ++ private static final String quote(String s) { + StringBuffer sb = new StringBuffer("\""); +- for (int i = 0; i < s.length(); ++i) { ++ for(int i = 0; i < s.length(); ++i) { + char c = s.charAt(i); +- switch (c) +- { ++ switch (c) { + case '\r': + case '\n': + case '\\': +@@ -128,15 +115,15 @@ + return sb.toString(); + } + +- protected final ArrayList<ReplyLine> readReply() throws IOException { ++ private ArrayList<ReplyLine> readReply() throws IOException { + ArrayList<ReplyLine> reply = new ArrayList<ReplyLine>(); + char c; + do { + String line = input.readLine(); +- if (line == null) { ++ if(line == null) { + // if line is null, the end of the stream has been reached, i.e. + // the connection to Tor has been closed! +- if (reply.isEmpty()) { ++ if(reply.isEmpty()) { + // nothing received so far, can exit cleanly + return reply; + } +@@ -144,91 +131,86 @@ + throw new TorControlSyntaxError("Connection to Tor " + + " broke down while receiving reply!"); + } +- if (debugOutput != null) +- debugOutput.println("<< "+line); +- if (line.length() < 4) +- throw new TorControlSyntaxError("Line (\""+line+"\") too short"); +- String status = line.substring(0,3); ++ if(debugOutput != null) debugOutput.println("<< " + line); ++ if(line.length() < 4) { ++ throw new TorControlSyntaxError("Line (\"" + line + ++ "\") too short"); ++ } ++ String status = line.substring(0, 3); + c = line.charAt(3); + String msg = line.substring(4); + String rest = null; +- if (c == '+') { ++ if(c == '+') { + StringBuffer data = new StringBuffer(); +- while (true) { ++ while(true) { + line = input.readLine(); +- if (debugOutput != null) +- debugOutput.print("<< "+line); +- if (line.equals(".")) +- break; +- else if (line.startsWith(".")) +- line = line.substring(1); ++ if(debugOutput != null) debugOutput.print("<< " + line); ++ if(line.equals(".")) break; ++ if(line.startsWith(".")) line = line.substring(1); + data.append(line).append('\n'); + } + rest = data.toString(); + } + reply.add(new ReplyLine(status, msg, rest)); +- } while (c != ' '); +- ++ } while(c != ' '); + return reply; + } + +- protected synchronized List<ReplyLine> sendAndWaitForResponse(String s,String rest) +- throws IOException { ++ private synchronized List<ReplyLine> sendAndWaitForResponse(String s, ++ String rest) throws IOException { ++ if(parseThreadException != null) throw parseThreadException; + checkThread(); + Waiter w = new Waiter(); +- if (debugOutput != null) +- debugOutput.print(">> "+s); +- synchronized (waiters) { ++ if(debugOutput != null) debugOutput.print(">> " + s); ++ synchronized(waiters) { + output.write(s); +- if (rest != null) +- writeEscaped(rest); ++ if(rest != null) writeEscaped(rest); + output.flush(); + waiters.addLast(w); + } +- List<ReplyLine> lst = w.getResponse(); +- for (Iterator<ReplyLine> i = lst.iterator(); i.hasNext(); ) { +- ReplyLine c = i.next(); +- if (! c.status.startsWith("2")) +- throw new TorControlError("Error reply: "+c.msg); ++ List<ReplyLine> lst; ++ try { ++ lst = w.getResponse(); ++ } catch(InterruptedException ex) { ++ throw new IOException(ex); ++ } ++ for(ReplyLine line : lst) { ++ if(!line.status.startsWith("2")) ++ throw new TorControlError("Error reply: " + line.msg); + } + return lst; + } + + /** Helper: decode a CMD_EVENT command and dispatch it to our + * EventHandler (if any). */ +- protected void handleEvent(ArrayList<ReplyLine> events) { +- if (handler == null) +- return; +- +- for (Iterator<ReplyLine> i = events.iterator(); i.hasNext(); ) { +- ReplyLine line = i.next(); ++ private void handleEvent(ArrayList<ReplyLine> events) { ++ if(handler == null) return; ++ for(ReplyLine line : events) { + int idx = line.msg.indexOf(' '); + String tp = line.msg.substring(0, idx).toUpperCase(); + String rest = line.msg.substring(idx+1); +- if (tp.equals("CIRC")) { ++ if(tp.equals("CIRC")) { + List<String> lst = Bytes.splitStr(null, rest); +- handler.circuitStatus(lst.get(1), +- lst.get(0), +- lst.get(1).equals("LAUNCHED") +- || lst.size() < 2 ? "" +- : lst.get(2)); +- } else if (tp.equals("STREAM")) { ++ String path; ++ if(lst.get(1).equals("LAUNCHED") || lst.size() < 2) path = ""; ++ else path = lst.get(2); ++ handler.circuitStatus(lst.get(1), lst.get(0), path); ++ } else if(tp.equals("STREAM")) { + List<String> lst = Bytes.splitStr(null, rest); +- handler.streamStatus(lst.get(1), +- lst.get(0), +- lst.get(3)); ++ handler.streamStatus(lst.get(1), lst.get(0), lst.get(3)); + // XXXX circID. +- } else if (tp.equals("ORCONN")) { ++ } else if(tp.equals("ORCONN")) { + List<String> lst = Bytes.splitStr(null, rest); + handler.orConnStatus(lst.get(1), lst.get(0)); +- } else if (tp.equals("BW")) { ++ } else if(tp.equals("BW")) { + List<String> lst = Bytes.splitStr(null, rest); +- handler.bandwidthUsed(Integer.parseInt(lst.get(0)), +- Integer.parseInt(lst.get(1))); +- } else if (tp.equals("NEWDESC")) { ++ int read = Integer.parseInt(lst.get(0)); ++ int written = Integer.parseInt(lst.get(1)); ++ handler.bandwidthUsed(read, written); ++ } else if(tp.equals("NEWDESC")) { + List<String> lst = Bytes.splitStr(null, rest); + handler.newDescriptors(lst); +- } else if (tp.equals("DEBUG") || ++ } else if(tp.equals("DEBUG") || + tp.equals("INFO") || + tp.equals("NOTICE") || + tp.equals("WARN") || +@@ -240,23 +222,22 @@ + } + } + +- + /** Sets <b>w</b> as the PrintWriter for debugging output, + * which writes out all messages passed between Tor and the controller. +- * Outgoing messages are preceded by "\>\>" and incoming messages are preceded +- * by "\<\<" ++ * Outgoing messages are preceded by "\>\>" and incoming messages are ++ * preceded by "\<\<" + */ +- public void setDebugging(java.io.PrintWriter w) { ++ public void setDebugging(PrintWriter w) { + debugOutput = w; + } + + /** Sets <b>s</b> as the PrintStream for debugging output, + * which writes out all messages passed between Tor and the controller. +- * Outgoing messages are preceded by "\>\>" and incoming messages are preceded +- * by "\<\<" ++ * Outgoing messages are preceded by "\>\>" and incoming messages are ++ * preceded by "\<\<" + */ +- public void setDebugging(java.io.PrintStream s) { +- debugOutput = new java.io.PrintWriter(s, true); ++ public void setDebugging(PrintStream s) { ++ debugOutput = new PrintWriter(s, true); + } + + /** Set the EventHandler object that will be notified of any +@@ -271,52 +252,43 @@ + * This is necessary to handle asynchronous events and synchronous + * responses that arrive independantly over the same socket. + */ +- public Thread launchThread(boolean daemon) { ++ public synchronized Thread launchThread(boolean daemon) { + ControlParseThread th = new ControlParseThread(); +- if (daemon) +- th.setDaemon(true); ++ if(daemon) th.setDaemon(true); + th.start(); +- this.thread = th; ++ thread = th; + return th; + } + +- protected class ControlParseThread extends Thread { +- boolean stopped = false; ++ private class ControlParseThread extends Thread { ++ + @Override + public void run() { + try { + react(); +- } catch (SocketException ex) { +- if (stopped) // we expected this exception +- return; +- throw new RuntimeException(ex); +- } catch (IOException ex) { +- throw new RuntimeException(ex); +- } ++ } catch(IOException ex) { ++ parseThreadException = ex; + } +- public void stopListening() { +- this.stopped = true; + } + } + +- protected final void checkThread() { +- if (thread == null) +- launchThread(true); ++ private synchronized void checkThread() { ++ if(thread == null) launchThread(true); + } + + /** helper: implement the main background loop. */ +- protected void react() throws IOException { +- while (true) { ++ private void react() throws IOException { ++ while(true) { + ArrayList<ReplyLine> lst = readReply(); +- if (lst.isEmpty()) { ++ if(lst.isEmpty()) { + // connection has been closed remotely! end the loop! + return; + } +- if ((lst.get(0)).status.startsWith("6")) ++ if((lst.get(0)).status.startsWith("6")) { + handleEvent(lst); +- else { ++ } else { + Waiter w; +- synchronized (waiters) { ++ synchronized(waiters) { + w = waiters.removeFirst(); + } + w.setResponse(lst); +@@ -327,17 +299,14 @@ + /** Change the value of the configuration option 'key' to 'val'. + */ + public void setConf(String key, String value) throws IOException { +- List<String> lst = new ArrayList<String>(); +- lst.add(key+" "+value); +- setConf(lst); ++ setConf(Arrays.asList(key + " " + value)); + } + + /** Change the values of the configuration options stored in kvMap. */ + public void setConf(Map<String, String> kvMap) throws IOException { + List<String> lst = new ArrayList<String>(); +- for (Iterator<Map.Entry<String,String>> it = kvMap.entrySet().iterator(); it.hasNext(); ) { +- Map.Entry<String,String> ent = it.next(); +- lst.add(ent.getKey()+" "+ent.getValue()+"\n"); ++ for(Map.Entry<String, String> e : kvMap.entrySet()) { ++ lst.add(e.getKey() + " " + e.getValue() + "\n"); + } + setConf(lst); + } +@@ -345,34 +314,35 @@ + /** Changes the values of the configuration options stored in + * <b>kvList</b>. Each list element in <b>kvList</b> is expected to be + * String of the format "key value". +- * ++ * <p> + * 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. ++ * <p> + * 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. ++ * <p> + * To remove all settings for a given option entirely (and go back to its +- * default value), include a String in <b>kvList</b> containing the key and no value. ++ * default value), include a String in <b>kvList</b> containing the key and ++ * no value. + */ + public void setConf(Collection<String> kvList) throws IOException { +- if (kvList.size() == 0) +- return; ++ if(kvList.size() == 0) return; + StringBuffer b = new StringBuffer("SETCONF"); +- for (Iterator<String> it = kvList.iterator(); it.hasNext(); ) { +- String kv = it.next(); +- int i = kv.indexOf(' '); +- if (i == -1) ++ for(String kv : kvList) { ++ int idx = kv.indexOf(' '); ++ if(idx == -1) { + b.append(" ").append(kv); +- b.append(" ").append(kv.substring(0,i)).append("=") +- .append(quote(kv.substring(i+1))); ++ } else { ++ b.append(" ").append(kv.substring(0, idx)); ++ b.append("=").append(quote(kv.substring(idx + 1))); ++ } + } + b.append("\r\n"); + sendAndWaitForResponse(b.toString(), null); +@@ -382,11 +352,9 @@ + * default values. + **/ + public void resetConf(Collection<String> keys) throws IOException { +- if (keys.size() == 0) +- return; ++ if(keys.size() == 0) return; + StringBuffer b = new StringBuffer("RESETCONF"); +- for (Iterator<String> it = keys.iterator(); it.hasNext(); ) { +- String key = it.next(); ++ for(String key : keys) { + b.append(" ").append(key); + } + b.append("\r\n"); +@@ -400,36 +368,38 @@ + return getConf(lst); + } + +- /** Requests the values of the configuration variables listed in <b>keys</b>. +- * Results are returned as a list of ConfigEntry objects. +- * ++ /** Requests the values of the configuration variables listed in ++ * <b>keys</b>. Results are returned as a list of ConfigEntry objects. ++ * <p> + * If an option appears multiple times in the configuration, all of its + * key-value pairs are returned in order. +- * ++ * <p> + * 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<ConfigEntry> getConf(Collection<String> keys) throws IOException { ++ public List<ConfigEntry> getConf(Collection<String> keys) ++ throws IOException { + StringBuffer sb = new StringBuffer("GETCONF"); +- for (Iterator<String> it = keys.iterator(); it.hasNext(); ) { +- String key = it.next(); ++ for(String key : keys) { + sb.append(" ").append(key); + } + sb.append("\r\n"); + List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null); + List<ConfigEntry> result = new ArrayList<ConfigEntry>(); +- for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) { +- String kv = (it.next()).msg; ++ for(ReplyLine line : lst) { ++ String kv = line.msg; + int idx = kv.indexOf('='); +- if (idx >= 0) +- result.add(new ConfigEntry(kv.substring(0, idx), +- kv.substring(idx+1))); +- else ++ if(idx >= 0) { ++ String key = kv.substring(0, idx); ++ String value = kv.substring(idx + 1); ++ result.add(new ConfigEntry(key, value)); ++ } else { + result.add(new ConfigEntry(kv)); + } ++ } + return result; + } + +@@ -437,37 +407,41 @@ + * Each element of <b>events</b> is one of the following Strings: + * ["CIRC" | "STREAM" | "ORCONN" | "BW" | "DEBUG" | + * "INFO" | "NOTICE" | "WARN" | "ERR" | "NEWDESC" | "ADDRMAP"] . +- * ++ * <p> + * Any events not listed in the <b>events</b> are turned off; thus, calling +- * setEvents with an empty <b>events</b> argument turns off all event reporting. ++ * setEvents with an empty <b>events</b> argument turns off all event ++ * reporting. + */ + public void setEvents(List<String> events) throws IOException { + StringBuffer sb = new StringBuffer("SETEVENTS"); +- for (Iterator<String> it = events.iterator(); it.hasNext(); ) { +- sb.append(" ").append(it.next()); ++ for(String event : events) { ++ sb.append(" ").append(event); + } + sb.append("\r\n"); + sendAndWaitForResponse(sb.toString(), null); + } + + /** Authenticates the controller to the Tor server. +- * ++ * <p> + * 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 <b>auth</b>. +- * +- * If the 'HashedControlPassword' option is set, <b>auth</b> 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]). ++ * <p> ++ * 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 ++ * <b>auth</b>. ++ * <p> ++ * If the 'HashedControlPassword' option is set, <b>auth</b> 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:". ++ * <p> + * You can generate the salt of a password by calling +- * 'tor --hash-password <password>' ++ * <tt>'tor --hash-password <password>'</tt> + * or by using the provided PasswordDigest class. ++ * <p> + * 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 <b>kvLines</b> 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 <b>kvLines</b> is a ++ * String of the form "old-address new-address". This function returns the ++ * new address mapping. ++ * <p> + * 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. ++ * <p> ++ * 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. ++ * <p> ++ * 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<String,String> mapAddresses(Collection<String> kvLines) throws IOException { ++ public Map<String, String> mapAddresses(Collection<String> kvLines) ++ throws IOException { + StringBuffer sb = new StringBuffer("MAPADDRESS"); +- for (Iterator<String> it = kvLines.iterator(); it.hasNext(); ) { +- String kv = it.next(); +- int i = kv.indexOf(' '); +- sb.append(" ").append(kv.substring(0,i)).append("=") +- .append(quote(kv.substring(i+1))); ++ for(String kv : kvLines) { ++ int idx = kv.indexOf(' '); ++ sb.append(" ").append(kv.substring(0, idx)); ++ sb.append("=").append(quote(kv.substring(idx + 1))); + } + sb.append("\r\n"); + List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null); +- Map<String,String> result = new HashMap<String,String>(); +- for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) { +- String kv = (it.next()).msg; ++ Map<String, String> result = new HashMap<String, String>(); ++ for(ReplyLine line : lst) { ++ String kv = line.msg; + int idx = kv.indexOf('='); +- result.put(kv.substring(0, idx), +- kv.substring(idx+1)); ++ result.put(kv.substring(0, idx), kv.substring(idx + 1)); + } + return result; + } + +- public Map<String,String> mapAddresses(Map<String,String> addresses) throws IOException { ++ public Map<String, String> mapAddresses(Map<String, String> addresses) ++ throws IOException { + List<String> kvList = new ArrayList<String>(); +- for (Iterator<Map.Entry<String, String>> it = addresses.entrySet().iterator(); it.hasNext(); ) { +- Map.Entry<String,String> e = it.next(); +- kvList.add(e.getKey()+" "+e.getValue()); ++ for(Map.Entry<String, String> e : addresses.entrySet()) { ++ kvList.add(e.getKey() + " " + e.getValue()); + } + return mapAddresses(kvList); + } + +- public String mapAddress(String fromAddr, String toAddr) throws IOException { ++ public String mapAddress(String fromAddr, String toAddr) ++ throws IOException { + List<String> lst = new ArrayList<String>(); +- lst.add(fromAddr+" "+toAddr+"\n"); +- Map<String,String> m = mapAddresses(lst); ++ lst.add(fromAddr + " " + toAddr + "\n"); ++ Map<String, String> m = mapAddresses(lst); + return m.get(fromAddr); + } + +- /** Queries the Tor server for keyed values that are not stored in the torrc +- * configuration file. Returns a map of keys to values. +- * ++ /** Queries the Tor server for keyed values that are not stored in the ++ * torrc configuration file. Returns a map of keys to values. ++ * <p> + * Recognized keys include: + * <ul> + * <li>"version" : The version of the server's software, including the name + * of the software. (example: "Tor 0.0.9.4")</li> +- * <li>"desc/id/<OR identity>" or "desc/name/<OR nickname>" : the latest server +- * descriptor for a given OR, NUL-terminated. If no such OR is known, the +- * corresponding value is an empty string.</li> +- * <li>"network-status" : a space-separated list of all known OR identities. +- * This is in the same format as the router-status line in directories; +- * see tor-spec.txt for details.</li> ++ * <li>"desc/id/<OR identity>" or "desc/name/<OR nickname>" : the latest ++ * server descriptor for a given OR, NUL-terminated. If no such OR is ++ * known, the corresponding value is an empty string.</li> ++ * <li>"network-status" : a space-separated list of all known OR ++ * identities. This is in the same format as the router-status line in ++ * directories; see tor-spec.txt for details.</li> + * <li>"addr-mappings/all"</li> + * <li>"addr-mappings/config"</li> + * <li>"addr-mappings/cache"</li> +- * <li>"addr-mappings/control" : a space-separated list of address mappings, each +- * in the form of "from-address=to-address". The 'config' key +- * returns those address mappings set in the configuration; the 'cache' ++ * <li>"addr-mappings/control" : a space-separated list of address ++ * mappings, each in the form of "from-address=to-address". The 'config' ++ * key returns those address mappings set in the configuration; the 'cache' + * key returns the mappings in the client-side DNS cache; the 'control' + * key returns the mappings set via the control interface; the 'all' + * target returns the mappings set through any mechanism.</li> +- * <li>"circuit-status" : A series of lines as for a circuit status event. Each line is of the form: +- * "CircuitID CircStatus Path"</li> +- * <li>"stream-status" : A series of lines as for a stream status event. Each is of the form: +- * "StreamID StreamStatus CircID Target"</li> +- * <li>"orconn-status" : A series of lines as for an OR connection status event. Each is of the +- * form: "ServerID ORStatus"</li> ++ * <li>"circuit-status" : A series of lines as for a circuit status event. ++ * Each line is of the form: "CircuitID CircStatus Path"</li> ++ * <li>"stream-status" : A series of lines as for a stream status event. ++ * Each is of the form: "StreamID StreamStatus CircID Target"</li> ++ * <li>"orconn-status" : A series of lines as for an OR connection status ++ * event. Each is of the form: "ServerID ORStatus"</li> + * </ul> + */ +- public Map<String,String> getInfo(Collection<String> keys) throws IOException { ++ public Map<String, String> getInfo(Collection<String> keys) ++ throws IOException { + StringBuffer sb = new StringBuffer("GETINFO"); +- for (Iterator<String> it = keys.iterator(); it.hasNext(); ) { +- sb.append(" ").append(it.next()); ++ for(String key : keys) { ++ sb.append(" ").append(key); + } + sb.append("\r\n"); + List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null); +- Map<String,String> m = new HashMap<String,String>(); +- for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) { +- ReplyLine line = it.next(); ++ Map<String, String> m = new HashMap<String, String>(); ++ for(ReplyLine line : lst) { + int idx = line.msg.indexOf('='); +- if (idx<0) +- break; +- String k = line.msg.substring(0,idx); ++ if(idx < 0) break; ++ String k = line.msg.substring(0, idx); + String v; +- if (line.rest != null) { +- v = line.rest; +- } else { +- v = line.msg.substring(idx+1); +- } ++ if(line.rest != null) v = line.rest; ++ else v = line.msg.substring(idx + 1); + m.put(k, v); + } + return m; + } + +- +- +- /** Return the value of the information field 'key' */ ++ /** Returns the value of the information field 'key' */ + public String getInfo(String key) throws IOException { +- List<String> lst = new ArrayList<String>(); +- lst.add(key); +- Map<String,String> m = getInfo(lst); ++ Map<String, String> m = getInfo(Arrays.asList(key)); + return m.get(key); + } + +- /** An extendCircuit request takes one of two forms: either the <b>circID</b> is zero, in +- * which case it is a request for the server to build a new circuit according +- * to the specified path, or the <b>circID</b> is nonzero, in which case it is a +- * request for the server to extend an existing circuit with that ID according +- * to the specified <b>path</b>. +- * +- * If successful, returns the Circuit ID of the (maybe newly created) circuit. ++ /** An extendCircuit request takes one of two forms: either the ++ * <b>circID</b> is zero, in which case it is a request for the server to ++ * build a new circuit according to the specified path, or the ++ * <b>circID</b> is nonzero, in which case it is a request for the server ++ * to extend an existing circuit with that ID according to the specified ++ * <b>path</b>. ++ * <p> ++ * If successful, returns the Circuit ID of the (maybe newly created) ++ * circuit. + */ + public String extendCircuit(String circID, String path) throws IOException { +- List<ReplyLine> lst = sendAndWaitForResponse( +- "EXTENDCIRCUIT "+circID+" "+path+"\r\n", null); +- return (lst.get(0)).msg; ++ String cmd = "EXTENDCIRCUIT " + circID + " " + path + "\r\n"; ++ List<ReplyLine> lst = sendAndWaitForResponse(cmd, null); ++ return lst.get(0).msg; + } + +- /** Informs the Tor server that the stream specified by <b>streamID</b> should be +- * associated with the circuit specified by <b>circID</b>. +- * +- * 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). +- * ++ /** Informs the Tor server that the stream specified by <b>streamID</b> ++ * should be associated with the circuit specified by <b>circID</b>. ++ * <p> ++ * 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). ++ * <p> + * If <b>circID</b> 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. ++ * <p> ++ * 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 <b>desc</b>. +- * ++ * <p> + * 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<ReplyLine> lst = sendAndWaitForResponse("+POSTDESCRIPTOR\r\n", desc); +- return (lst.get(0)).msg; ++ String cmd = "+POSTDESCRIPTOR\r\n"; ++ List<ReplyLine> lst = sendAndWaitForResponse(cmd, desc); ++ return lst.get(0).msg; + } + +- /** Tells Tor to change the exit address of the stream identified by <b>streamID</b> +- * to <b>address</b>. No remapping is performed on the new provided address. +- * +- * 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 { +- sendAndWaitForResponse("REDIRECTSTREAM "+streamID+" "+address+"\r\n", +- null); ++ /** Tells Tor to change the exit address of the stream identified by ++ * <b>streamID</b> to <b>address</b>. No remapping is performed on the new ++ * provided address. ++ * <p> ++ * 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 <b>streamID</b>. +- * <b>reason</b> should be one of the Tor RELAY_END reasons given in tor-spec.txt, as a decimal: ++ * <b>reason</b> should be one of the Tor RELAY_END reasons given in ++ * tor-spec.txt, as a decimal: + * <ul> + * <li>1 -- REASON_MISC (catch-all for unlisted reasons)</li> + * <li>2 -- REASON_RESOLVEFAILED (couldn't look up hostname)</li> + * <li>3 -- REASON_CONNECTREFUSED (remote host refused connection)</li> +- * <li>4 -- REASON_EXITPOLICY (OR refuses to connect to host or port)</li> ++ * <li>4 -- REASON_EXITPOLICY (OR refuses to connect to host or ++ * port)</li> + * <li>5 -- REASON_DESTROY (Circuit is being destroyed)</li> +- * <li>6 -- REASON_DONE (Anonymized TCP connection was closed)</li> +- * <li>7 -- REASON_TIMEOUT (Connection timed out, or OR timed out while connecting)</li> ++ * <li>6 -- REASON_DONE (Anonymized TCP connection was ++ * closed)</li> ++ * <li>7 -- REASON_TIMEOUT (Connection timed out, or OR timed out ++ * while connecting)</li> + * <li>8 -- (unallocated)</li> + * <li>9 -- REASON_HIBERNATING (OR is temporarily hibernating)</li> + * <li>10 -- REASON_INTERNAL (Internal error at the OR)</li> +- * <li>11 -- REASON_RESOURCELIMIT (OR has no resources to fulfill request)</li> ++ * <li>11 -- REASON_RESOURCELIMIT (OR has no resources to fulfill ++ * request)</li> + * <li>12 -- REASON_CONNRESET (Connection was unexpectedly reset)</li> +- * <li>13 -- REASON_TORPROTOCOL (Sent when closing connection because of Tor protocol violations)</li> ++ * <li>13 -- REASON_TORPROTOCOL (Sent when closing connection because of ++ * Tor protocol violations)</li> + * </ul> +- * +- * 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 <b>circID</b>. +- * If <b>ifUnused</b> is true, do not close the circuit unless it is unused. ++ * If <b>ifUnused</b> 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); ++ } + } + -- GitLab