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 &lt;password&gt;'</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);
+	}
 }