[or-cvs] Finish making new (v1) controller logic and multiplexing lo...
Nick Mathewson
nickm at seul.org
Fri Jun 24 18:03:30 UTC 2005
Update of /home/or/cvsroot/control/python
In directory moria:/tmp/cvs-serv21811/python
Modified Files:
TorCtl.py TorCtl0.py TorCtl1.py TorExample.py
Log Message:
Finish making new (v1) controller logic and multiplexing logic work in Python and Java controllers. Try out example code a bit.
Index: TorCtl.py
===================================================================
RCS file: /home/or/cvsroot/control/python/TorCtl.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- TorCtl.py 19 Jun 2005 22:38:31 -0000 1.3
+++ TorCtl.py 24 Jun 2005 18:03:27 -0000 1.4
@@ -7,8 +7,8 @@
TorCtl -- Library to control Tor processes. See TorCtlDemo.py for example use.
"""
-import TorCtl0
-import TorCtl1
+import struct
+import sys
class TorCtlError(Exception):
"Generic error raised by TorControl code."
@@ -97,10 +97,11 @@
return evtype, args
- def handle1(self, evbody):
+ def handle1(self, lines):
"""Dispatcher: called from Connection when an event is received."""
- evtype, args = self.decode1(evbody)
- self._map1.get(evtype, self.unknownEvent)(evtype, *args)
+ for code, msg, data in lines:
+ evtype, args = self.decode1(msg)
+ self._map1.get(evtype, self.unknownEvent)(evtype, *args)
def decode1(self, body):
"""Unpack an event message into a type/arguments-tuple tuple."""
@@ -165,7 +166,7 @@
"""
raise NotImplemented
- def streamStatus(self, status, circID, target, circID="0"):
+ def streamStatus(self, status, streamID, target, circID="0"):
"""Called when a stream status changes if listening to STREAMSTATUS
events. 'status' is a member of STREAM_STATUS; streamID is a
numeric stream ID, and 'target' is the destination of the stream.
@@ -200,6 +201,35 @@
"""DOCDOC"""
raise NotImplemented
+class DebugEventHandler(EventHandler):
+ """Trivial event handler: dumps all events to stdout."""
+ def __init__(self, out=None):
+ if out is None:
+ out = sys.stdout
+ self._out = out
+
+ def handle0(self, body):
+ evtype, args = self.decode0(body)
+ print >>self._out,EVENT_TYPE.nameOf[evtype],args
+
+ def handle1(self, lines):
+ for code, msg, data in lines:
+ print >>self._out, msg
+
+def detectVersion(s):
+ s.sendall("\x00\x00\r\n")
+ m = s.recv(4)
+ v0len, v0type = struct.unpack("!HH", m)
+ if v0type == '\x00\x00':
+ s.recv(v0len)
+ return 0
+ if '\n' not in m:
+ while 1:
+ c = s.recv(1)
+ if c == '\n':
+ break
+ return 1
+
def parseHostAndPort(h):
"""Given a string of the form 'address:port' or 'address' or
'port' or '', return a two-tuple of (address, port)
@@ -221,6 +251,15 @@
return host, port
+def get_connection(sock):
+ v = detectVersion(sock)
+ if v == 0:
+ import TorCtl0
+ return TorCtl0.Connection(sock)
+ else:
+ import TorCtl1
+ return TorCtl1.Connection(sock)
+
def secret_to_key(secret, s2k_specifier):
c = ord(s2k_specifier[8])
EXPBIAS = 6
Index: TorCtl0.py
===================================================================
RCS file: /home/or/cvsroot/control/python/TorCtl0.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- TorCtl0.py 19 Jun 2005 22:38:31 -0000 1.1
+++ TorCtl0.py 24 Jun 2005 18:03:27 -0000 1.2
@@ -20,7 +20,6 @@
"MSG_TYPE", "EVENT_TYPE", "CIRC_STATUS", "STREAM_STATUS",
"OR_CONN_STATUS", "SIGNAL", "ERR_CODES",
"TorCtlError", "ProtocolError", "ErrorReply", "Connection", "EventHandler",
- "DebugEventHandler", "parseHostAndPort"
]
class _Enum:
@@ -429,6 +428,16 @@
"""Send the signal 'sig' to the Tor process; 'sig' must be a member of
SIGNAL.
"""
+ try:
+ sig = sig.upper()
+ except AttributeError:
+ pass
+ sig = { "HUP" : 0x01, "RELOAD" : 0x01,
+ "INT" : 0x02, "SHUTDOWN" : 0x02,
+ "DUMP" : 0x0A, "USR1" : 0x0A,
+ "USR2" : 0x0C, "DEBUG" : 0x0C,
+ "TERM" : 0x0F, "HALT" : 0x0F
+ }.get(sig,sig)
self._sendAndRecv(MSG_TYPE.SIGNAL,struct.pack("B",sig))
def map_address(self, kvList):
@@ -479,13 +488,3 @@
"""Tell Tor about a new descriptor in 'descriptor'."""
self._sendAndRecv(MSG_TYPE.POSTDESCRIPTOR,descriptor)
-class DebugEventHandler(EventHandler):
- """Trivial event handler: dumps all events to stdout."""
- def __init__(self, out=None):
- if out is None:
- out = sys.stdout
- self._out = out
-
- def handle(self, body):
- evtype, args = self.decode(body)
- print >>self._out,EVENT_TYPE.nameOf[evtype],args
Index: TorCtl1.py
===================================================================
RCS file: /home/or/cvsroot/control/python/TorCtl1.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- TorCtl1.py 19 Jun 2005 22:38:31 -0000 1.1
+++ TorCtl1.py 24 Jun 2005 18:03:27 -0000 1.2
@@ -11,6 +11,7 @@
import threading
import types
import Queue
+import TorCtl
def _quote(s):
return re.sub(r'([\r\n\\\"])', r'\\\1', s)
@@ -43,17 +44,6 @@
else:
return "\r\n".join(lines)
-def _parseKV(body,sep=" ",term="\n"):
- """Helper: parse a key/value list of the form [key sep value term]* .
- Return a list of (k,v)."""
- res = []
- for line in body.split(term):
- if not line: continue
- k, v = line.split(sep,1)
- res.append((k,v))
- return res
-
-
def _read_reply(f,debugFile=None):
lines = []
while 1:
@@ -61,18 +51,17 @@
if debugFile:
debugFile.write(" %s\n" % line)
if len(line)<4:
- raise ProtocolError("Badly formatted reply line: Too short")
+ raise TorCtl.ProtocolError("Badly formatted reply line: Too short")
code = line[:3]
tp = line[3]
- s = line[3:]
- if s == "-":
- lines.append((tp, s, None))
- elif s == " ":
- lines.append((tp, s, None))
+ s = line[4:]
+ if tp == "-":
+ lines.append((code, s, None))
+ elif tp == " ":
+ lines.append((code, s, None))
return lines
- elif s != "+":
- raise ProtocolError("Badly formatted reply line: unknown type %r",
- s)
+ elif tp != "+":
+ raise TorCtl.ProtocolError("Badly formatted reply line: unknown type %r"%tp)
else:
more = []
while 1:
@@ -82,10 +71,10 @@
if line in (".\r\n", ".\n"):
break
more.append(line)
- lines.append((tp, s, _unescape_dots("".join(more)))
+ lines.append((code, s, _unescape_dots("".join(more))))
class Connection:
- """A Connection represents a connection to the Tor process."""
+ """A Connection represents a connection to the Tor process."""
def __init__(self, sock, file=None):
"""Create a Connection to communicate with the Tor process over the
socket 'sock'.
@@ -142,7 +131,7 @@
assert lines
if lines[0][0][0] == "6":
if self._handler is not None:
- self._handler.handle1(body)
+ self._handler.handle1(lines)
else:
cb = self._queue.get()
cb(lines)
@@ -151,7 +140,7 @@
"""Helper: Send a command 'msg' to Tor, and wait for a command
in response. If the response type is in expectedTypes,
return a list of (tp,body,extra) tuples. If it is an
- error, raise ErrorReply. Otherwise, raise ProtocolError.
+ error, raise ErrorReply. Otherwise, raise TorCtl.ProtocolError.
"""
# This condition will get notified when we've got a result...
condition = threading.Condition()
@@ -178,6 +167,7 @@
if self._debugFile:
self._debugFile.write(">>> %s" % msg)
self._s.write(msg)
+ self._s.flush()
finally:
self._sendLock.release()
@@ -194,9 +184,9 @@
lines = result[0]
for tp, msg, _ in lines:
if tp[0] in '45':
- raise ErrorReply("%s %s"%(tp, msg))
+ raise TorCtl.ErrorReply("%s %s"%(tp, msg))
if tp not in expectedTypes:
- raise ProtocolError("Unexpectd message type %r"%tp)
+ raise TorCtl.ProtocolError("Unexpectd message type %r"%tp)
return lines
@@ -204,7 +194,7 @@
"""Send an authenticating secret to Tor. You'll need to call this
method before Tor can start.
"""
- hexstr = binascii.b2a_hex(MSG_TYPE.AUTH,secret)
+ hexstr = binascii.b2a_hex(secret)
self._sendAndRecv("AUTHENTICATE %s\r\n"%hexstr)
def get_option(self, name):
@@ -215,6 +205,7 @@
name = " ".join(name)
lines = self._sendAndRecv("GETCONF %s\r\n" % name)
+ r = []
for _,line,_ in lines:
try:
key, val = line.split("=", 1)
@@ -252,7 +243,7 @@
try:
k,rest = msg.split("=",1)
except ValueError:
- raise ProtocolError("Bad info line %r",msg)
+ raise TorCtl.ProtocolError("Bad info line %r",msg)
if more:
d[k] = more
else:
@@ -292,7 +283,7 @@
e = "ERR"
evs.append(e)
- self._sendAndRecv("SETEVENTS %s"\r\n," ".join(evs))
+ self._sendAndRecv("SETEVENTS %s\r\n" % " ".join(evs))
def save_conf(self):
"""Flush all configuration changes to disk.
@@ -308,7 +299,7 @@
0x0A : "USR1",
0x0C : "USR2",
0x0F : "TERM" }.get(sig,sig)
- seld._sendAndRecv("SIGNAL %s\r\n"%sig)
+ self._sendAndRecv("SIGNAL %s\r\n"%sig)
def map_address(self, kvList):
if not kvList:
@@ -320,7 +311,7 @@
try:
key, val = line.split("=", 1)
except ValueError:
- raise ProtocolError("Bad address line %r",v)
+ raise TorCtl.ProtocolError("Bad address line %r",v)
r.append((key,val))
return r
@@ -335,7 +326,7 @@
tp,msg,_ = lines[0]
m = re.match(r'EXTENDED (\S*)', msg)
if not m:
- raise ProtocolError("Bad extended line %r",msg)
+ raise TorCtl.ProtocolError("Bad extended line %r",msg)
return m.group(1)
def redirect_stream(self, streamid, newtarget):
@@ -359,4 +350,3 @@
def post_descriptor(self, desc):
self._sendAndRecv("+POSTDESCRIPTOR\r\n%s"%_escape_dots(desc))
-
Index: TorExample.py
===================================================================
RCS file: /home/or/cvsroot/control/python/TorExample.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- TorExample.py 15 Jun 2005 15:18:22 -0000 1.2
+++ TorExample.py 24 Jun 2005 18:03:27 -0000 1.3
@@ -8,18 +8,25 @@
from TorCtl import *
def getConnection(daemon=1):
- if sys.argv[1] == '--host':
- hostport = sys.argv[2]
- del sys.argv[1:3]
- elif sys.argv[1].startswith("--host="):
- hostport = sys.argv[1][7:]
- del sys.argv[1]
- else:
- hostport = "localhost:9100"
+ hostport = "localhost:9100"
+ verbose = 0
+ while sys.argv[1][0] == '-':
+ if sys.argv[1] == '--host':
+ hostport = sys.argv[2]
+ del sys.argv[1:3]
+ elif sys.argv[1].startswith("--host="):
+ hostport = sys.argv[1][7:]
+ del sys.argv[1]
+ elif sys.argv[1] in ('-v', '--verbose'):
+ verbose = 1
+ del sys.argv[1]
+
host,port = parseHostAndPort(hostport)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
- conn = Connection(s)
+ conn = get_connection(s)
+ if verbose and hasattr(conn, "debug"):
+ conn.debug(sys.stdout)
th = conn.launchThread(daemon)
conn.authenticate("")
return conn
@@ -32,6 +39,7 @@
fn = globals().get("run_"+cmd)
if fn is None:
print "Unrecognized command:",cmd
+ return
fn()
def run_set_config():
@@ -51,9 +59,9 @@
def run_get_config():
conn = getConnection()
opts = conn.get_option(sys.argv[1:])
- for k in sys.argv[1:]:
+ for k,v in opts:
print "KEY:",k
- print "VALUE:",opts.get(k)
+ print "VALUE:",v
def run_get_info():
conn = getConnection()
@@ -63,44 +71,17 @@
print "VALUE:",opts.get(k)
def run_listen():
- m = { "circ": "CIRCSTATUS",
- "stream": "STREAMSTATUS",
- "orconn": "ORCONNSTATUS",
- "bw": "BANDWIDTH",
- "newdesc": "NEWDESC",
- "info": "INFO_MSG",
- "notice": "NOTICE_MSG",
- "warn": "WARN_MSG",
- "error": "ERR_MSG",
- }
conn = getConnection(daemon=0)
events = []
- for kw in sys.argv[1:]:
- try:
- events.append(EVENT_TYPE.get(m[kw]))
- except KeyError:
- print "Unrecognized event %r; recognized events are: %s"%(
- kw, ", ".join(m.keys()))
- if not events:
- return
-
conn.setEventHandler(DebugEventHandler())
- conn.listenForEvents(events)
+ conn.set_events(sys.argv[1:])
def run_signal():
conn = getConnection()
- m = { 'reload': "HUP", 'shutdown': "INT", 'dump': "USR1",
- 'debug': "USR2", 'halt': 'TERM' }
if len(sys.argv)<2:
print "Syntax: signal [signal]"
return
- try:
- sig = SIGNAL.get(m[sys.argv[1]])
- except KeyError:
- print "Unrecognized signal %r. Options are %s"%(
- sys.argv[1], ", ".join(m.keys()))
-
- conn.signal(sig)
+ conn.send_signal(sys.argv[1])
def run_authdemo():
conn = getConnection()
More information about the tor-commits
mailing list