1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
|
#!/usr/bin/python
# Copyright 2009-2010 Mike Perry. See LICENSE file.
import PathSupport
import threading
import copy
import time
import shutil
import TorCtl
from TorUtil import plog
SQLSupport = None
# Note: be careful writing functions for this class. Remember that
# the PathBuilder has its own thread that it recieves events on
# independent from your thread that calls into here.
class ScanHandler(PathSupport.PathBuilder):
def set_pct_rstr(self, percent_skip, percent_fast):
def notlambda(sm):
sm.percent_fast=percent_fast
sm.percent_skip=percent_skip
self.schedule_selmgr(notlambda)
def reset_stats(self):
def notlambda(this):
this.reset()
self.schedule_low_prio(notlambda)
def commit(self):
plog("INFO", "Scanner committing jobs...")
cond = threading.Condition()
def notlambda2(this):
cond.acquire()
this.run_all_jobs = False
plog("INFO", "Commit done.")
cond.notify()
cond.release()
def notlambda1(this):
plog("INFO", "Committing jobs...")
this.run_all_jobs = True
self.schedule_low_prio(notlambda2)
cond.acquire()
self.schedule_immediate(notlambda1)
cond.wait()
cond.release()
plog("INFO", "Scanner commit done.")
def close_circuits(self):
cond = threading.Condition()
def notlambda(this):
cond.acquire()
this.close_all_circuits()
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
def close_streams(self, reason):
cond = threading.Condition()
plog("NOTICE", "Wedged Tor stream. Closing all streams")
def notlambda(this):
cond.acquire()
this.close_all_streams(reason)
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
def new_exit(self):
cond = threading.Condition()
def notlambda(this):
cond.acquire()
this.new_nym = True
if this.selmgr.bad_restrictions:
plog("NOTICE", "Clearing bad restrictions with reconfigure..")
this.selmgr.reconfigure(this.current_consensus())
lines = this.c.sendAndRecv("SIGNAL CLEARDNSCACHE\r\n")
for _,msg,more in lines:
plog("DEBUG", msg)
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
def idhex_to_r(self, idhex):
cond = threading.Condition()
def notlambda(this):
cond.acquire()
if idhex in self.routers:
cond._result = self.routers[idhex]
else:
cond._result = None
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
return cond._result
def name_to_idhex(self, nick):
cond = threading.Condition()
def notlambda(this):
cond.acquire()
if nick in self.name_to_key:
cond._result = self.name_to_key[nick]
else:
cond._result = None
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
return cond._result
def rank_to_percent(self, rank):
cond = threading.Condition()
def notlambda(this):
cond.acquire()
cond._pct = (100.0*rank)/len(this.sorted_r) # lol moar haxx
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
return cond._pct
def percent_to_rank(self, pct):
cond = threading.Condition()
def notlambda(this):
cond.acquire()
cond._rank = int(round((pct*len(this.sorted_r))/100.0,0)) # lol moar haxx
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
return cond._rank
def get_exit_node(self):
ret = copy.copy(self.last_exit) # GIL FTW
if ret:
plog("DEBUG", "Got last exit of "+ret.idhex)
else:
plog("DEBUG", "No last exit.")
return ret
def set_exit_node(self, arg):
cond = threading.Condition()
exit_name = arg
plog("DEBUG", "Got Setexit: "+exit_name)
def notlambda(sm):
plog("DEBUG", "Job for setexit: "+exit_name)
cond.acquire()
sm.set_exit(exit_name)
cond.notify()
cond.release()
cond.acquire()
self.schedule_selmgr(notlambda)
cond.wait()
cond.release()
class SQLScanHandler(ScanHandler):
def __init__(self, c, selmgr, RouterClass=TorCtl.Router,
strm_selector=PathSupport.StreamSelector):
# Only require sqlalchemy if we really need it.
global SQLSupport
if SQLSupport is None:
import SQLSupport
ScanHandler.__init__(self, c, selmgr, RouterClass, strm_selector)
def attach_sql_listener(self, db_uri):
plog("DEBUG", "Got sqlite: "+db_uri)
SQLSupport.setup_db(db_uri, echo=False, drop=True)
self.sql_consensus_listener = SQLSupport.ConsensusTrackerListener()
self.add_event_listener(self.sql_consensus_listener)
self.add_event_listener(SQLSupport.StreamListener())
def write_sql_stats(self, rfilename=None, stats_filter=None):
if not rfilename:
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"),
0, 100, order_by=SQLSupport.RouterStats.sbw,
recompute=True, disp_clause=stats_filter)
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
def write_strm_bws(self, rfilename=None, slice_num=0, stats_filter=None):
if not rfilename:
rfilename="./data/stats/bws-"+time.strftime("20%y-%m-%d-%H:%M:%S")
cond = threading.Condition()
def notlambda(this):
cond.acquire()
f=file(rfilename, "w")
f.write("slicenum="+str(slice_num)+"\n")
SQLSupport.RouterStats.write_bws(f, 0, 100,
order_by=SQLSupport.RouterStats.sbw,
recompute=False, disp_clause=stats_filter)
f.close()
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
def save_sql_file(self, sql_file, new_file):
cond = threading.Condition()
def notlambda(this):
cond.acquire()
SQLSupport.tc_session.close()
try:
shutil.copy(sql_file, new_file)
except Exception,e:
plog("WARN", "Error moving sql file: "+str(e))
SQLSupport.reset_all()
cond.notify()
cond.release()
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
def wait_for_consensus(self):
cond = threading.Condition()
def notlambda(this):
if this.sql_consensus_listener.last_desc_at \
!= SQLSupport.ConsensusTrackerListener.CONSENSUS_DONE:
this.sql_consensus_listener.wait_for_signal = False
plog("INFO", "Waiting on consensus result: "+str(this.run_all_jobs))
this.schedule_low_prio(notlambda)
else:
cond.acquire()
this.sql_consensus_listener.wait_for_signal = True
cond.notify()
cond.release()
plog("DEBUG", "Checking for consensus")
cond.acquire()
self.schedule_low_prio(notlambda)
cond.wait()
cond.release()
plog("INFO", "Consensus OK")
|