[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] Oops. I guess I would probably get more comments about thi...
Update of /home/or/cvsroot/control/python
In directory moria:/tmp/cvs-serv6608/python
Added Files:
.cvsignore TorCtl.py TorExample.py
Log Message:
Oops. I guess I would probably get more comments about this clever controller API/demo stuff if I actually committed it to CVS. Here then.
--- NEW FILE: .cvsignore ---
*.pyo
*.pyc
--- NEW FILE: TorCtl.py ---
#!/usr/bin/python
# TorCtl.py -- Python module to interface with Tor Control interface.
# Copyright 2005 Nick Mathewson -- See LICENSE for licensing information.
#$Id: TorCtl.py,v 1.1 2005/06/04 02:42:56 nickm Exp $
"""
TorCtl -- Library to control Tor processes. See TorCtlDemo.py for example use.
"""
import binascii
import os
import sha
import socket
import struct
import sys
import threading
import Queue
__all__ = [
"MSG_TYPE", "EVENT_TYPE", "CIRC_STATUS", "STREAM_STATUS",
"OR_CONN_STATUS", "SIGNAL", "ERR_STATUS",
"TorCtlError", "ProtocolError", "ErrorReply", "Connection", "EventHandler",
"DebugEventHandler", "parseHostAndPort"
]
class _Enum:
# Helper: define an ordered dense name-to-number 1-1 mapping.
def __init__(self, start, names):
self.nameOf = {}
idx = start
for name in names:
setattr(self,name,idx)
self.nameOf[idx] = name
idx += 1
class _Enum2:
# Helper: define an ordered sparse name-to-number 1-1 mapping.
def __init__(self, **args):
self.__dict__.update(args)
self.nameOf = {}
for k,v in args.items():
self.nameOf[v] = k
# Message types that client or server can send.
MSG_TYPE = _Enum(0x0000,
["ERROR",
"DONE",
"SETCONF",
"GETCONF",
"CONFVALUE",
"SETEVENTS",
"EVENT",
"AUTH",
"SAVECONF",
"SIGNAL",
"MAPADDRESS",
"GETINFO",
"INFOVALUE",
"EXTENDCIRCUIT",
"ATTACHSTREAM",
"POSTDESCRIPTOR",
"FRAGMENTHEADER",
"FRAGMENT",
"REDIRECTSTREAM",
"CLOSESTREAM",
"CLOSECIRCUIT",
])
# Make sure that the enumeration code is working.
assert MSG_TYPE.SAVECONF == 0x0008
assert MSG_TYPE.CLOSECIRCUIT == 0x0014
# Types of "EVENT" message.
EVENT_TYPE = _Enum(0x0001,
["CIRCSTATUS",
"STREAMSTATUS",
"ORCONNSTATUS",
"BANDWIDTH",
"OBSOLETE_LOG",
"NEWDESC",
"DEBUG_MSG",
"INFO_MSG",
"NOTICE_MSG",
"WARN_MSG",
"ERR_MSG",
])
assert EVENT_TYPE.ERR_MSG == 0x000B
assert EVENT_TYPE.OBSOLETE_LOG == 0x0005
# Status codes for "CIRCSTATUS" events.
CIRC_STATUS = _Enum(0x00,
["LAUNCHED",
"BUILT",
"EXTENDED",
"FAILED",
"CLOSED"])
# Status codes for "STREAMSTATUS" events
STREAM_STATUS = _Enum(0x00,
["SENT_CONNECT",
"SENT_RESOLVE",
"SUCCEEDED",
"FAILED",
"CLOSED",
"NEW_CONNECT",
"NEW_RESOLVE",
"DETACHED"])
# Status codes for "ORCONNSTATUS" events
OR_CONN_STATUS = _Enum(0x00,
["LAUNCHED","CONNECTED","FAILED","CLOSED"])
# Signal codes for "SIGNAL" events.
SIGNAL = _Enum2(HUP=0x01,INT=0x02,USR1=0x0A,USR2=0x0C,TERM=0x0F)
# Error codes for "ERROR" events.
ERR_CODES = {
0x0000 : "Unspecified error",
0x0001 : "Internal error",
0x0002 : "Unrecognized message type",
0x0003 : "Syntax error",
0x0004 : "Unrecognized configuration key",
0x0005 : "Invalid configuration value",
0x0006 : "Unrecognized byte code",
0x0007 : "Unauthorized",
0x0008 : "Failed authentication attempt",
0x0009 : "Resource exhausted",
0x000A : "No such stream",
0x000B : "No such circuit",
0x000C : "No such OR"
}
class TorCtlError(Exception):
"Generic error raised by TorControl code."
pass
class ProtocolError(TorCtlError):
"Raised on violations in Tor controller protocol"
pass
class ErrorReply(TorCtlError):
"Raised when Tor controller returns an error"
pass
def parseHostAndPort(h):
"""Given a string of the form 'address:port' or 'address' or
'port' or '', return a two-tuple of (address, port)
"""
host, port = "localhost", 9100
if ":" in h:
i = h.index(":")
host = h[:i]
try:
port = int(h[i+1:])
except ValueError:
print "Bad hostname %r"%h
sys.exit(1)
elif h:
try:
port = int(h)
except ValueError:
host = h
return host, port
def _unpack_singleton_msg(msg):
"""Helper: unpack a single packet. Return (None, minLength, body-so-far)
on incomplete packet or (type,body,rest) on somplete packet
"""
if len(msg) < 4:
return None, 4, msg
length,type = struct.unpack("!HH",msg)
if len(msg) >= 4+length:
return type,msg[4:4+length],msg[4+length:]
else:
return None,4+length,msg
def _minLengthToPack(bytes):
"""Return the minimum number of bytes needed to pack the message 'smg'"""
whole,left = divmod(bytes,65535)
if left:
return whole*(65535+4)+4+left
else:
return whole*(65535+4)
def _unpack_msg(msg):
"returns as for _unpack_singleton_msg"
tp,body,rest = _unpack_singleton_msg(msg)
if tp != MSG_TYPE.FRAGMENTHEADER:
return tp, body, rest
if len(body) < 6:
raise ProtocolError("FRAGMENTHEADER message too short")
realType,realLength = struct.unpack("!HL", body[:6])
# Okay; could the message _possibly_ be here?
minLength = _minLengthToPack(realLength+6)
if len(msg) < minLength:
return None, minLength, msg
# Okay; optimistically try to build up the msg.
soFar = [ body[6:] ]
lenSoFarLen = len(body)-6
while len(rest)>=4 and lenSoFar < realLength:
ln, tp = struct.unpack("!HH", rest[:4])
if tp != MSG_TYPE.FRAGMENT:
raise ProtocolError("Missing FRAGMENT message")
soFar.append(rest[4:4+ln])
lenSoFar += ln
if 4+ln > len(rest):
rest = ""
leftInPacket = 4+ln-len(rest)
else:
rest = rest[4+ln:]
leftInPacket=0
if lenSoFar == realLength:
return realType, "".join(soFar), rest
elif lenSoFar > realLength:
raise ProtocolError("Bad fragmentation: message longer than declared")
else:
inOtherPackets = realLength-lenSoFar-leftInPacket
minLength = _minLengthToPack(inOtherPackets)
return None, len(msg)+leftInPacket+inOtherPackets, msg
def _receive_singleton_msg(s):
"""Read a single packet from the socket s.
"""
body = ""
header = s.recv(4)
length,type = struct.unpack("!HH",header)
if length:
while length > len(body):
body += s.recv(length-len(body))
return length,type,body
def _receive_message(s):
"""Read a single message (possibly multi-packet) from the socket s."""
length, tp, body = _receive_singleton_msg(s)
if tp != MSG_TYPE.FRAGMENTHEADER:
return length, tp, body
if length < 6:
raise ProtocolError("FRAGMENTHEADER message too short")
realType,realLength = struct.unpack("!HL", body[:6])
data = [ body[6:] ]
soFar = len(data[0])
while 1:
length, tp, body = _receive_singleton_msg(s)
if tp != MSG_TYPE.FRAGMENT:
raise ProtocolError("Missing FRAGMENT message")
soFar += length
data.append(body)
if soFar == realLength:
return realLength, realType, "".join(data)
elif soFar > realLength:
raise ProtocolError("FRAGMENT message too long!")
def pack_message(type, body=""):
"""Given a message type and optional message body, generate a set of
packets to send.
"""
length = len(body)
if length < 65536:
reqheader = struct.pack("!HH", length, type)
return "%s%s"%(reqheader,body)
fragheader = struct.pack("!HHHL",
65535, MSG_TYPE.FRAGMENTHEADER, type, length)
msgs = [ fragheader, body[:65535-6] ]
body = body[65535-6:]
while body:
if len(body) > 65535:
fl = 65535
else:
fl = len(body)
fragheader = struct.pack("!HH", MSG_TYPE.FRAGMENT, fl)
msgs.append(fragheader)
msgs.append(body[:fl])
body = body[fl:]
return "".join(msgs)
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 _unterminate(s):
"""Strip trailing NUL characters from s."""
if s[-1] == '\0':
return s[:-1]
else:
return s
class Connection:
"""A Connection represents a connection to the Tor process."""
def __init__(self, sock):
"""Create a Connection to communicate with the Tor process over the
socket 'sock'.
"""
self._s = sock
self._handler = None
self._sendLock = threading.RLock()
self._queue = Queue.Queue()
self._thread = None
def setEventHandler(self, handler):
"""Cause future events from the Tor process to be sent to 'handler'.
"""
self._handler = handler
def launchThread(self, daemon=1):
"""Launch a background thread to handle messages from the Tor process."""
assert self._thread is None
t = threading.Thread(target=self._loop)
if daemon:
t.setDaemon(daemon)
t.start()
self._thread = t
return t
def _send(self, type, body=""):
"""Helper: Deliver a command of type 'type' and body 'body' to Tor.
"""
self._s.sendall(pack_message(type, body))
def _loop(self):
"""Main subthread loop: Read commands from Tor, and handle them either
as events or as responses to other commands.
"""
while 1:
try:
length, tp, body = _receive_message(self._s)
except OSError:
if self._queue.get(timeout=0) != "CLOSE":
raise
if tp == MSG_TYPE.EVENT:
if self._handler is not None:
self._handler.handle(body)
else:
cb = self._queue.get()
cb(tp, body)
def _sendAndRecv(self, tp, msg="", expectedTypes=(MSG_TYPE.DONE,)):
"""Helper: Send a command of type 'tp' and body 'msg' to Tor,
and wait for a command in response. If the response type is
in expectedTypes, return a (tp,body) tuple. If it is an error,
raise ErrorReply. Otherwise, raise ProtocolError.
"""
# This condition will get notified when we've got a result...
condition = threading.Condition()
# Here's where the result goes...
result = []
def cb(tp,body,condition=condition,result=result):
condition.acquire()
try:
result.append((tp, body))
condition.notify()
finally:
condition.release()
# Sends a message to Tor...
self._sendLock.acquire()
try:
self._queue.put(cb)
self._send(tp, msg)
finally:
self._sendLock.release()
# Now wait till the answer is in...
condition.acquire()
try:
while not result:
condition.wait()
finally:
condition.release()
# ...And handle the answer appropriately.
assert len(result) == 1
tp, msg = result[0]
if tp in expectedTypes:
return tp, msg
elif tp == MSG_TYPE.ERROR:
if len(msg)<2:
raise ProtocolError("(Truncated error message)")
errCode, = struct.unpack("!H", msg[:2])
raise ErrorReply((errCode,
ERR_CODES.get(errCode,"[unrecognized]"),
msg[2:]))
else:
raise ProtocolError("Unexpectd message type 0x%04x"%tp)
def close(self):
"""Shut down this controller connection"""
self._sendLock.acquire()
try:
self._queue.put("CLOSE")
self._s.close()
finally:
self._sendLock.release()
def authenticate(self, secret=""):
"""Send an authenticating secret to Tor. You'll need to call this
method before Tor can start.
"""
self._sendAndRecv(MSG_TYPE.AUTH,secret)
def get_option(self,name):
"""Return the value of the configuration option named 'name'.
"""
if not isinstance(name, str):
name = "".join(["%s\n"%s for s in name])
tp,body = self._sendAndRecv(MSG_TYPE.GETCONF,name,[MSG_TYPE.CONFVALUE])
return _parseKV(body)
def set_option(self,key,value):
"""Set the value of the configuration option 'key' to the value 'value'.
"""
self.set_options([key, value])
def set_options(self,kvlist):
"""Given a list of [(key,value)] pairs, set them as configuration
options.
"""
msg = "".join(["%s %s\n" for k,v in kvlist])
self._sendAndRecv(MSG_TYPE.SETCONF,msg)
def get_info(self,name):
"""Return the value of the internal information field named 'named'.
"""
if not isinstance(name, str):
name = "".join(["%s\n"%s for s in name])
tp, body = self._sendAndRecv(MSG_TYPE.GETINFO,name,[MSG_TYPE.INFOVALUE])
kvs = body.split("\0")
d = {}
for i in xrange(0,len(kvs)-1,2):
d[kvs[i]] = kvs[i+1]
return d
def set_events(self,events):
"""Change the list of events that the event handler is interested
in to those in 'events', which is a list of EVENT_TYPE members.
"""
self._sendAndRecv(MSG_TYPE.SETEVENTS,
"".join([struct.pack("!H", event) for event in events]))
def save_conf(self):
"""Flush all configuration changes to disk.
"""
self._sendAndRecv(s,MSG_TYPE.SAVECONF)
def send_signal(self, sig):
"""Send the signal 'sig' to the Tor process; 'sig' must be a member of
SIGNAL.
"""
self._sendAndRecv(MSG_TYPE.SIGNAL,struct.pack("B",sig))
def map_address(self, kvList):
"""Given a list of (old-address,new-address), have Tor redirect
streams from old-address to new-address. Old-address can be in a
special "dont-care" form of "0.0.0.0" or ".".
"""
msg = [ "%s %s\n"%(k,v) for k,v in kvList ]
tp, body = self._sendAndRecv(MSG_TYPE.MAPADDRESS,"".join(msg))
return _parseKV(body)
def extend_circuit(self, circid, hops):
"""Tell Tor to extend the circuit identified by 'circid' through the
servers named in the list "hops".
"""
msg = struct.pack("!L",circid) + ",".join(hops) + "\0"
tp, body = self._sendAndRecv(MSG_TYPE.EXTENDCIRCUIT,msg)
if len(body) != 4:
raise ProtocolError("Extendcircuit reply too short or long")
return struct.unpack("!L",body)[0]
def redirect_stream(self, streamid, newtarget):
"""Tell Tor to change the target address of the stream identified by
'streamid' from its old value to 'newtarget'."""
msg = struct.pack("!L",streamid) + newtarget + "\0"
self._sendAndRecv(MSG_TYPE.REDIRECTSTREAM,msg)
def attach_stream(self, streamid, circid):
"""Tell Tor To attach stream 'streamid' to circuit 'circid'."""
msg = struct.pack("!LL",streamid, circid)
self._sendAndRecv(MSG_TYPE.ATTACHSTREAM,msg)
def close_stream(self, streamid, reason=0, flags=0):
"""Close the stream 'streamid'. """
msg = struct.pack("!LBB",streamid,reason,flags)
self._sendAndRecv(MSG_TYPE.CLOSESTREAM,msg)
def close_circuit(self, circid, flags=0):
"""Close the circuit 'circid'."""
msg = struct.pack("!LB",circid,flags)
self._sendAndRecv(MSG_TYPE.CLOSECIRCUIT,msg)
def post_descriptor(self, descriptor):
"""Tell Tor about a new descriptor in 'descriptor'."""
self._sendAndRecv(MSG_TYPE.POSTDESCRIPTOR,descriptor)
class EventHandler:
"""An 'EventHandler' wraps callbacks for the events Tor can return."""
def __init__(self):
"""Create a new EventHandler."""
self._map = {
EVENT_TYPE.CIRCSTATUS : self.circStatus,
EVENT_TYPE.STREAMSTATUS : self.streamStatus,
EVENT_TYPE.ORCONNSTATUS : self.orConnStatus,
EVENT_TYPE.BANDWIDTH : self.circStatus,
EVENT_TYPE.NEWDESC : self.newDesc,
EVENT_TYPE.INFO_MSG : self.msg,
EVENT_TYPE.NOTICE_MSG : self.msg,
EVENT_TYPE.WARN_MSG : self.msg,
EVENT_TYPE.ERR_MSG : self.msg,
}
def handle(self, evbody):
"""Dispatcher: called from Connection when an event is received."""
evtype, args = self.decode(evbody)
self._map.get(evtype, self.unknownEvent)(evtype, *args)
def decode(self, body):
"""Unpack an event message into a type/arguments-tuple tuple."""
if len(body)<2:
raise ProtocolError("EVENT body too short.")
evtype, = struct.unpack("!H", body[:2])
body = body[2:]
if evtype == EVENT_TYPE.CIRCSTATUS:
if len(body)<5:
raise ProtocolError("CIRCUITSTATUS event too short.")
status,ident = struct.unpack("!BL", body[:5])
path = _unterminate(body[5:]).split(",")
args = status, ident, path
elif evtype == EVENT_TYPE.STREAMSTATUS:
if len(body)<5:
raise ProtocolError("STREAMSTATUS event too short.")
status,ident = struct.unpack("!BL", body[:5])
target = _unterminate(body[5:])
args = status, ident, target
elif evtype == EVENT_TYPE.ORCONNSTATUS:
if len(body)<2:
raise ProtocolError("ORCONNSTATUS event too short.")
status = ord(body[0])
target = _unterminate(body[1:])
args = status, target
elif evtype == EVENT_TYPE.BANDWIDTH:
if len(body)<8:
raise ProtocolError("BANDWIDTH event too short.")
read, written = struct.unpack("!LL",body[:8])
args = read, written
elif evtype == EVENT_TYPE.OBSOLETE_LOG:
args = (_unterminate(body),)
elif evtype == EVENT_TYPE.NEWDESC:
args = (_unterminate(body).split(","),)
elif EVENT_TYPE.DEBUG_MSG <= evtype <= EVENT_TYPE.ERR_MSG:
args = (EVENT_TYPE.nameOf[evtype], _unterminate(body))
else:
args = (body,)
return evtype, args
def circStatus(self, status, circID, path):
"""Called when a circuit status changes if listening to CIRCSTATUS
events. 'status' is a member of CIRC_STATUS; circID is a numeric
circuit ID, and 'path' is the circuit's path so far as a list of
names.
"""
raise NotImplemented
def streamStatus(self, status, circID, target):
"""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.
"""
raise NotImplemented
def orConnStatus(self, status, target):
"""Called when an OR connection's status changes if listening to
ORCONNSTATUS events. 'status' is a member of OR_CONN_STATUS; target
is the OR in question.
"""
raise NotImplemented
def bandwidth(self, read, written):
"""Called once a second if listening to BANDWIDTH events. 'read' is
the number of bytes read; 'written' is the number of bytes written.
"""
raise NotImplemented
def newDesc(self, identities):
"""Called when Tor learns a new server descriptor if listenting to
NEWDESC events.
"""
raise NotImplemented
def msg(self, severity, message):
"""Called when a log message of a given severity arrives if listening
to INFO_MSG, NOTICE_MSG, WARN_MSG, or ERR_MSG events."""
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 handle(self, body):
evtype, args = self.decode(body)
print >>self._out,EVENT_TYPE.nameOf[evtype],args
def secret_to_key(secret, s2k_specifier):
c = ord(s2k_specifier[8])
EXPBIAS = 6
count = (16+(c&15)) << ((c>>4) + EXPBIAS)
d = sha.new()
tmp = s2k_specifier[:8]+secret
slen = len(tmp)
while count:
if count > slen:
d.update(tmp)
count -= slen
else:
d.update(tmp[:count])
count = 0
return d.digest()
def urandom_rng(n):
f = open('/dev/urandom', 'rb')
try:
return f.read(n)
finally:
f.close()
def s2k_gen(secret, rng):
spec = "%s%s"%(rng(8), chr(96))
return "16:%s"%(
binascii.b2a_hex(spec + secret_to_key(secret, spec)))
def s2k_check(secret, k):
assert k[:3] == "16:"
k = binascii.a2b_hex(k[3:])
return secret_to_key(secret, k[:9]) == k[9:]
def run_example(host,port):
print "host is %s:%d"%(host,port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
c = Connection(s)
c.setEventHandler(DebugEventHandler())
th = c.launchThread()
c.authenticate()
print "nick",`c.get_option("nickname")`
print c.get_option("DirFetchPeriod\n")
print `c.get_info("version")`
#print `c.get_info("desc/name/moria1")`
print `c.get_info("network-status")`
print `c.get_info("addr-mappings/all")`
print `c.get_info("addr-mappings/config")`
print `c.get_info("addr-mappings/cache")`
print `c.get_info("addr-mappings/control")`
print `c.map_address([("0.0.0.0", "Foobar.com"),
("1.2.3.4", "foobaz.com"),
("frebnitz.com", "5.6.7.8"),
(".", "abacinator.onion")])`
print `c.extend_circuit(0,["moria1"])`
try:
print `c.extend_circuit(0,[""])`
except ErrorReply:
print "got error. good."
#send_signal(s,1)
#save_conf(s)
#set_option(s,"1")
#set_option(s,"bandwidthburstbytes 100000")
#set_option(s,"runasdaemon 1")
#set_events(s,[EVENT_TYPE.WARN])
c.set_events([EVENT_TYPE.ORCONNSTATUS, EVENT_TYPE.STREAMSTATUS,
EVENT_TYPE.CIRCSTATUS, EVENT_TYPE.INFO_MSG,
EVENT_TYPE.BANDWIDTH])
th.join()
return
if __name__ == '__main__':
if len(sys.argv) > 2:
print "Syntax: TorControl.py torhost:torport"
sys.exit(0)
else:
sys.argv.append("localhost:9051")
sh,sp = parseHostAndPort(sys.argv[1])
run_example(sh,sp)
--- NEW FILE: TorExample.py ---
#!/usr/bin/python
# TorExample.py -- Python module to demonstrate tor controller functionality.
# Copyright 2005 Nick Mathewson -- See LICENSE for licensing information.
#$Id: TorExample.py,v 1.1 2005/06/04 02:42:56 nickm Exp $
import socket
import sys
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"
host,port = parseHostAndPort(hostport)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
conn = Connection(s)
th = conn.launchThread(daemon)
conn.authenticate("")
return conn
def run():
if len(sys.argv)<2:
print "No command given."
cmd = sys.argv[1].replace("-","_")
del sys.argv[1]
fn = globals().get("run_"+cmd)
if fn is None:
print "Unrecognized command:",cmd
fn()
def run_set_config():
conn = getConnection()
if sys.argv[1] == '--save':
save = 1
del sys.argv[1]
else:
save = 0
kvList = []
for i in xrange(1, len(sys.argv), 2):
kvList.append((sys.argv[i], sys.argv[i+1]))
conn.set_options(kvList)
if save:
conn.save_conf()
def run_get_config():
conn = getConnection()
opts = conn.get_option(sys.argv[1:])
for k in sys.argv[1:]:
print "KEY:",k
print "VALUE:",opts.get(k)
def run_get_info():
conn = getConnection()
opts = conn.get_option(sys.argv[1:])
for k in sys.argv[1:]:
print "KEY:",k
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)
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)
def run_authdemo():
conn = getConnection()
conn.close()
#XXXX