Skip to content
This repository has been archived by the owner on May 4, 2021. It is now read-only.

Commit

Permalink
update with fixes for thread-safe and better exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
n8fr8 committed Aug 11, 2014
1 parent 319377b commit 9f8afff
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 86 deletions.
9 changes: 5 additions & 4 deletions net/freehaven/tor/control/PasswordDigest.java
Expand Up @@ -2,8 +2,9 @@
// See LICENSE file for copying information
package net.freehaven.tor.control;

import java.security.SecureRandom;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
* A hashed digest of a secret password (used to set control connection
Expand All @@ -13,8 +14,8 @@
*/
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() {
Expand Down Expand Up @@ -63,7 +64,7 @@ public static byte[] secretToKey(byte[] secret, byte[] specifier) {
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;
Expand Down
110 changes: 51 additions & 59 deletions net/freehaven/tor/control/TorControlConnection.java
Expand Up @@ -2,7 +2,17 @@
// See LICENSE file for copying information
package net.freehaven.tor.control;

import java.io.BufferedReader;
import java.io.IOException;
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.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -15,79 +25,66 @@
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;

protected java.io.BufferedReader input;
private volatile EventHandler handler;
private volatile PrintWriter debugOutput;
private volatile IOException parseThreadException;

protected java.io.Writer output;
static class Waiter {

protected java.io.PrintWriter debugOutput;
List<ReplyLine> response; // Locking: this

static class Waiter {
List<ReplyLine> response;
public synchronized List<ReplyLine> getResponse() {
try {
synchronized List<ReplyLine> getResponse() throws InterruptedException {
while (response == null) {
wait();
}
} catch (InterruptedException ex) {
throw new CancellationException(
"Please don't interrupt library calls.");
}
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;

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;
}
}

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 {
public TorControlConnection(Socket connection) throws IOException {
this(connection.getInputStream(), connection.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) {
public TorControlConnection(Reader i, Writer o) {
this.output = o;
if (i instanceof java.io.BufferedReader)
this.input = (java.io.BufferedReader) i;
if (i instanceof BufferedReader)
this.input = (BufferedReader) i;
else
this.input = new java.io.BufferedReader(i);

this.input = new BufferedReader(i);
this.waiters = new LinkedList<Waiter>();
}

Expand Down Expand Up @@ -172,8 +169,9 @@ else if (line.startsWith("."))
return reply;
}

protected synchronized List<ReplyLine> sendAndWaitForResponse(String s,String rest)
throws IOException {
protected synchronized List<ReplyLine> sendAndWaitForResponse(String s,
String rest) throws IOException {
if(parseThreadException != null) throw parseThreadException;
checkThread();
Waiter w = new Waiter();
if (debugOutput != null)
Expand All @@ -185,7 +183,12 @@ protected synchronized List<ReplyLine> sendAndWaitForResponse(String s,String re
output.flush();
waiters.addLast(w);
}
List<ReplyLine> lst = w.getResponse();
List<ReplyLine> lst;
try {
lst = w.getResponse();
} catch (InterruptedException ex) {
throw new IOException("Interrupted");
}
for (Iterator<ReplyLine> i = lst.iterator(); i.hasNext(); ) {
ReplyLine c = i.next();
if (! c.status.startsWith("2"))
Expand All @@ -210,7 +213,7 @@ protected void handleEvent(ArrayList<ReplyLine> events) {
handler.circuitStatus(lst.get(1),
lst.get(0),
lst.get(1).equals("LAUNCHED")
|| lst.size() < 2 ? ""
|| lst.size() < 3 ? ""
: lst.get(2));
} else if (tp.equals("STREAM")) {
List<String> lst = Bytes.splitStr(null, rest);
Expand Down Expand Up @@ -246,7 +249,7 @@ protected void handleEvent(ArrayList<ReplyLine> events) {
* 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;
}

Expand All @@ -255,8 +258,8 @@ public void setDebugging(java.io.PrintWriter w) {
* 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
Expand All @@ -271,7 +274,7 @@ public void setEventHandler(EventHandler handler) {
* 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);
Expand All @@ -281,25 +284,18 @@ public Thread launchThread(boolean daemon) {
}

protected class ControlParseThread extends Thread {
boolean stopped = false;

@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);
parseThreadException = ex;
}
}
public void stopListening() {
this.stopped = true;
}
}

protected final void checkThread() {
protected synchronized void checkThread() {
if (thread == null)
launchThread(true);
}
Expand Down Expand Up @@ -509,13 +505,9 @@ public void shutdownTor(String signal) throws IOException {
Waiter w = new Waiter();
if (debugOutput != null)
debugOutput.print(">> "+s);
if (this.thread != null) {
this.thread.stopListening();
}
synchronized (waiters) {
output.write(s);
output.flush();
waiters.addLast(w); // Prevent react() from finding the list empty
}
}

Expand Down
13 changes: 10 additions & 3 deletions net/freehaven/tor/control/TorControlError.java
Expand Up @@ -2,23 +2,30 @@
// See LICENSE file for copying information
package net.freehaven.tor.control;

import java.io.IOException;

/**
* An exception raised when Tor tells us about an error.
*/
public class TorControlError extends RuntimeException {
static final long serialVersionUID = 2;
public class TorControlError extends IOException {

static final long serialVersionUID = 3;

private final int errorType;

int errorType;
public TorControlError(int type, String s) {
super(s);
errorType = type;
}

public TorControlError(String s) {
this(-1, s);
}

public int getErrorType() {
return errorType;
}

public String getErrorMsg() {
try {
if (errorType == -1)
Expand Down
7 changes: 5 additions & 2 deletions net/freehaven/tor/control/TorControlSyntaxError.java
Expand Up @@ -2,11 +2,14 @@
// See LICENSE file for copying information
package net.freehaven.tor.control;

import java.io.IOException;

/**
* An exception raised when Tor behaves in an unexpected way.
*/
public class TorControlSyntaxError extends RuntimeException {
static final long serialVersionUID = 2;
public class TorControlSyntaxError extends IOException {

static final long serialVersionUID = 3;

public TorControlSyntaxError(String s) { super(s); }
}
Expand Down
Expand Up @@ -8,7 +8,7 @@

public class DebuggingEventHandler implements EventHandler {

protected PrintWriter out;
private final PrintWriter out;

public DebuggingEventHandler(PrintWriter p) {
out = p;
Expand Down
31 changes: 14 additions & 17 deletions net/freehaven/tor/control/examples/Main.java
Expand Up @@ -3,8 +3,10 @@
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;
Expand Down Expand Up @@ -34,27 +36,22 @@ public static void main(String 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 (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;
Expand Down Expand Up @@ -132,15 +129,15 @@ public static void signal(String[] args) throws IOException {
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));
s = new Socket("127.0.0.1", 9100);
conn = new TorControlConnection(s);
conn.launchThread(true);
conn.authenticate(pwd.getSecret());
}
Expand Down

0 comments on commit 9f8afff

Please sign in to comment.