mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Add an absurd amount of logging.
This commit is contained in:
@@ -13,7 +13,6 @@ import java.io.PrintWriter;
|
|||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -22,11 +21,18 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/** A connection to a running Tor process as specified in control-spec.txt. */
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A connection to a running Tor process as specified in control-spec.txt.
|
||||||
|
*/
|
||||||
public class TorControlConnection implements TorControlCommands {
|
public class TorControlConnection implements TorControlCommands {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(TorControlConnection.class.getName());
|
||||||
|
|
||||||
private final LinkedList<Waiter> waiters;
|
private final LinkedList<Waiter> waiters;
|
||||||
private final BufferedReader input;
|
private final BufferedReader input;
|
||||||
private final Writer output;
|
private final Writer output;
|
||||||
@@ -42,24 +48,45 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
List<ReplyLine> response; // Locking: this
|
List<ReplyLine> response; // Locking: this
|
||||||
boolean interrupted;
|
boolean interrupted;
|
||||||
|
|
||||||
synchronized List<ReplyLine> getResponse() throws InterruptedException {
|
List<ReplyLine> getResponse() throws InterruptedException {
|
||||||
|
LOG.info("Entering synchronized (waiter " + hashCode() + ")");
|
||||||
|
synchronized (this) {
|
||||||
|
LOG.info("Entered synchronized (waiter " + hashCode() + ")");
|
||||||
while (response == null) {
|
while (response == null) {
|
||||||
|
LOG.info("Waiter " + hashCode() + " waiting for response");
|
||||||
wait();
|
wait();
|
||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
|
LOG.info("Waiter " + hashCode() + " interrupted");
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOG.info("Waiter " + hashCode() + " got response " + response);
|
||||||
|
LOG.info("Leaving synchronized (waiter " + hashCode() + ")");
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setResponse(List<ReplyLine> response) {
|
|
||||||
this.response = response;
|
|
||||||
notifyAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void interrupt() {
|
void setResponse(List<ReplyLine> response) {
|
||||||
|
LOG.info("Entering synchronized (waiter " + hashCode() + ")");
|
||||||
|
synchronized (this) {
|
||||||
|
LOG.info("Entered synchronized (waiter " + hashCode() + ")");
|
||||||
|
LOG.info("Setting response for waiter " + hashCode() + ": "
|
||||||
|
+ response);
|
||||||
|
this.response = response;
|
||||||
|
notifyAll();
|
||||||
|
LOG.info("Leaving synchronized (waiter " + hashCode() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void interrupt() {
|
||||||
|
LOG.info("Entering synchronized (waiter " + hashCode() + ")");
|
||||||
|
synchronized (this) {
|
||||||
|
LOG.info("Entered synchronized (waiter " + hashCode() + ")");
|
||||||
|
LOG.info("Interrupting waiter " + hashCode());
|
||||||
interrupted = true;
|
interrupted = true;
|
||||||
notifyAll();
|
notifyAll();
|
||||||
|
LOG.info("Leaving synchronized (waiter " + hashCode() + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,18 +97,28 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
final String rest;
|
final String rest;
|
||||||
|
|
||||||
ReplyLine(String status, String msg, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return status + " " + msg + " " + rest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a new TorControlConnection to communicate with Tor over
|
/**
|
||||||
|
* Create a new TorControlConnection to communicate with Tor over
|
||||||
* a given socket. After calling this constructor, it is typical to
|
* a given socket. After calling this constructor, it is typical to
|
||||||
* call launchThread and authenticate. */
|
* call launchThread and authenticate.
|
||||||
|
*/
|
||||||
public TorControlConnection(Socket connection) throws IOException {
|
public TorControlConnection(Socket connection) throws IOException {
|
||||||
this(connection.getInputStream(), connection.getOutputStream());
|
this(connection.getInputStream(), connection.getOutputStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a new TorControlConnection to communicate with Tor over
|
/**
|
||||||
|
* Create a new TorControlConnection to communicate with Tor over
|
||||||
* an arbitrary pair of data streams.
|
* an arbitrary pair of data streams.
|
||||||
*/
|
*/
|
||||||
public TorControlConnection(InputStream i, OutputStream o) {
|
public TorControlConnection(InputStream i, OutputStream o) {
|
||||||
@@ -94,7 +131,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
this.input = (BufferedReader) i;
|
this.input = (BufferedReader) i;
|
||||||
else
|
else
|
||||||
this.input = new BufferedReader(i);
|
this.input = new BufferedReader(i);
|
||||||
this.waiters = new LinkedList<Waiter>();
|
this.waiters = new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void writeEscaped(String s) throws IOException {
|
protected final void writeEscaped(String s) throws IOException {
|
||||||
@@ -102,13 +139,13 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
while (st.hasMoreTokens()) {
|
while (st.hasMoreTokens()) {
|
||||||
String line = st.nextToken();
|
String line = st.nextToken();
|
||||||
if (line.startsWith("."))
|
if (line.startsWith("."))
|
||||||
line = "."+line;
|
line = "." + line;
|
||||||
if (line.endsWith("\r"))
|
if (line.endsWith("\r"))
|
||||||
line += "\n";
|
line += "\n";
|
||||||
else
|
else
|
||||||
line += "\r\n";
|
line += "\r\n";
|
||||||
if (debugOutput != null)
|
if (debugOutput != null)
|
||||||
debugOutput.print(">> "+line);
|
debugOutput.print(">> " + line);
|
||||||
output.write(line);
|
output.write(line);
|
||||||
}
|
}
|
||||||
output.write(".\r\n");
|
output.write(".\r\n");
|
||||||
@@ -116,12 +153,11 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
debugOutput.print(">> .\n");
|
debugOutput.print(">> .\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final String quote(String s) {
|
protected static String quote(String s) {
|
||||||
StringBuffer sb = new StringBuffer("\"");
|
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);
|
char c = s.charAt(i);
|
||||||
switch (c)
|
switch (c) {
|
||||||
{
|
|
||||||
case '\r':
|
case '\r':
|
||||||
case '\n':
|
case '\n':
|
||||||
case '\\':
|
case '\\':
|
||||||
@@ -135,7 +171,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final ArrayList<ReplyLine> readReply() throws IOException {
|
protected final ArrayList<ReplyLine> readReply() throws IOException {
|
||||||
ArrayList<ReplyLine> reply = new ArrayList<ReplyLine>();
|
ArrayList<ReplyLine> reply = new ArrayList<>();
|
||||||
char c;
|
char c;
|
||||||
do {
|
do {
|
||||||
String line = input.readLine();
|
String line = input.readLine();
|
||||||
@@ -151,10 +187,11 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
" broke down while receiving reply!");
|
" broke down while receiving reply!");
|
||||||
}
|
}
|
||||||
if (debugOutput != null)
|
if (debugOutput != null)
|
||||||
debugOutput.println("<< "+line);
|
debugOutput.println("<< " + line);
|
||||||
if (line.length() < 4)
|
if (line.length() < 4)
|
||||||
throw new TorControlSyntaxError("Line (\""+line+"\") too short");
|
throw new TorControlSyntaxError(
|
||||||
String status = line.substring(0,3);
|
"Line (\"" + line + "\") too short");
|
||||||
|
String status = line.substring(0, 3);
|
||||||
c = line.charAt(3);
|
c = line.charAt(3);
|
||||||
String msg = line.substring(4);
|
String msg = line.substring(4);
|
||||||
String rest = null;
|
String rest = null;
|
||||||
@@ -163,7 +200,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
while (true) {
|
while (true) {
|
||||||
line = input.readLine();
|
line = input.readLine();
|
||||||
if (debugOutput != null)
|
if (debugOutput != null)
|
||||||
debugOutput.print("<< "+line);
|
debugOutput.print("<< " + line);
|
||||||
if (line.equals("."))
|
if (line.equals("."))
|
||||||
break;
|
break;
|
||||||
else if (line.startsWith("."))
|
else if (line.startsWith("."))
|
||||||
@@ -178,36 +215,61 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized List<ReplyLine> sendAndWaitForResponse(String s,
|
protected List<ReplyLine> sendAndWaitForResponse(String s,
|
||||||
String rest) throws IOException {
|
String rest) throws IOException {
|
||||||
if (parseThreadException != null) throw parseThreadException;
|
LOG.info("Entering synchronized (connection)");
|
||||||
|
synchronized (this) {
|
||||||
|
LOG.info("Entered synchronized (connection)");
|
||||||
|
LOG.info("Sending '" + s + "', '" + rest +
|
||||||
|
"' and waiting for response");
|
||||||
|
if (parseThreadException != null) {
|
||||||
|
LOG.info("Throwing previously caught exception "
|
||||||
|
+ parseThreadException);
|
||||||
|
throw parseThreadException;
|
||||||
|
}
|
||||||
checkThread();
|
checkThread();
|
||||||
Waiter w = new Waiter();
|
Waiter w = new Waiter();
|
||||||
|
LOG.info("Created waiter " + w.hashCode());
|
||||||
if (debugOutput != null)
|
if (debugOutput != null)
|
||||||
debugOutput.print(">> "+s);
|
debugOutput.print(">> " + s);
|
||||||
|
LOG.info("Entering synchronized (waiters)");
|
||||||
synchronized (waiters) {
|
synchronized (waiters) {
|
||||||
|
LOG.info("Entered synchronized (waiters)");
|
||||||
output.write(s);
|
output.write(s);
|
||||||
if (rest != null)
|
LOG.info("Wrote '" + s + "'");
|
||||||
|
if (rest != null) {
|
||||||
writeEscaped(rest);
|
writeEscaped(rest);
|
||||||
|
LOG.info("Wrote escaped '" + rest + "'");
|
||||||
|
}
|
||||||
output.flush();
|
output.flush();
|
||||||
|
LOG.info("Flushed output");
|
||||||
waiters.addLast(w);
|
waiters.addLast(w);
|
||||||
|
LOG.info("Added waiter, " + waiters.size() + " waiting");
|
||||||
|
LOG.info("Leaving synchronized (waiters)");
|
||||||
}
|
}
|
||||||
List<ReplyLine> lst;
|
List<ReplyLine> lst;
|
||||||
try {
|
try {
|
||||||
|
LOG.info("Getting response from waiter " + w.hashCode());
|
||||||
lst = w.getResponse();
|
lst = w.getResponse();
|
||||||
|
LOG.info("Got response from waiter " + w.hashCode() + ": " +
|
||||||
|
lst);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
throw new IOException("Interrupted");
|
throw new IOException("Interrupted");
|
||||||
}
|
}
|
||||||
for (Iterator<ReplyLine> i = lst.iterator(); i.hasNext(); ) {
|
for (Iterator<ReplyLine> i = lst.iterator(); i.hasNext(); ) {
|
||||||
ReplyLine c = i.next();
|
ReplyLine c = i.next();
|
||||||
if (! c.status.startsWith("2"))
|
if (!c.status.startsWith("2"))
|
||||||
throw new TorControlError("Error reply: "+c.msg);
|
throw new TorControlError("Error reply: " + c.msg);
|
||||||
}
|
}
|
||||||
|
LOG.info("Leaving synchronized (connection)");
|
||||||
return lst;
|
return lst;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Helper: decode a CMD_EVENT command and dispatch it to our
|
/**
|
||||||
* EventHandler (if any). */
|
* Helper: decode a CMD_EVENT command and dispatch it to our
|
||||||
|
* EventHandler (if any).
|
||||||
|
*/
|
||||||
protected void handleEvent(ArrayList<ReplyLine> events) {
|
protected void handleEvent(ArrayList<ReplyLine> events) {
|
||||||
if (handler == null)
|
if (handler == null)
|
||||||
return;
|
return;
|
||||||
@@ -216,7 +278,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
ReplyLine line = i.next();
|
ReplyLine line = i.next();
|
||||||
int idx = line.msg.indexOf(' ');
|
int idx = line.msg.indexOf(' ');
|
||||||
String tp = line.msg.substring(0, idx).toUpperCase();
|
String tp = line.msg.substring(0, idx).toUpperCase();
|
||||||
String rest = line.msg.substring(idx+1);
|
String rest = line.msg.substring(idx + 1);
|
||||||
if (tp.equals("CIRC")) {
|
if (tp.equals("CIRC")) {
|
||||||
List<String> lst = Bytes.splitStr(null, rest);
|
List<String> lst = Bytes.splitStr(null, rest);
|
||||||
handler.circuitStatus(lst.get(1),
|
handler.circuitStatus(lst.get(1),
|
||||||
@@ -253,7 +315,8 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Sets <b>w</b> as the PrintWriter for debugging output,
|
/**
|
||||||
|
* Sets <b>w</b> as the PrintWriter for debugging output,
|
||||||
* which writes out all messages passed between Tor and the controller.
|
* which writes out all messages passed between Tor and the controller.
|
||||||
* Outgoing messages are preceded by "\>\>" and incoming messages are preceded
|
* Outgoing messages are preceded by "\>\>" and incoming messages are preceded
|
||||||
* by "\<\<"
|
* by "\<\<"
|
||||||
@@ -262,7 +325,8 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
debugOutput = w;
|
debugOutput = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets <b>s</b> as the PrintStream for debugging output,
|
/**
|
||||||
|
* Sets <b>s</b> as the PrintStream for debugging output,
|
||||||
* which writes out all messages passed between Tor and the controller.
|
* which writes out all messages passed between Tor and the controller.
|
||||||
* Outgoing messages are preceded by "\>\>" and incoming messages are preceded
|
* Outgoing messages are preceded by "\>\>" and incoming messages are preceded
|
||||||
* by "\<\<"
|
* by "\<\<"
|
||||||
@@ -271,9 +335,11 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
debugOutput = new PrintWriter(s, true);
|
debugOutput = new PrintWriter(s, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the EventHandler object that will be notified of any
|
/**
|
||||||
|
* Set the EventHandler object that will be notified of any
|
||||||
* events Tor delivers to this connection. To make Tor send us
|
* events Tor delivers to this connection. To make Tor send us
|
||||||
* events, call setEvents(). */
|
* events, call setEvents().
|
||||||
|
*/
|
||||||
public void setEventHandler(EventHandler handler) {
|
public void setEventHandler(EventHandler handler) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
@@ -283,14 +349,20 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* This is necessary to handle asynchronous events and synchronous
|
* This is necessary to handle asynchronous events and synchronous
|
||||||
* responses that arrive independantly over the same socket.
|
* responses that arrive independantly over the same socket.
|
||||||
*/
|
*/
|
||||||
public synchronized Thread launchThread(boolean daemon) {
|
public Thread launchThread(boolean daemon) {
|
||||||
|
LOG.info("Entering synchronized (connection)");
|
||||||
|
synchronized (this) {
|
||||||
|
LOG.info("Entered synchronized (connection)");
|
||||||
ControlParseThread th = new ControlParseThread();
|
ControlParseThread th = new ControlParseThread();
|
||||||
|
LOG.info("Launching parse thread " + th.hashCode());
|
||||||
if (daemon)
|
if (daemon)
|
||||||
th.setDaemon(true);
|
th.setDaemon(true);
|
||||||
th.start();
|
th.start();
|
||||||
this.thread = th;
|
this.thread = th;
|
||||||
|
LOG.info("Leaving synchronized (connection)");
|
||||||
return th;
|
return th;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected class ControlParseThread extends Thread {
|
protected class ControlParseThread extends Thread {
|
||||||
|
|
||||||
@@ -299,82 +371,109 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
try {
|
try {
|
||||||
react();
|
react();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
LOG.info("Parse thread " + hashCode()
|
||||||
|
+ " caught exception " + ex);
|
||||||
parseThreadException = ex;
|
parseThreadException = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void checkThread() {
|
protected void checkThread() {
|
||||||
|
LOG.info("Entering synchronized (connection)");
|
||||||
|
synchronized (this) {
|
||||||
|
LOG.info("Entered synchronized (connection)");
|
||||||
if (thread == null)
|
if (thread == null)
|
||||||
launchThread(true);
|
launchThread(true);
|
||||||
|
LOG.info("Leaving synchronized (connection)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** helper: implement the main background loop. */
|
/**
|
||||||
|
* helper: implement the main background loop.
|
||||||
|
*/
|
||||||
protected void react() throws IOException {
|
protected void react() throws IOException {
|
||||||
while (true) {
|
while (true) {
|
||||||
ArrayList<ReplyLine> lst = readReply();
|
ArrayList<ReplyLine> lst = readReply();
|
||||||
|
LOG.info("Read reply: " + lst);
|
||||||
if (lst.isEmpty()) {
|
if (lst.isEmpty()) {
|
||||||
// interrupted queued waiters, there won't be any response.
|
// interrupted queued waiters, there won't be any response.
|
||||||
|
LOG.info("Entering synchronized (waiters)");
|
||||||
synchronized (waiters) {
|
synchronized (waiters) {
|
||||||
|
LOG.info("Entered synchronized (waiters)");
|
||||||
if (!waiters.isEmpty()) {
|
if (!waiters.isEmpty()) {
|
||||||
for (Waiter w : waiters) {
|
for (Waiter w : waiters) {
|
||||||
|
LOG.info("Interrupting waiter " + w.hashCode());
|
||||||
w.interrupt();
|
w.interrupt();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
LOG.info("No waiters");
|
||||||
}
|
}
|
||||||
|
LOG.info("Leaving synchronized (waiters)");
|
||||||
}
|
}
|
||||||
throw new IOException("Tor is no longer running");
|
throw new IOException("Tor is no longer running");
|
||||||
}
|
}
|
||||||
if ((lst.get(0)).status.startsWith("6"))
|
if ((lst.get(0)).status.startsWith("6")) {
|
||||||
|
LOG.info("Reply is an event");
|
||||||
handleEvent(lst);
|
handleEvent(lst);
|
||||||
else {
|
} else {
|
||||||
|
LOG.info("Entering synchronized (waiters)");
|
||||||
synchronized (waiters) {
|
synchronized (waiters) {
|
||||||
if (!waiters.isEmpty())
|
LOG.info("Entered synchronized (waiters)");
|
||||||
{
|
if (!waiters.isEmpty()) {
|
||||||
Waiter w;
|
Waiter w;
|
||||||
w = waiters.removeFirst();
|
w = waiters.removeFirst();
|
||||||
|
LOG.info("Setting response for waiter " + w.hashCode());
|
||||||
w.setResponse(lst);
|
w.setResponse(lst);
|
||||||
|
} else {
|
||||||
|
LOG.info("No waiters");
|
||||||
}
|
}
|
||||||
|
LOG.info("Leaving synchronized (waiters)");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Change the value of the configuration option 'key' to 'val'.
|
/**
|
||||||
|
* Change the value of the configuration option 'key' to 'val'.
|
||||||
*/
|
*/
|
||||||
public void setConf(String key, String value) throws IOException {
|
public void setConf(String key, String value) throws IOException {
|
||||||
List<String> lst = new ArrayList<String>();
|
List<String> lst = new ArrayList<>();
|
||||||
lst.add(key+" "+value);
|
lst.add(key + " " + value);
|
||||||
setConf(lst);
|
setConf(lst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Change the values of the configuration options stored in kvMap. */
|
/**
|
||||||
|
* Change the values of the configuration options stored in kvMap.
|
||||||
|
*/
|
||||||
public void setConf(Map<String, String> kvMap) throws IOException {
|
public void setConf(Map<String, String> kvMap) throws IOException {
|
||||||
List<String> lst = new ArrayList<String>();
|
List<String> lst = new ArrayList<>();
|
||||||
for (Iterator<Map.Entry<String,String>> it = kvMap.entrySet().iterator(); it.hasNext(); ) {
|
for (Iterator<Map.Entry<String, String>> it =
|
||||||
Map.Entry<String,String> ent = it.next();
|
kvMap.entrySet().iterator(); it.hasNext(); ) {
|
||||||
lst.add(ent.getKey()+" "+ent.getValue()+"\n");
|
Map.Entry<String, String> ent = it.next();
|
||||||
|
lst.add(ent.getKey() + " " + ent.getValue() + "\n");
|
||||||
}
|
}
|
||||||
setConf(lst);
|
setConf(lst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Changes the values of the configuration options stored in
|
/**
|
||||||
|
* Changes the values of the configuration options stored in
|
||||||
* <b>kvList</b>. Each list element in <b>kvList</b> is expected to be
|
* <b>kvList</b>. Each list element in <b>kvList</b> is expected to be
|
||||||
* String of the format "key value".
|
* String of the format "key value".
|
||||||
*
|
* <p>
|
||||||
* Tor behaves as though it had just read each of the key-value pairs
|
* Tor behaves as though it had just read each of the key-value pairs
|
||||||
* from its configuration file. Keywords with no corresponding values have
|
* from its configuration file. Keywords with no corresponding values have
|
||||||
* their configuration values reset to their defaults. setConf is
|
* their configuration values reset to their defaults. setConf is
|
||||||
* all-or-nothing: if there is an error in any of the configuration settings,
|
* all-or-nothing: if there is an error in any of the configuration settings,
|
||||||
* Tor sets none of them.
|
* Tor sets none of them.
|
||||||
*
|
* <p>
|
||||||
* When a configuration option takes multiple values, or when multiple
|
* When a configuration option takes multiple values, or when multiple
|
||||||
* configuration keys form a context-sensitive group (see getConf below), then
|
* 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
|
* 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
|
* the others. For example, if two ORBindAddress values are configured, and a
|
||||||
* command arrives containing a single ORBindAddress value, the new
|
* command arrives containing a single ORBindAddress value, the new
|
||||||
* command's value replaces the two old values.
|
* command's value replaces the two old values.
|
||||||
*
|
* <p>
|
||||||
* To remove all settings for a given option entirely (and go back to its
|
* 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.
|
||||||
*/
|
*/
|
||||||
@@ -387,14 +486,15 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
int i = kv.indexOf(' ');
|
int i = kv.indexOf(' ');
|
||||||
if (i == -1)
|
if (i == -1)
|
||||||
b.append(" ").append(kv);
|
b.append(" ").append(kv);
|
||||||
b.append(" ").append(kv.substring(0,i)).append("=")
|
b.append(" ").append(kv.substring(0, i)).append("=")
|
||||||
.append(quote(kv.substring(i+1)));
|
.append(quote(kv.substring(i + 1)));
|
||||||
}
|
}
|
||||||
b.append("\r\n");
|
b.append("\r\n");
|
||||||
sendAndWaitForResponse(b.toString(), null);
|
sendAndWaitForResponse(b.toString(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Try to reset the values listed in the collection 'keys' to their
|
/**
|
||||||
|
* Try to reset the values listed in the collection 'keys' to their
|
||||||
* default values.
|
* default values.
|
||||||
**/
|
**/
|
||||||
public void resetConf(Collection<String> keys) throws IOException {
|
public void resetConf(Collection<String> keys) throws IOException {
|
||||||
@@ -409,26 +509,30 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
sendAndWaitForResponse(b.toString(), null);
|
sendAndWaitForResponse(b.toString(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the value of the configuration option 'key' */
|
/**
|
||||||
|
* Return the value of the configuration option 'key'
|
||||||
|
*/
|
||||||
public List<ConfigEntry> getConf(String key) throws IOException {
|
public List<ConfigEntry> getConf(String key) throws IOException {
|
||||||
List<String> lst = new ArrayList<String>();
|
List<String> lst = new ArrayList<>();
|
||||||
lst.add(key);
|
lst.add(key);
|
||||||
return getConf(lst);
|
return getConf(lst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Requests the values of the configuration variables listed in <b>keys</b>.
|
/**
|
||||||
|
* Requests the values of the configuration variables listed in <b>keys</b>.
|
||||||
* Results are returned as a list of ConfigEntry objects.
|
* Results are returned as a list of ConfigEntry objects.
|
||||||
*
|
* <p>
|
||||||
* If an option appears multiple times in the configuration, all of its
|
* If an option appears multiple times in the configuration, all of its
|
||||||
* key-value pairs are returned in order.
|
* key-value pairs are returned in order.
|
||||||
*
|
* <p>
|
||||||
* Some options are context-sensitive, and depend on other options with
|
* Some options are context-sensitive, and depend on other options with
|
||||||
* different keywords. These cannot be fetched directly. Currently there
|
* different keywords. These cannot be fetched directly. Currently there
|
||||||
* is only one such option: clients should use the "HiddenServiceOptions"
|
* is only one such option: clients should use the "HiddenServiceOptions"
|
||||||
* virtual keyword to get all HiddenServiceDir, HiddenServicePort,
|
* virtual keyword to get all HiddenServiceDir, HiddenServicePort,
|
||||||
* HiddenServiceNodes, and HiddenServiceExcludeNodes option settings.
|
* 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");
|
StringBuffer sb = new StringBuffer("GETCONF");
|
||||||
for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
||||||
String key = it.next();
|
String key = it.next();
|
||||||
@@ -436,24 +540,25 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
}
|
}
|
||||||
sb.append("\r\n");
|
sb.append("\r\n");
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
||||||
List<ConfigEntry> result = new ArrayList<ConfigEntry>();
|
List<ConfigEntry> result = new ArrayList<>();
|
||||||
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
||||||
String kv = (it.next()).msg;
|
String kv = (it.next()).msg;
|
||||||
int idx = kv.indexOf('=');
|
int idx = kv.indexOf('=');
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
result.add(new ConfigEntry(kv.substring(0, idx),
|
result.add(new ConfigEntry(kv.substring(0, idx),
|
||||||
kv.substring(idx+1)));
|
kv.substring(idx + 1)));
|
||||||
else
|
else
|
||||||
result.add(new ConfigEntry(kv));
|
result.add(new ConfigEntry(kv));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Request that the server inform the client about interesting events.
|
/**
|
||||||
|
* Request that the server inform the client about interesting events.
|
||||||
* Each element of <b>events</b> is one of the following Strings:
|
* Each element of <b>events</b> is one of the following Strings:
|
||||||
* ["CIRC" | "STREAM" | "ORCONN" | "BW" | "DEBUG" |
|
* ["CIRC" | "STREAM" | "ORCONN" | "BW" | "DEBUG" |
|
||||||
* "INFO" | "NOTICE" | "WARN" | "ERR" | "NEWDESC" | "ADDRMAP"] .
|
* "INFO" | "NOTICE" | "WARN" | "ERR" | "NEWDESC" | "ADDRMAP"] .
|
||||||
*
|
* <p>
|
||||||
* Any events not listed in the <b>events</b> are turned off; thus, calling
|
* 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.
|
||||||
*/
|
*/
|
||||||
@@ -466,21 +571,22 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
sendAndWaitForResponse(sb.toString(), null);
|
sendAndWaitForResponse(sb.toString(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Authenticates the controller to the Tor server.
|
/**
|
||||||
*
|
* Authenticates the controller to the Tor server.
|
||||||
|
* <p>
|
||||||
* By default, the current Tor implementation trusts all local users, and
|
* By default, the current Tor implementation trusts all local users, and
|
||||||
* the controller can authenticate itself by calling authenticate(new byte[0]).
|
* the controller can authenticate itself by calling authenticate(new byte[0]).
|
||||||
*
|
* <p>
|
||||||
* If the 'CookieAuthentication' option is true, Tor writes a "magic cookie"
|
* If the 'CookieAuthentication' option is true, Tor writes a "magic cookie"
|
||||||
* file named "control_auth_cookie" into its data directory. To authenticate,
|
* file named "control_auth_cookie" into its data directory. To authenticate,
|
||||||
* the controller must send the contents of this file in <b>auth</b>.
|
* 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
|
* 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
|
* 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.
|
* S2K algorithm in RFC 2440 (OpenPGP), and prefixed with the s2k specifier.
|
||||||
* This is then encoded in hexadecimal, prefixed by the indicator sequence
|
* This is then encoded in hexadecimal, prefixed by the indicator sequence
|
||||||
* "16:".
|
* "16:".
|
||||||
*
|
* <p>
|
||||||
* You can generate the salt of a password by calling
|
* You can generate the salt of a password by calling
|
||||||
* 'tor --hash-password <password>'
|
* 'tor --hash-password <password>'
|
||||||
* or by using the provided PasswordDigest class.
|
* or by using the provided PasswordDigest class.
|
||||||
@@ -492,13 +598,15 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
sendAndWaitForResponse(cmd, null);
|
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 {
|
public void saveConf() throws IOException {
|
||||||
sendAndWaitForResponse("SAVECONF\r\n", null);
|
sendAndWaitForResponse("SAVECONF\r\n", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends a signal from the controller to the Tor server.
|
/**
|
||||||
|
* Sends a signal from the controller to the Tor server.
|
||||||
* <b>signal</b> is one of the following Strings:
|
* <b>signal</b> is one of the following Strings:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>"RELOAD" or "HUP" : Reload config items, refetch directory</li>
|
* <li>"RELOAD" or "HUP" : Reload config items, refetch directory</li>
|
||||||
@@ -514,24 +622,30 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
sendAndWaitForResponse(cmd, null);
|
sendAndWaitForResponse(cmd, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send a signal to the Tor process to shut it down or halt it.
|
/**
|
||||||
* Does not wait for a response. */
|
* Send a signal to the Tor process to shut it down or halt it.
|
||||||
|
* Does not wait for a response.
|
||||||
|
*/
|
||||||
public void shutdownTor(String signal) throws IOException {
|
public void shutdownTor(String signal) throws IOException {
|
||||||
String s = "SIGNAL " + signal + "\r\n";
|
String s = "SIGNAL " + signal + "\r\n";
|
||||||
Waiter w = new Waiter();
|
Waiter w = new Waiter();
|
||||||
if (debugOutput != null)
|
if (debugOutput != null)
|
||||||
debugOutput.print(">> "+s);
|
debugOutput.print(">> " + s);
|
||||||
|
LOG.info("Entering synchronized (waiters)");
|
||||||
synchronized (waiters) {
|
synchronized (waiters) {
|
||||||
|
LOG.info("Entered synchronized (waiters)");
|
||||||
output.write(s);
|
output.write(s);
|
||||||
output.flush();
|
output.flush();
|
||||||
|
LOG.info("Leaving synchronized (waiters)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tells the Tor server that future SOCKS requests for connections to a set of original
|
/**
|
||||||
|
* 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 should be replaced with connections to the specified replacement
|
||||||
* addresses. Each element of <b>kvLines</b> is a String of the form
|
* addresses. Each element of <b>kvLines</b> is a String of the form
|
||||||
* "old-address new-address". This function returns the new address mapping.
|
* "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
|
* 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
|
* 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
|
* "." for hostname), signifying that the server should choose the original
|
||||||
@@ -539,56 +653,61 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* should ensure that it returns an element of address space that is unlikely
|
* 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
|
* to be in actual use. If there is already an address mapped to the
|
||||||
* destination address, the server may reuse that mapping.
|
* destination address, the server may reuse that mapping.
|
||||||
*
|
* <p>
|
||||||
* If the original address is already mapped to a different address, the old
|
* If the original address is already mapped to a different address, the old
|
||||||
* mapping is removed. If the original address and the destination address
|
* mapping is removed. If the original address and the destination address
|
||||||
* are the same, the server removes any mapping in place for the original
|
* are the same, the server removes any mapping in place for the original
|
||||||
* address.
|
* address.
|
||||||
*
|
* <p>
|
||||||
* Mappings set by the controller last until the Tor process exits:
|
* Mappings set by the controller last until the Tor process exits:
|
||||||
* they never expire. If the controller wants the mapping to last only
|
* 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
|
* a certain time, then it must explicitly un-map the address when that
|
||||||
* time has elapsed.
|
* 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");
|
StringBuffer sb = new StringBuffer("MAPADDRESS");
|
||||||
for (Iterator<String> it = kvLines.iterator(); it.hasNext(); ) {
|
for (Iterator<String> it = kvLines.iterator(); it.hasNext(); ) {
|
||||||
String kv = it.next();
|
String kv = it.next();
|
||||||
int i = kv.indexOf(' ');
|
int i = kv.indexOf(' ');
|
||||||
sb.append(" ").append(kv.substring(0,i)).append("=")
|
sb.append(" ").append(kv.substring(0, i)).append("=")
|
||||||
.append(quote(kv.substring(i+1)));
|
.append(quote(kv.substring(i + 1)));
|
||||||
}
|
}
|
||||||
sb.append("\r\n");
|
sb.append("\r\n");
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
||||||
Map<String,String> result = new HashMap<String,String>();
|
Map<String, String> result = new HashMap<>();
|
||||||
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
||||||
String kv = (it.next()).msg;
|
String kv = (it.next()).msg;
|
||||||
int idx = kv.indexOf('=');
|
int idx = kv.indexOf('=');
|
||||||
result.put(kv.substring(0, idx),
|
result.put(kv.substring(0, idx),
|
||||||
kv.substring(idx+1));
|
kv.substring(idx + 1));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String,String> mapAddresses(Map<String,String> addresses) throws IOException {
|
public Map<String, String> mapAddresses(Map<String, String> addresses)
|
||||||
List<String> kvList = new ArrayList<String>();
|
throws IOException {
|
||||||
for (Iterator<Map.Entry<String, String>> it = addresses.entrySet().iterator(); it.hasNext(); ) {
|
List<String> kvList = new ArrayList<>();
|
||||||
Map.Entry<String,String> e = it.next();
|
for (Iterator<Map.Entry<String, String>> it =
|
||||||
kvList.add(e.getKey()+" "+e.getValue());
|
addresses.entrySet().iterator(); it.hasNext(); ) {
|
||||||
|
Map.Entry<String, String> e = it.next();
|
||||||
|
kvList.add(e.getKey() + " " + e.getValue());
|
||||||
}
|
}
|
||||||
return mapAddresses(kvList);
|
return mapAddresses(kvList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String mapAddress(String fromAddr, String toAddr) throws IOException {
|
public String mapAddress(String fromAddr, String toAddr)
|
||||||
List<String> lst = new ArrayList<String>();
|
throws IOException {
|
||||||
lst.add(fromAddr+" "+toAddr+"\n");
|
List<String> lst = new ArrayList<>();
|
||||||
Map<String,String> m = mapAddresses(lst);
|
lst.add(fromAddr + " " + toAddr + "\n");
|
||||||
|
Map<String, String> m = mapAddresses(lst);
|
||||||
return m.get(fromAddr);
|
return m.get(fromAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Queries the Tor server for keyed values that are not stored in the torrc
|
/**
|
||||||
|
* Queries the Tor server for keyed values that are not stored in the torrc
|
||||||
* configuration file. Returns a map of keys to values.
|
* configuration file. Returns a map of keys to values.
|
||||||
*
|
* <p>
|
||||||
* Recognized keys include:
|
* Recognized keys include:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>"version" : The version of the server's software, including the name
|
* <li>"version" : The version of the server's software, including the name
|
||||||
@@ -616,25 +735,26 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* form: "ServerID ORStatus"</li>
|
* form: "ServerID ORStatus"</li>
|
||||||
* </ul>
|
* </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");
|
StringBuffer sb = new StringBuffer("GETINFO");
|
||||||
for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
||||||
sb.append(" ").append(it.next());
|
sb.append(" ").append(it.next());
|
||||||
}
|
}
|
||||||
sb.append("\r\n");
|
sb.append("\r\n");
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
||||||
Map<String,String> m = new HashMap<String,String>();
|
Map<String, String> m = new HashMap<>();
|
||||||
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
||||||
ReplyLine line = it.next();
|
ReplyLine line = it.next();
|
||||||
int idx = line.msg.indexOf('=');
|
int idx = line.msg.indexOf('=');
|
||||||
if (idx<0)
|
if (idx < 0)
|
||||||
break;
|
break;
|
||||||
String k = line.msg.substring(0,idx);
|
String k = line.msg.substring(0, idx);
|
||||||
String v;
|
String v;
|
||||||
if (line.rest != null) {
|
if (line.rest != null) {
|
||||||
v = line.rest;
|
v = line.rest;
|
||||||
} else {
|
} else {
|
||||||
v = line.msg.substring(idx+1);
|
v = line.msg.substring(idx + 1);
|
||||||
}
|
}
|
||||||
m.put(k, v);
|
m.put(k, v);
|
||||||
}
|
}
|
||||||
@@ -642,41 +762,44 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
/** Return the value of the information field 'key' */
|
* Return the value of the information field 'key'
|
||||||
|
*/
|
||||||
public String getInfo(String key) throws IOException {
|
public String getInfo(String key) throws IOException {
|
||||||
List<String> lst = new ArrayList<String>();
|
List<String> lst = new ArrayList<>();
|
||||||
lst.add(key);
|
lst.add(key);
|
||||||
Map<String,String> m = getInfo(lst);
|
Map<String, String> m = getInfo(lst);
|
||||||
return m.get(key);
|
return m.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An extendCircuit request takes one of two forms: either the <b>circID</b> is zero, in
|
/**
|
||||||
|
* 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
|
* 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
|
* 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
|
* request for the server to extend an existing circuit with that ID according
|
||||||
* to the specified <b>path</b>.
|
* to the specified <b>path</b>.
|
||||||
*
|
* <p>
|
||||||
* If successful, returns the Circuit ID of the (maybe newly created) circuit.
|
* If successful, returns the Circuit ID of the (maybe newly created) circuit.
|
||||||
*/
|
*/
|
||||||
public String extendCircuit(String circID, String path) throws IOException {
|
public String extendCircuit(String circID, String path) throws IOException {
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(
|
List<ReplyLine> lst = sendAndWaitForResponse(
|
||||||
"EXTENDCIRCUIT "+circID+" "+path+"\r\n", null);
|
"EXTENDCIRCUIT " + circID + " " + path + "\r\n", null);
|
||||||
return (lst.get(0)).msg;
|
return (lst.get(0)).msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Informs the Tor server that the stream specified by <b>streamID</b> should be
|
/**
|
||||||
|
* Informs the Tor server that the stream specified by <b>streamID</b> should be
|
||||||
* associated with the circuit specified by <b>circID</b>.
|
* associated with the circuit specified by <b>circID</b>.
|
||||||
*
|
* <p>
|
||||||
* Each stream may be associated with
|
* Each stream may be associated with
|
||||||
* at most one circuit, and multiple streams may share the same circuit.
|
* at most one circuit, and multiple streams may share the same circuit.
|
||||||
* Streams can only be attached to completed circuits (that is, circuits that
|
* 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
|
* have sent a circuit status "BUILT" event or are listed as built in a
|
||||||
* getInfo circuit-status request).
|
* getInfo circuit-status request).
|
||||||
*
|
* <p>
|
||||||
* If <b>circID</b> is 0, responsibility for attaching the given stream is
|
* If <b>circID</b> is 0, responsibility for attaching the given stream is
|
||||||
* returned to Tor.
|
* returned to Tor.
|
||||||
*
|
* <p>
|
||||||
* By default, Tor automatically attaches streams to
|
* By default, Tor automatically attaches streams to
|
||||||
* circuits itself, unless the configuration variable
|
* circuits itself, unless the configuration variable
|
||||||
* "__LeaveStreamsUnattached" is set to "1". Attempting to attach streams
|
* "__LeaveStreamsUnattached" is set to "1". Attempting to attach streams
|
||||||
@@ -685,34 +808,41 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
*/
|
*/
|
||||||
public void attachStream(String streamID, String circID)
|
public void attachStream(String streamID, String circID)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
sendAndWaitForResponse("ATTACHSTREAM "+streamID+" "+circID+"\r\n", null);
|
sendAndWaitForResponse(
|
||||||
|
"ATTACHSTREAM " + streamID + " " + circID + "\r\n", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tells Tor about the server descriptor in <b>desc</b>.
|
/**
|
||||||
*
|
* Tells Tor about the server descriptor in <b>desc</b>.
|
||||||
|
* <p>
|
||||||
* The descriptor, when parsed, must contain a number of well-specified
|
* The descriptor, when parsed, must contain a number of well-specified
|
||||||
* fields, including fields for its nickname and identity.
|
* fields, including fields for its nickname and identity.
|
||||||
*/
|
*/
|
||||||
// More documentation here on format of desc?
|
// More documentation here on format of desc?
|
||||||
// No need for return value? control-spec.txt says reply is merely "250 OK" on success...
|
// No need for return value? control-spec.txt says reply is merely "250 OK" on success...
|
||||||
public String postDescriptor(String desc) throws IOException {
|
public String postDescriptor(String desc) throws IOException {
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse("+POSTDESCRIPTOR\r\n", desc);
|
List<ReplyLine> lst =
|
||||||
|
sendAndWaitForResponse("+POSTDESCRIPTOR\r\n", desc);
|
||||||
return (lst.get(0)).msg;
|
return (lst.get(0)).msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tells Tor to change the exit address of the stream identified by <b>streamID</b>
|
/**
|
||||||
|
* 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 <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
|
* 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
|
* after a new stream event is received, and before attaching this stream to
|
||||||
* a circuit.
|
* a circuit.
|
||||||
*/
|
*/
|
||||||
public void redirectStream(String streamID, String address) throws IOException {
|
public void redirectStream(String streamID, String address)
|
||||||
sendAndWaitForResponse("REDIRECTSTREAM "+streamID+" "+address+"\r\n",
|
throws IOException {
|
||||||
|
sendAndWaitForResponse(
|
||||||
|
"REDIRECTSTREAM " + streamID + " " + address + "\r\n",
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tells Tor to close the stream identified by <b>streamID</b>.
|
/**
|
||||||
|
* 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>
|
* <ul>
|
||||||
* <li>1 -- REASON_MISC (catch-all for unlisted reasons)</li>
|
* <li>1 -- REASON_MISC (catch-all for unlisted reasons)</li>
|
||||||
@@ -729,23 +859,27 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* <li>12 -- REASON_CONNRESET (Connection was unexpectedly reset)</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>
|
* </ul>
|
||||||
*
|
* <p>
|
||||||
* 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)
|
public void closeStream(String streamID, byte reason)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
sendAndWaitForResponse("CLOSESTREAM "+streamID+" "+reason+"\r\n",null);
|
sendAndWaitForResponse(
|
||||||
|
"CLOSESTREAM " + streamID + " " + reason + "\r\n", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tells Tor to close the circuit identified by <b>circID</b>.
|
/**
|
||||||
|
* 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 {
|
public void closeCircuit(String circID, boolean ifUnused)
|
||||||
sendAndWaitForResponse("CLOSECIRCUIT "+circID+
|
throws IOException {
|
||||||
(ifUnused?" IFUNUSED":"")+"\r\n", null);
|
sendAndWaitForResponse("CLOSECIRCUIT " + circID +
|
||||||
|
(ifUnused ? " IFUNUSED" : "") + "\r\n", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tells Tor to exit when this control connection is closed. This command
|
/**
|
||||||
|
* Tells Tor to exit when this control connection is closed. This command
|
||||||
* was added in Tor 0.2.2.28-beta.
|
* was added in Tor 0.2.2.28-beta.
|
||||||
*/
|
*/
|
||||||
public void takeOwnership() throws IOException {
|
public void takeOwnership() throws IOException {
|
||||||
@@ -758,7 +892,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
||||||
*/
|
*/
|
||||||
public Map<String,String> addOnion(Map<Integer,String> portLines)
|
public Map<String, String> addOnion(Map<Integer, String> portLines)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return addOnion("NEW:BEST", portLines, null);
|
return addOnion("NEW:BEST", portLines, null);
|
||||||
}
|
}
|
||||||
@@ -769,7 +903,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
||||||
*/
|
*/
|
||||||
public Map<String,String> addOnion(Map<Integer,String> portLines,
|
public Map<String, String> addOnion(Map<Integer, String> portLines,
|
||||||
boolean ephemeral, boolean detach)
|
boolean ephemeral, boolean detach)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return addOnion("NEW:BEST", portLines, ephemeral, detach);
|
return addOnion("NEW:BEST", portLines, ephemeral, detach);
|
||||||
@@ -780,8 +914,8 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
||||||
*/
|
*/
|
||||||
public Map<String,String> addOnion(String privKey,
|
public Map<String, String> addOnion(String privKey,
|
||||||
Map<Integer,String> portLines)
|
Map<Integer, String> portLines)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return addOnion(privKey, portLines, null);
|
return addOnion(privKey, portLines, null);
|
||||||
}
|
}
|
||||||
@@ -791,11 +925,11 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
||||||
*/
|
*/
|
||||||
public Map<String,String> addOnion(String privKey,
|
public Map<String, String> addOnion(String privKey,
|
||||||
Map<Integer,String> portLines,
|
Map<Integer, String> portLines,
|
||||||
boolean ephemeral, boolean detach)
|
boolean ephemeral, boolean detach)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
List<String> flags = new ArrayList<String>();
|
List<String> flags = new ArrayList<>();
|
||||||
if (ephemeral)
|
if (ephemeral)
|
||||||
flags.add("DiscardPK");
|
flags.add("DiscardPK");
|
||||||
if (detach)
|
if (detach)
|
||||||
@@ -808,14 +942,15 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
||||||
*/
|
*/
|
||||||
public Map<String,String> addOnion(String privKey,
|
public Map<String, String> addOnion(String privKey,
|
||||||
Map<Integer,String> portLines,
|
Map<Integer, String> portLines,
|
||||||
List<String> flags)
|
List<String> flags)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (privKey.indexOf(':') < 0)
|
if (privKey.indexOf(':') < 0)
|
||||||
throw new IllegalArgumentException("Invalid privKey");
|
throw new IllegalArgumentException("Invalid privKey");
|
||||||
if (portLines == null || portLines.size() < 1)
|
if (portLines == null || portLines.size() < 1)
|
||||||
throw new IllegalArgumentException("Must provide at least one port line");
|
throw new IllegalArgumentException(
|
||||||
|
"Must provide at least one port line");
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
b.append("ADD_ONION ").append(privKey);
|
b.append("ADD_ONION ").append(privKey);
|
||||||
if (flags != null && flags.size() > 0) {
|
if (flags != null && flags.size() > 0) {
|
||||||
@@ -826,7 +961,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
separator = ",";
|
separator = ",";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Map.Entry<Integer,String> portLine : portLines.entrySet()) {
|
for (Map.Entry<Integer, String> portLine : portLines.entrySet()) {
|
||||||
int virtPort = portLine.getKey();
|
int virtPort = portLine.getKey();
|
||||||
String target = portLine.getValue();
|
String target = portLine.getValue();
|
||||||
b.append(" Port=").append(virtPort);
|
b.append(" Port=").append(virtPort);
|
||||||
@@ -835,7 +970,7 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
}
|
}
|
||||||
b.append("\r\n");
|
b.append("\r\n");
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(b.toString(), null);
|
List<ReplyLine> lst = sendAndWaitForResponse(b.toString(), null);
|
||||||
Map<String,String> ret = new HashMap<String,String>();
|
Map<String, String> ret = new HashMap<>();
|
||||||
ret.put(HS_ADDRESS, (lst.get(0)).msg.split("=", 2)[1]);
|
ret.put(HS_ADDRESS, (lst.get(0)).msg.split("=", 2)[1]);
|
||||||
if (lst.size() > 2)
|
if (lst.size() > 2)
|
||||||
ret.put(HS_PRIVKEY, (lst.get(1)).msg.split("=", 2)[1]);
|
ret.put(HS_PRIVKEY, (lst.get(1)).msg.split("=", 2)[1]);
|
||||||
@@ -852,7 +987,8 @@ public class TorControlConnection implements TorControlCommands {
|
|||||||
sendAndWaitForResponse("DEL_ONION " + hostname + "\r\n", null);
|
sendAndWaitForResponse("DEL_ONION " + hostname + "\r\n", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tells Tor to forget any cached client state relating to the hidden
|
/**
|
||||||
|
* Tells Tor to forget any cached client state relating to the hidden
|
||||||
* service with the given hostname (excluding the .onion extension).
|
* service with the given hostname (excluding the .onion extension).
|
||||||
*/
|
*/
|
||||||
public void forgetHiddenService(String hostname) throws IOException {
|
public void forgetHiddenService(String hostname) throws IOException {
|
||||||
|
|||||||
Reference in New Issue
Block a user