def open_controller(filename,ncircuits,use_sql): """ starts stat gathering thread """ s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect((control_host,control_port)) c = PathSupport.Connection(s) c.authenticate(control_pass) # also launches thread... c.debug(file(filename+".log", "w", buffering=0)) h = CircStatsGatherer(c,__selmgr,filename,ncircuits) c.set_event_handler(h) if use_sql: from TorCtl import SQLSupport SQLSupport.setup_db("sqlite:///"+filename+".sqlite", drop=True) c.add_event_listener(SQLSupport.ConsensusTrackerListener()) c.add_event_listener(SQLSupport.CircuitListener()) global FUDValue if not FUDValue: FUDValue = c.get_option("FetchUselessDescriptors")[0][1] c.set_option("FetchUselessDescriptors", "1") c.set_events([TorCtl.EVENT_TYPE.STREAM, TorCtl.EVENT_TYPE.BW, TorCtl.EVENT_TYPE.NEWCONSENSUS, TorCtl.EVENT_TYPE.NEWDESC, TorCtl.EVENT_TYPE.CIRC, TorCtl.EVENT_TYPE.STREAM_BW], True) return c
def open_controller(filename, ncircuits, use_sql): """ starts stat gathering thread """ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((control_host, control_port)) c = PathSupport.Connection(s) c.authenticate(control_pass) # also launches thread... c.debug(file(filename + ".log", "w", buffering=0)) h = CircStatsGatherer(c, __selmgr, filename, ncircuits) c.set_event_handler(h) if use_sql: from TorCtl import SQLSupport SQLSupport.setup_db("sqlite:///" + filename + ".sqlite", drop=True) c.add_event_listener(SQLSupport.ConsensusTrackerListener()) c.add_event_listener(SQLSupport.CircuitListener()) global FUDValue if not FUDValue: FUDValue = c.get_option("FetchUselessDescriptors")[0][1] c.set_option("FetchUselessDescriptors", "1") c.set_events([ TorCtl.EVENT_TYPE.STREAM, TorCtl.EVENT_TYPE.BW, TorCtl.EVENT_TYPE.NEWCONSENSUS, TorCtl.EVENT_TYPE.NEWDESC, TorCtl.EVENT_TYPE.CIRC, TorCtl.EVENT_TYPE.STREAM_BW ], True) return c
def commandloop(s, c, h): "The main metatroller listener loop" s.write("220 Welcome to the Tor Metatroller "+mt_version+"! Try HELP for Info\r\n\r\n") percent_skip=__selmgr.percent_skip percent_fast=__selmgr.percent_fast while 1: buf = s.readline() if not buf: break m = re.search(r"^(\S+)(?:\s(\S+))?", buf) if not m: s.write("500 "+buf+" is not a metatroller command\r\n") continue (command, arg) = m.groups() if command == "GETLASTEXIT": # local assignment avoids need for lock w/ GIL # http://effbot.org/pyfaq/can-t-we-get-rid-of-the-global-interpreter-lock.htm # http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm le = h.last_exit if le: s.write("250 LASTEXIT=$"+le.idhex+" ("+le.nickname+") OK\r\n") else: s.write("250 LASTEXIT=0 (0) OK\r\n") elif command == "NEWEXIT" or command == "NEWNYM": # XXX: Seperate this clear_dns_cache(c) h.new_nym = True # GIL hack plog("DEBUG", "Got new nym") s.write("250 NEWNYM OK\r\n") elif command == "GETDNSEXIT": pass # TODO: Takes a hostname? Or prints most recent? elif command == "ORDEREXITS": try: if arg: order_exits = int(arg) def notlambda(sm): sm.order_exits=order_exits h.schedule_selmgr(notlambda) s.write("250 ORDEREXITS="+str(order_exits)+" OK\r\n") else: s.write("250 ORDEREXITS="+str(h.selmgr.order_exits)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "USEALLEXITS": try: if arg: use_all_exits = int(arg) def notlambda(sm): sm.use_all_exits=use_all_exits h.schedule_selmgr(notlambda) s.write("250 USEALLEXITS="+str(use_all_exits)+" OK\r\n") else: s.write("250 USEALLEXITS="+str(h.selmgr.use_all_exits)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "PRECIRCUITS": # XXX: Use op-addon code for this.. try: if arg: num_circuits = int(arg) def notlambda(pb): pb.num_circuits=num_circuits h.schedule_immediate(notlambda) s.write("250 PRECIRCUITS="+str(num_circuits)+" OK\r\n") else: s.write("250 PRECIRCUITS="+str(h.num_circuits)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "RESOLVEPORT": try: if arg: resolve_port = int(arg) def notlambda(pb): pb.resolve_port=resolve_port h.schedule_immediate(notlambda) s.write("250 RESOLVEPORT="+str(resolve_port)+" OK\r\n") else: s.write("250 RESOLVEPORT="+str(h.resolve_port)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "PERCENTFAST": try: if arg: percent_fast = int(arg) def notlambda(sm): sm.percent_fast=percent_fast h.schedule_selmgr(notlambda) s.write("250 PERCENTFAST="+str(percent_fast)+" OK\r\n") else: s.write("250 PERCENTFAST="+str(h.selmgr.percent_fast)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "PERCENTSKIP": try: if arg: percent_skip = int(arg) def notlambda(sm): sm.percent_skip=percent_skip h.schedule_selmgr(notlambda) s.write("250 PERCENTSKIP="+str(percent_skip)+" OK\r\n") else: s.write("250 PERCENTSKIP="+str(h.selmgr.percent_skip)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "BWCUTOFF": try: if arg: min_bw = int(arg) def notlambda(sm): sm.min_bw=min_bw h.schedule_selmgr(notlambda) s.write("250 BWCUTOFF="+str(min_bw)+" OK\r\n") else: s.write("250 BWCUTOFF="+str(h.selmgr.min_bw)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "UNIFORM": try: if arg: uniform = int(arg) def notlambda(sm): sm.uniform=uniform h.schedule_selmgr(notlambda) s.write("250 UNIFORM="+str(uniform)+" OK\r\n") else: s.write("250 UNIFORM="+str(h.selmgr.uniform)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "PATHLEN": try: if arg: pathlen = int(arg) # Technically this doesn't need a full selmgr update.. But # the user shouldn't be changing it very often.. def notlambda(sm): sm.pathlen=pathlen h.schedule_selmgr(notlambda) s.write("250 PATHLEN="+str(pathlen)+" OK\r\n") else: s.write("250 PATHLEN="+str(h.selmgr.pathlen)+" OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "SETEXIT": if arg: exit_name = arg plog("DEBUG", "Got Setexit: "+exit_name) def notlambda(sm): plog("DEBUG", "Job for setexit: "+exit_name) sm.set_exit(exit_name) h.schedule_selmgr(notlambda) s.write("250 OK\r\n") else: s.write("510 Argument expected\r\n") elif command == "GUARDNODES": try: if arg: use_guards = bool(int(arg)) plog("DEBUG", "Got Setexit: "+str(use_guards)) def notlambda(sm): plog("DEBUG", "Job for setexit: "+str(use_guards)) sm.use_guards = use_guards h.schedule_selmgr(notlambda) s.write("250 OK\r\n") except ValueError: s.write("510 Integer expected\r\n") elif command == "SQLSUPPORT": try: if arg: plog("DEBUG", "Got sqlite: "+arg) use_db = arg from TorCtl import SQLSupport SQLSupport.setup_db(use_db, echo=False, drop=True) h.add_event_listener(SQLSupport.ConsensusTrackerListener()) h.add_event_listener(SQLSupport.StreamListener()) plog("DEBUG", "Did sqlite: "+arg) s.write("250 OK\r\n") except ValueError: s.write("510 database expected\r\n") elif command == "CLOSEALLCIRCS": def notlambda(this): this.close_all_circuits() h.schedule_immediate(notlambda) s.write("250 OK\r\n") elif command == "SAVESTATS": if arg: filename = arg else: filename="./data/stats/stats-"+time.strftime("20%y-%m-%d-%H:%M:%S") def notlambda(this): this.write_stats(filename) h.schedule_low_prio(notlambda) s.write("250 OK\r\n") elif command == "SAVERATIOS": if arg: rfilename = arg else: rfilename="./data/stats/ratios-"+time.strftime("20%y-%m-%d-%H:%M:%S") def notlambda(this): this.write_ratios(rfilename) h.schedule_low_prio(notlambda) s.write("250 OK\r\n") elif command == "SAVESQL": # TODO: Use threading conditions more. Maybe even get some # better status reporting than always blindly printing OK. if arg: rfilename = arg else: rfilename="./data/stats/sql-"+time.strftime("20%y-%m-%d-%H:%M:%S") cond = threading.Condition() def notlambda(h): cond.acquire() SQLSupport.RouterStats.write_stats(file(rfilename, "w"), percent_skip, percent_fast, order_by=SQLSupport.RouterStats.sbw, recompute=True) cond.notify() cond.release() cond.acquire() h.schedule_low_prio(notlambda) cond.wait() cond.release() s.write("250 OK\r\n") elif command == "RESETSTATS": plog("DEBUG", "Got resetstats") def notlambda(this): this.reset() h.schedule_low_prio(notlambda) s.write("250 OK\r\n") elif command == "COMMIT": plog("DEBUG", "Got commit") def notlambda(this): this.run_all_jobs = True h.schedule_immediate(notlambda) s.write("250 OK\r\n") elif command == "HELP": s.write("250 OK\r\n") else: s.write("500 "+buf+" is not a metatroller command\r\n") s.close()