[or-cvs] Refactor java tor control library to split out v0 protocol
Nick Mathewson
nickm at seul.org
Tue Jun 21 21:49:32 UTC 2005
Update of /home/or/cvsroot/control/java/net/freehaven/tor/control
In directory moria:/tmp/cvs-serv17111/net/freehaven/tor/control
Modified Files:
Bytes.java EventHandler.java TorControlConnection.java
Added Files:
TorControlConnection0.java
Log Message:
Refactor java tor control library to split out v0 protocol
Index: Bytes.java
===================================================================
RCS file: /home/or/cvsroot/control/java/net/freehaven/tor/control/Bytes.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- Bytes.java 4 Jun 2005 02:42:55 -0000 1.1
+++ Bytes.java 21 Jun 2005 21:49:30 -0000 1.2
@@ -38,6 +38,10 @@
((ba[pos+3]&0xff));
}
+ public static String getU32S(byte[] ba, int pos) {
+ return String.valueOf( ((long)getU32(ba,pos))&0xffffffffL );
+ }
+
/** Return the two-byte value starting at index 'pos' within 'ba' */
public static int getU16(byte[] ba, int pos) {
return
Index: EventHandler.java
===================================================================
RCS file: /home/or/cvsroot/control/java/net/freehaven/tor/control/EventHandler.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- EventHandler.java 4 Jun 2005 02:42:55 -0000 1.1
+++ EventHandler.java 21 Jun 2005 21:49:30 -0000 1.2
@@ -10,22 +10,21 @@
* @see TorControlConnection#listenForEvents
*/
public interface EventHandler {
-
/**
* Invoked when a circuit's status has changed.
* See TorControlCommands.CIRC_STATUS_* for possible status codes.
*/
- public void circuitStatus(int status, int circID, String path);
+ public void circuitStatus(String status, String circID, String path);
/**
* Invoked when a stream's status has changed.
* See TorControlCommands.STREAM_STATUS_* for possible status codes.
*/
- public void streamStatus(int status, int streamID, String target);
+ public void streamStatus(String status, String streamID, String target);
/**
* Invoked when the status of a connection to an OR has changed.
* See TorControlCommands.OR_CONN_STATUS_* for possible status codes.
*/
- public void orConnStatus(int status, String orName);
+ public void orConnStatus(String status, String orName);
/**
* Invoked once per second with the number of bytes read an written in
* the last secone.
@@ -39,4 +38,4 @@
* Invoked when Tor logs a message.
*/
public void message(int type, String msg);
-}
\ No newline at end of file
+}
Index: TorControlConnection.java
===================================================================
RCS file: /home/or/cvsroot/control/java/net/freehaven/tor/control/TorControlConnection.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- TorControlConnection.java 4 Jun 2005 02:42:55 -0000 1.1
+++ TorControlConnection.java 21 Jun 2005 21:49:30 -0000 1.2
@@ -13,16 +13,15 @@
import java.util.Map;
/** A connection to a running Tor process. */
-public class TorControlConnection implements TorControlCommands {
- protected java.io.DataOutputStream outStream;
- protected java.io.DataInputStream inStream;
+public abstract class TorControlConnection// implements TorControlCommands {
+{
protected EventHandler handler;
protected LinkedList waiters;
static class Waiter {
- Cmd response;
- public synchronized Cmd getResponse() {
+ Object response;
+ public synchronized Object getResponse() {
try {
while (response == null) {
wait();
@@ -32,104 +31,16 @@
}
return response;
}
- public synchronized void setResponse(Cmd response) {
+ public synchronized void setResponse(Object response) {
this.response = response;
notifyAll();
}
}
- static class Cmd {
- public int type;
- public byte[] body;
-
- Cmd(int t, byte[] b) { type = t; body = b; }
- Cmd(int t, int l) { type = t; body = new byte[l]; };
- }
-
- /** 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());
- }
-
- /** 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)
- throws IOException {
- this.outStream = new java.io.DataOutputStream(o);
- this.inStream = new java.io.DataInputStream(i);
+ protected TorControlConnection() {
this.waiters = new LinkedList();
}
- /** helper: sends a single (unfragmentable) command to Tor */
- protected final void sendCommand0(int type, byte[] cmd)
- throws IOException {
- int length = cmd == null ? 0 : cmd.length;
- outStream.writeShort((short)length);
- outStream.writeShort(type);
- if (cmd != null)
- outStream.write(cmd);
- }
-
- /** helper: sends a single (possibly fragmented) command to Tor */
- protected void sendCommand(short type, byte[] cmd) throws IOException {
- synchronized(this.outStream) {
- if (cmd == null || cmd.length <= 65535) {
- sendCommand0(type, cmd);
- return;
- }
- int length = cmd.length;
- outStream.writeShort(65535);
- outStream.writeShort(CMD_FRAGMENTHEADER);
- outStream.writeShort(type);
- outStream.writeInt(length);
- outStream.write(cmd, 0, 65535);
- for (int pos=65535; pos < length; pos += 65535) {
- int flen = length-pos < 65535 ? length-pos : 65535;
- outStream.writeShort(flen);
- outStream.writeShort(CMD_FRAGMENT);
- this.outStream.write(cmd, pos, flen);
- }
- }
- }
-
- /** helper: read a possibly fragmented command from Tor */
- protected final Cmd readCommand0() throws IOException {
- int len = this.inStream.readUnsignedShort();
- int cmd = this.inStream.readUnsignedShort();
- byte[] result = new byte[len];
- this.inStream.readFully(result);
- return new Cmd(cmd, result);
- }
-
- /** Read a command from Tor, defragmenting as necessary */
- protected Cmd readCommand() throws IOException {
- synchronized (inStream) {
- Cmd c = readCommand0();
- if (c.type != CMD_FRAGMENT && c.type != CMD_FRAGMENTHEADER)
- return c;
-
- if (c.type == CMD_FRAGMENT)
- throw new TorControlSyntaxError("Fragment without header");
-
- int realType = Bytes.getU16(c.body, 0);
- int realLen = Bytes.getU32(c.body, 2);
-
- Cmd out = new Cmd(realType, realLen);
- System.arraycopy(c.body, 6, out.body, 0, c.body.length-6);
- int pos = c.body.length-6;
- while (pos < realLen) {
- c = readCommand0();
- if (c.type != CMD_FRAGMENT)
- throw new TorControlSyntaxError("Incomplete fragmented message");
- System.arraycopy(c.body, 0, out.body, pos, c.body.length);
- pos += c.body.length;
- }
- return out;
- }
- }
/** Set the EventHandler object that will be notified of any
* events Tor delivers to this connection. To make Tor send us
@@ -159,123 +70,8 @@
return th;
}
- /** helper: implement the main background loop. */
- protected void react() throws IOException {
- while (true) {
- Cmd c = readCommand();
- if (c.type == CMD_EVENT)
- handleEvent(c);
- else {
- Waiter w;
- synchronized (waiters) {
- w = (Waiter) waiters.removeFirst();
- }
- w.setResponse(c);
- }
- }
- }
-
- /** helper: Send a command and wait for the next reponse type command
- * to be received (in order) */
- protected synchronized Cmd _sendAndWaitForResponse(short type, byte[] cmd)
- throws IOException {
- Waiter w = new Waiter();
- synchronized (waiters) {
- sendCommand(type, cmd);
- waiters.addLast(w);
- }
- return w.getResponse();
- }
-
- /** Send a message to Tor, and wait for a respose.
- *
- * @throw TorControlError if Tor tells us about an error
- * @throw TorControlSyntaxError if the response type wasn't exType1...4
- **/
- protected Cmd sendAndWaitForResponse(short type, byte[] cmd,
- short exType1, short exType2, short exType3, short exType4)
- throws IOException {
-
- Cmd c = _sendAndWaitForResponse(type, cmd);
- if (c.type == CMD_ERROR)
- throw new TorControlError(Bytes.getU16(c.body, 0),
- Bytes.getNulTerminatedStr(c.body, 2));
- if (c.type == exType1 || c.type == exType2 || c.type == exType3 ||
- c.type == exType4)
- return c;
-
- throw new TorControlSyntaxError("Unexpected reply type: "+c.type);
- }
-
- protected Cmd sendAndWaitForResponse(short type, byte[] cmd)
- throws IOException {
- return sendAndWaitForResponse(type, cmd, CMD_DONE, CMD_DONE, CMD_DONE, CMD_DONE);
- }
-
-
- protected Cmd sendAndWaitForResponse(short type, byte[] cmd, short exType1)
- throws IOException {
- return sendAndWaitForResponse(type, cmd, exType1, exType1, exType1,
- exType1);
- }
-
- protected Cmd sendAndWaitForResponse(short type, byte[] cmd,
- short exType1, short exType2)
- throws IOException {
- return sendAndWaitForResponse(type, cmd, exType1, exType2, exType2,
- exType2);
- }
-
-
- protected Cmd sendAndWaitForResponse(short type, byte[] cmd,
- short exType1, short exType2, short exType3)
- throws IOException {
- return sendAndWaitForResponse(type, cmd, exType1, exType2, exType3,
- exType3);
- }
-
- /** Helper: decode a CMD_EVENT command and dispatch it to our
- * EventHandler (if any). */
- protected void handleEvent(Cmd c) {
- if (handler == null)
- return;
- int type = Bytes.getU16(c.body, 0);
+ protected abstract void react() throws IOException;
- switch (type) {
- case EVENT_CIRCSTATUS:
- handler.circuitStatus(c.body[2],
- (int)Bytes.getU32(c.body, 3),
- Bytes.getNulTerminatedStr(c.body, 7));
- break;
- case EVENT_STREAMSTATUS:
- handler.streamStatus(c.body[2],
- (int)Bytes.getU32(c.body, 3),
- Bytes.getNulTerminatedStr(c.body, 7));
- break;
- case EVENT_ORCONNSTATUS:
- handler.orConnStatus(c.body[2],
- Bytes.getNulTerminatedStr(c.body, 3));
- break;
- case EVENT_BANDWIDTH:
- handler.bandwidthUsed(Bytes.getU32(c.body, 2),
- Bytes.getU32(c.body, 6));
- break;
- case EVENT_NEWDESCRIPTOR:
- List lst = new ArrayList();
- Bytes.splitStr(lst, c.body, 2, (byte)',');
- handler.newDescriptors(lst);
- break;
- case EVENT_MSG_DEBUG:
- case EVENT_MSG_INFO:
- case EVENT_MSG_NOTICE:
- case EVENT_MSG_WARN:
- case EVENT_MSG_ERROR:
- handler.message(type, Bytes.getNulTerminatedStr(c.body, 2));
- break;
- default:
- throw new TorControlSyntaxError("Unrecognized event type.");
- }
- }
/** Change the value of the configuration option 'key' to 'val'.
*/
@@ -285,17 +81,6 @@
setConf(lst);
}
- /** Change the values of the configuration options stored in
- * 'kvList'. (The format is "key value"). */
- public void setConf(Collection kvList) throws IOException {
- StringBuffer b = new StringBuffer();
- for (Iterator it = kvList.iterator(); it.hasNext(); ) {
- String kv = (String) it.next();
- b.append(kv).append("\n");
- }
- sendAndWaitForResponse(CMD_SETCONF, b.toString().getBytes());
- }
-
/** Change the values of the configuration options stored in kvMap. */
public void setConf(Map kvMap) throws IOException {
List lst = new ArrayList();
@@ -306,6 +91,10 @@
setConf(lst);
}
+ /** Change the values of the configuration options stored in
+ * 'kvList'. (The format is "key value"). */
+ public abstract void setConf(Collection kvList) throws IOException;
+
/** Return the value of the configuration option 'key' */
public String getConf(String key) throws IOException {
List lst = new ArrayList();
@@ -315,82 +104,26 @@
}
/** Return a key-value map for the configuration options in 'keys' */
- public Map getConf(Collection keys) throws IOException {
- StringBuffer s = new StringBuffer();
- for (Iterator it = keys.iterator(); it.hasNext(); ) {
- String key = (String) it.next();
- s.append(key).append("\n");
- }
- Cmd c = sendAndWaitForResponse(CMD_GETCONF, s.toString().getBytes(),
- CMD_CONFVALUE);
- List lines = new ArrayList();
- Bytes.splitStr(lines, c.body, 0, (byte)'\n');
- Map result = new HashMap();
- for (Iterator it = lines.iterator(); it.hasNext(); ) {
- String kv = (String) it.next();
- int idx = kv.indexOf(' ');
- result.put(kv.substring(0, idx),
- kv.substring(idx+1));
- }
- return result;
- }
+ public abstract Map getConf(Collection keys) throws IOException;
/** Tell Tor to begin sending us events of the types listed in 'events'.
* Elements must be one of the EVENT_* values from TorControlCommands */
- public void setEvents(List events) throws IOException {
- byte[] ba = new byte[events.size() * 2];
- int i;
- Iterator it;
- for(i=0, it = events.iterator(); it.hasNext(); i += 2) {
- short event = ((Number)it.next()).shortValue();
- Bytes.setU16(ba, i, event);
- }
- sendAndWaitForResponse(CMD_SETEVENTS, ba);
- System.out.println("OK");
- }
+ public abstract void setEvents(List events) throws IOException;
/** Send Tor an authentication sequence 'auth' */
// XXXX more info about how to set this up securely.
- public void authenticate(byte[] auth) throws IOException {
- if (auth == null)
- auth = new byte[0];
- sendAndWaitForResponse(CMD_AUTH, auth);
- }
+ public abstract void authenticate(byte[] auth) throws IOException;
/** Tell Tor to save the value of its configuration to disk. */
- public void saveConf() throws IOException {
- sendAndWaitForResponse(CMD_SAVECONF, new byte[0]);
- }
+ public abstract void saveConf() throws IOException;
/** Send a signal to the Tor process. */
- public void signal(int signal) throws IOException {
- if (signal != SIGNAL_HUP && signal != SIGNAL_INT &&
- signal != SIGNAL_USR1 && signal != SIGNAL_USR2 &&
- signal != SIGNAL_TERM)
- throw new Error("Unrecognized value for signal()");
- byte[] ba = { (byte)signal };
- sendAndWaitForResponse(CMD_SIGNAL, ba);
- }
+ public abstract void signal(String signal) throws IOException;
/** Tell Tor to replace incoming addresses with those as listed in 'kvLines'.
*/
- public Map mapAddresses(Collection kvLines) throws IOException {
- StringBuffer sb = new StringBuffer();
- for (Iterator it = kvLines.iterator(); it.hasNext(); ) {
- sb.append((String)it.next()).append("\n");
- }
- Cmd c = sendAndWaitForResponse(CMD_MAPADDRESS, sb.toString().getBytes());
- Map result = new HashMap();
- List lst = new ArrayList();
- Bytes.splitStr(lst, c.body, 0, (byte)'\n');
- for (Iterator it = lst.iterator(); it.hasNext(); ) {
- String kv = (String) it.next();
- int idx = kv.indexOf(' ');
- result.put(kv.substring(0, idx),
- kv.substring(idx+1));
- }
- return result;
- }
+ public abstract Map mapAddresses(Collection kvLines) throws IOException;
+
public Map mapAddresses(Map addresses) throws IOException {
List kvList = new ArrayList();
for (Iterator it = addresses.entrySet().iterator(); it.hasNext(); ) {
@@ -399,6 +132,7 @@
}
return mapAddresses(kvList);
}
+
public String mapAddress(String fromAddr, String toAddr) throws IOException {
List lst = new ArrayList();
lst.add(fromAddr+" "+toAddr+"\n");
@@ -407,26 +141,7 @@
}
/** Look up the information values listed in keys. */
- public Map getInfo(Collection keys) throws IOException {
- StringBuffer sb = new StringBuffer();
- for (Iterator it = keys.iterator(); it.hasNext(); ) {
- sb.append(((String)it.next())+"\n");
- }
- Cmd c = sendAndWaitForResponse(CMD_GETINFO, sb.toString().getBytes(),
- CMD_INFOVALUE);
- Map m = new HashMap();
- List lst = new ArrayList();
- Bytes.splitStr(lst, c.body, 0, (byte)0);
- if ((lst.size() % 2) != 0)
- throw new TorControlSyntaxError(
- "Odd number of substrings from GETINFO");
- for (Iterator it = lst.iterator(); it.hasNext(); ) {
- Object k = it.next();
- Object v = it.next();
- m.put(k, v);
- }
- return m;
- }
+ public abstract Map getInfo(Collection keys) throws IOException;
/** Return the value of the information field 'key' */
public String getInfo(String key) throws IOException {
@@ -440,62 +155,29 @@
* Tell Tor to extend the circuit identified by 'circID' through the
* servers named in the list 'path'.
*/
- public int extendCircuit(int circID, String path) throws IOException {
- byte[] p = path.getBytes();
- byte[] ba = new byte[p.length+4];
- Bytes.setU32(ba, 0, circID);
- System.arraycopy(p, 0, ba, 4, p.length);
- Cmd c = sendAndWaitForResponse(CMD_EXTENDCIRCUIT, ba);
- return Bytes.getU32(c.body, 0);
- }
+ public abstract int extendCircuit(String circID, String path) throws IOException;
/**
* Tell Tor to attach the stream identified by 'streamID' to the circuit
* identified by 'circID'.
*/
- public void attachStream(int streamID, int circID) throws IOException {
- byte[] ba = new byte[8];
- Bytes.setU32(ba, 0, streamID);
- Bytes.setU32(ba, 4, circID);
- sendAndWaitForResponse(CMD_ATTACHSTREAM, ba);
- }
+ public abstract void attachStream(String streamID, String circID) throws IOException;
/** Tell Tor about the server descriptor in 'desc' */
- public String postDescriptor(byte[] desc) throws IOException {
- return new String(
- sendAndWaitForResponse(CMD_POSTDESCRIPTOR, desc).body);
- }
+ public abstract String postDescriptor(String desc) throws IOException;
/** Tell Tor to change the target of the stream identified by 'streamID'
* to 'address'.
*/
- public void redirectStream(int streamID, String address) throws IOException {
- byte[] addr = address.getBytes();
- byte[] ba = new byte[addr.length+4];
- Bytes.setU32(ba, 0, streamID);
- System.arraycopy(addr, 0, ba, 4, addr.length);
- sendAndWaitForResponse(CMD_REDIRECTSTREAM, ba);
- }
+ public abstract void redirectStream(String streamID, String address) throws IOException;
/** Tell Tor to close the stream identified by 'streamID'.
*/
- public void closeStream(int streamID, byte reason, byte flags)
- throws IOException {
- byte[] ba = new byte[6];
- Bytes.setU32(ba, 0, streamID);
- ba[4] = reason;
- ba[5] = flags;
- sendAndWaitForResponse(CMD_CLOSESTREAM, ba);
- }
+ public abstract void closeStream(String streamID, byte reason, byte flags)
+ throws IOException;
/** Tell Tor to close the circuit identified by 'streamID'.
*/
- public void closeCircuit(int circID, byte flags) throws IOException {
- byte[] ba = new byte[5];
- Bytes.setU32(ba, 0, circID);
- ba[4] = flags;
- sendAndWaitForResponse(CMD_CLOSECIRCUIT, ba);
- }
-
+ public abstract void closeCircuit(String circID, byte flags) throws IOException;
-}
\ No newline at end of file
+}
--- NEW FILE: TorControlConnection0.java ---
// $Id: TorControlConnection0.java,v 1.1 2005/06/21 21:49:30 nickm Exp $
// Copyright 2005 Nick Mathewson, Roger Dingledine
// See LICENSE file for copying information
package net.freehaven.tor.control;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** DOCDOC */
public class TorControlConnection0 extends TorControlConnection
implements TorControlCommands
{
protected java.io.DataOutputStream outStream;
protected java.io.DataInputStream inStream;
static class Cmd {
public int type;
public byte[] body;
Cmd(int t, byte[] b) { type = t; body = b; }
Cmd(int t, int l) { type = t; body = new byte[l]; };
}
/** 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 TorControlConnection0(java.net.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 TorControlConnection0(java.io.InputStream i, java.io.OutputStream o)
throws IOException {
this.outStream = new java.io.DataOutputStream(o);
this.inStream = new java.io.DataInputStream(i);
this.waiters = new LinkedList();
}
/** helper: sends a single (unfragmentable) command to Tor */
protected final void sendCommand0(int type, byte[] cmd)
throws IOException {
int length = cmd == null ? 0 : cmd.length;
outStream.writeShort((short)length);
outStream.writeShort(type);
if (cmd != null)
outStream.write(cmd);
}
/** helper: sends a single (possibly fragmented) command to Tor */
protected void sendCommand(short type, byte[] cmd) throws IOException {
synchronized(this.outStream) {
if (cmd == null || cmd.length <= 65535) {
sendCommand0(type, cmd);
return;
}
int length = cmd.length;
outStream.writeShort(65535);
outStream.writeShort(CMD_FRAGMENTHEADER);
outStream.writeShort(type);
outStream.writeInt(length);
outStream.write(cmd, 0, 65535);
for (int pos=65535; pos < length; pos += 65535) {
int flen = length-pos < 65535 ? length-pos : 65535;
outStream.writeShort(flen);
outStream.writeShort(CMD_FRAGMENT);
this.outStream.write(cmd, pos, flen);
}
}
}
/** helper: read a possibly fragmented command from Tor */
protected final Cmd readCommand0() throws IOException {
int len = this.inStream.readUnsignedShort();
int cmd = this.inStream.readUnsignedShort();
byte[] result = new byte[len];
this.inStream.readFully(result);
return new Cmd(cmd, result);
}
/** Read a command from Tor, defragmenting as necessary */
protected Cmd readCommand() throws IOException {
synchronized (inStream) {
Cmd c = readCommand0();
if (c.type != CMD_FRAGMENT && c.type != CMD_FRAGMENTHEADER)
return c;
if (c.type == CMD_FRAGMENT)
throw new TorControlSyntaxError("Fragment without header");
int realType = Bytes.getU16(c.body, 0);
int realLen = Bytes.getU32(c.body, 2);
Cmd out = new Cmd(realType, realLen);
System.arraycopy(c.body, 6, out.body, 0, c.body.length-6);
int pos = c.body.length-6;
while (pos < realLen) {
c = readCommand0();
if (c.type != CMD_FRAGMENT)
throw new TorControlSyntaxError("Incomplete fragmented message");
System.arraycopy(c.body, 0, out.body, pos, c.body.length);
pos += c.body.length;
}
return out;
}
}
/** helper: implement the main background loop. */
protected void react() throws IOException {
while (true) {
Cmd c = readCommand();
if (c.type == CMD_EVENT)
handleEvent(c);
else {
Waiter w;
synchronized (waiters) {
w = (Waiter) waiters.removeFirst();
}
w.setResponse(c);
}
}
}
/** helper: Send a command and wait for the next reponse type command
* to be received (in order) */
protected synchronized Cmd _sendAndWaitForResponse(short type, byte[] cmd)
throws IOException {
Waiter w = new Waiter();
synchronized (waiters) {
sendCommand(type, cmd);
waiters.addLast(w);
}
return (Cmd) w.getResponse();
}
/** Send a message to Tor, and wait for a respose.
*
* @throw TorControlError if Tor tells us about an error
* @throw TorControlSyntaxError if the response type wasn't exType1...4
**/
protected Cmd sendAndWaitForResponse(short type, byte[] cmd,
short exType1, short exType2, short exType3, short exType4)
throws IOException {
Cmd c = _sendAndWaitForResponse(type, cmd);
if (c.type == CMD_ERROR)
throw new TorControlError(Bytes.getU16(c.body, 0),
Bytes.getNulTerminatedStr(c.body, 2));
if (c.type == exType1 || c.type == exType2 || c.type == exType3 ||
c.type == exType4)
return c;
throw new TorControlSyntaxError("Unexpected reply type: "+c.type);
}
protected Cmd sendAndWaitForResponse(short type, byte[] cmd)
throws IOException {
return sendAndWaitForResponse(type, cmd, CMD_DONE, CMD_DONE, CMD_DONE, CMD_DONE);
}
protected Cmd sendAndWaitForResponse(short type, byte[] cmd, short exType1)
throws IOException {
return sendAndWaitForResponse(type, cmd, exType1, exType1, exType1,
exType1);
}
protected Cmd sendAndWaitForResponse(short type, byte[] cmd,
short exType1, short exType2)
throws IOException {
return sendAndWaitForResponse(type, cmd, exType1, exType2, exType2,
exType2);
}
protected Cmd sendAndWaitForResponse(short type, byte[] cmd,
short exType1, short exType2, short exType3)
throws IOException {
return sendAndWaitForResponse(type, cmd, exType1, exType2, exType3,
exType3);
}
/** Helper: decode a CMD_EVENT command and dispatch it to our
* EventHandler (if any). */
protected void handleEvent(Cmd c) {
if (handler == null)
return;
int type = Bytes.getU16(c.body, 0);
switch (type) {
case EVENT_CIRCSTATUS:
handler.circuitStatus(CIRC_STATUS_NAMES[c.body[2]],
Bytes.getU32S(c.body, 3),
Bytes.getNulTerminatedStr(c.body, 7));
break;
case EVENT_STREAMSTATUS:
handler.streamStatus(STREAM_STATUS_NAMES[c.body[2]],
Bytes.getU32S(c.body, 3),
Bytes.getNulTerminatedStr(c.body, 7));
break;
case EVENT_ORCONNSTATUS:
handler.orConnStatus(OR_CONN_STATUS_NAMES[c.body[2]],
Bytes.getNulTerminatedStr(c.body, 3));
break;
case EVENT_BANDWIDTH:
handler.bandwidthUsed(Bytes.getU32(c.body, 2),
Bytes.getU32(c.body, 6));
break;
case EVENT_NEWDESCRIPTOR:
List lst = new ArrayList();
Bytes.splitStr(lst, c.body, 2, (byte)',');
handler.newDescriptors(lst);
break;
case EVENT_MSG_DEBUG:
case EVENT_MSG_INFO:
case EVENT_MSG_NOTICE:
case EVENT_MSG_WARN:
case EVENT_MSG_ERROR:
handler.message(type, Bytes.getNulTerminatedStr(c.body, 2));
break;
default:
throw new TorControlSyntaxError("Unrecognized event type.");
}
}
/** Change the values of the configuration options stored in
* 'kvList'. (The format is "key value"). */
public void setConf(Collection kvList) throws IOException {
StringBuffer b = new StringBuffer();
for (Iterator it = kvList.iterator(); it.hasNext(); ) {
String kv = (String) it.next();
b.append(kv).append("\n");
}
sendAndWaitForResponse(CMD_SETCONF, b.toString().getBytes());
}
public Map getConf(Collection keys) throws IOException {
StringBuffer s = new StringBuffer();
for (Iterator it = keys.iterator(); it.hasNext(); ) {
String key = (String) it.next();
s.append(key).append("\n");
}
Cmd c = sendAndWaitForResponse(CMD_GETCONF, s.toString().getBytes(),
CMD_CONFVALUE);
List lines = new ArrayList();
Bytes.splitStr(lines, c.body, 0, (byte)'\n');
Map result = new HashMap();
for (Iterator it = lines.iterator(); it.hasNext(); ) {
String kv = (String) it.next();
int idx = kv.indexOf(' ');
result.put(kv.substring(0, idx),
kv.substring(idx+1));
}
return result;
}
public void setEvents(List events) throws IOException {
byte[] ba = new byte[events.size() * 2];
int i;
Iterator it;
for(i=0, it = events.iterator(); it.hasNext(); i += 2) {
short event = ((Number)it.next()).shortValue();
Bytes.setU16(ba, i, event);
}
sendAndWaitForResponse(CMD_SETEVENTS, ba);
System.out.println("OK");
}
public void authenticate(byte[] auth) throws IOException {
if (auth == null)
auth = new byte[0];
sendAndWaitForResponse(CMD_AUTH, auth);
}
public void saveConf() throws IOException {
sendAndWaitForResponse(CMD_SAVECONF, new byte[0]);
}
public void signal(String signal) throws IOException {
int sig;
signal = signal.toUpperCase();
if (signal.equals("HUP") || signal.equals("RELOAD"))
sig = SIGNAL_HUP;
else if (signal.equals("INT") || signal.equals("SHUTDOWN"))
sig = SIGNAL_HUP;
else if (signal.equals("USR1") || signal.equals("DUMP"))
sig = SIGNAL_HUP;
else if (signal.equals("USR2") || signal.equals("DEBUG"))
sig = SIGNAL_HUP;
else if (signal.equals("TERM") || signal.equals("HALT"))
sig = SIGNAL_HUP;
else
throw new Error("Unrecognized value for signal()");
byte[] ba = { (byte)sig };
sendAndWaitForResponse(CMD_SIGNAL, ba);
}
public Map mapAddresses(Collection kvLines) throws IOException {
StringBuffer sb = new StringBuffer();
for (Iterator it = kvLines.iterator(); it.hasNext(); ) {
sb.append((String)it.next()).append("\n");
}
Cmd c = sendAndWaitForResponse(CMD_MAPADDRESS, sb.toString().getBytes());
Map result = new HashMap();
List lst = new ArrayList();
Bytes.splitStr(lst, c.body, 0, (byte)'\n');
for (Iterator it = lst.iterator(); it.hasNext(); ) {
String kv = (String) it.next();
int idx = kv.indexOf(' ');
result.put(kv.substring(0, idx),
kv.substring(idx+1));
}
return result;
}
public Map getInfo(Collection keys) throws IOException {
StringBuffer sb = new StringBuffer();
for (Iterator it = keys.iterator(); it.hasNext(); ) {
sb.append(((String)it.next())+"\n");
}
Cmd c = sendAndWaitForResponse(CMD_GETINFO, sb.toString().getBytes(),
CMD_INFOVALUE);
Map m = new HashMap();
List lst = new ArrayList();
Bytes.splitStr(lst, c.body, 0, (byte)0);
if ((lst.size() % 2) != 0)
throw new TorControlSyntaxError(
"Odd number of substrings from GETINFO");
for (Iterator it = lst.iterator(); it.hasNext(); ) {
Object k = it.next();
Object v = it.next();
m.put(k, v);
}
return m;
}
public int extendCircuit(String circID, String path) throws IOException {
byte[] p = path.getBytes();
byte[] ba = new byte[p.length+4];
Bytes.setU32(ba, 0, (int)Long.parseLong(circID));
System.arraycopy(p, 0, ba, 4, p.length);
Cmd c = sendAndWaitForResponse(CMD_EXTENDCIRCUIT, ba);
return Bytes.getU32(c.body, 0);
}
public void attachStream(String streamID, String circID)
throws IOException {
byte[] ba = new byte[8];
Bytes.setU32(ba, 0, (int)Long.parseLong(streamID));
Bytes.setU32(ba, 4, (int)Long.parseLong(circID));
sendAndWaitForResponse(CMD_ATTACHSTREAM, ba);
}
/** Tell Tor about the server descriptor in 'desc' */
public String postDescriptor(String desc) throws IOException {
return new String(
sendAndWaitForResponse(CMD_POSTDESCRIPTOR, desc.getBytes()).body);
}
/** Tell Tor to change the target of the stream identified by 'streamID'
* to 'address'.
*/
public void redirectStream(String streamID, String address) throws IOException {
byte[] addr = address.getBytes();
byte[] ba = new byte[addr.length+4];
Bytes.setU32(ba, 0, (int)Long.parseLong(streamID));
System.arraycopy(addr, 0, ba, 4, addr.length);
sendAndWaitForResponse(CMD_REDIRECTSTREAM, ba);
}
/** Tell Tor to close the stream identified by 'streamID'.
*/
public void closeStream(String streamID, byte reason, byte flags)
throws IOException {
byte[] ba = new byte[6];
Bytes.setU32(ba, 0, (int)Long.parseLong(streamID));
ba[4] = reason;
ba[5] = flags;
sendAndWaitForResponse(CMD_CLOSESTREAM, ba);
}
/** Tell Tor to close the circuit identified by 'streamID'.
*/
public void closeCircuit(String circID, byte flags) throws IOException {
byte[] ba = new byte[5];
Bytes.setU32(ba, 0, (int)Long.parseLong(circID));
ba[4] = flags;
sendAndWaitForResponse(CMD_CLOSECIRCUIT, ba);
}
}
More information about the tor-commits
mailing list