[or-cvs] r11002: Moved CircuitHandler and StreamHandler classes to PathSuppor (in torflow/trunk: . TorCtl)
renner at seul.org
renner at seul.org
Tue Jul 31 05:58:19 UTC 2007
Author: renner
Date: 2007-07-31 01:58:18 -0400 (Tue, 31 Jul 2007)
New Revision: 11002
Modified:
torflow/trunk/TorCtl/GeoIPSupport.py
torflow/trunk/TorCtl/PathSupport.py
torflow/trunk/op-addon.py
Log:
Moved CircuitHandler and StreamHandler classes to PathSupport.py and introduced
saving of a network-model to a binary-file for being able to load it on startup.
Modified: torflow/trunk/TorCtl/GeoIPSupport.py
===================================================================
--- torflow/trunk/TorCtl/GeoIPSupport.py 2007-07-31 00:26:54 UTC (rev 11001)
+++ torflow/trunk/TorCtl/GeoIPSupport.py 2007-07-31 05:58:18 UTC (rev 11002)
@@ -56,39 +56,42 @@
# List of continents
continents = [africa, asia, europe, north_america, oceania, south_america]
-# Perform country -- continent mapping
def get_continent(country_code):
+ """ Perform country -- continent mapping """
for c in continents:
if c.contains(country_code):
return c.code
plog("INFO", country_code + " is not on any continent")
return None
-# Get the country code out of a GeoLiteCity record (not used)
+def get_country(ip):
+ """ Get the country via the library """
+ return geoip.country_code_by_addr(ip)
+
def get_country_from_record(ip):
+ """ Get the country code out of a GeoLiteCity record (not used) """
record = geoip.record_by_addr(ip)
if record != None:
return record['country_code']
-# Router class extended to GeoIP
class GeoIPRouter(TorCtl.Router):
+ """ Router class extended to GeoIP """
def __init__(self, router):
self.__dict__ = router.__dict__
- # Select method to get the country_code here
- self.country_code = geoip.country_code_by_addr(self.get_ip_dotted())
- #self.country_code = get_country_from_record(self.get_ip_dotted())
+ self.country_code = get_country(self.get_ip_dotted())
if self.country_code == None:
plog("INFO", self.nickname + ": Country code not found")
self.continent = None
else: self.continent = get_continent(self.country_code)
- # Convert long int back to dotted quad string
def get_ip_dotted(self):
+ """ Convert long int back to dotted quad string """
return socket.inet_ntoa(struct.pack('>I', self.ip))
class GeoIPConfig:
""" Class to configure GeoIP-based path building """
- def __init__(self, unique_countries, max_crossings, entry_country, exit_country, excludes):
+ def __init__(self, unique_countries, max_crossings, entry_country,
+ exit_country, excludes):
# TODO: Somehow ensure validity of the configuration
# Do not use a country twice in a route
Modified: torflow/trunk/TorCtl/PathSupport.py
===================================================================
--- torflow/trunk/TorCtl/PathSupport.py 2007-07-31 00:26:54 UTC (rev 11001)
+++ torflow/trunk/TorCtl/PathSupport.py 2007-07-31 05:58:18 UTC (rev 11002)
@@ -17,10 +17,11 @@
"AtLeastNNodeRestriction", "NotNodeRestriction", "Subnet16Restriction",
"UniqueRestriction", "UniformGenerator", "OrderedExitGenerator",
"BwWeightedGenerator", "PathSelector", "Connection", "NickRestriction",
-"IdHexRestriction", "PathBuilder", "SelectionManager",
-"CountryCodeRestriction", "CountryRestriction", "UniqueCountryRestriction",
-"SingleCountryRestriction", "ContinentRestriction",
-"ContinentJumperRestriction", "UniqueContinentRestriction"]
+"IdHexRestriction", "PathBuilder", "CircuitHandler", "StreamHandler",
+"SelectionManager", "CountryCodeRestriction", "CountryRestriction",
+"UniqueCountryRestriction", "SingleCountryRestriction",
+"ContinentRestriction", "ContinentJumperRestriction",
+"UniqueContinentRestriction"]
#################### Path Support Interfaces #####################
@@ -661,9 +662,12 @@
self.exit = None
self.built = False
self.dirty = False
+ self.closed = False
self.detached_cnt = 0
self.last_extended_at = time.time()
- self.pending_streams = [] # Which stream IDs are pending us
+ self.extend_times = [] # List of all extend-durations
+ self.setup_duration = None # Sum of extend-times
+ self.pending_streams = [] # Which stream IDs are pending us
def id_path(self): return map(lambda r: r.idhex, self.path)
@@ -979,9 +983,278 @@
def bandwidth_event(self, b): pass # For heartbeat only..
+################### CircuitHandler #############################
+
+class CircuitHandler(PathBuilder):
+ """ CircuitHandler that extends from PathBuilder """
+ def __init__(self, c, selmgr, num_circuits, RouterClass):
+ PathBuilder.__init__(self, c, selmgr, RouterClass)
+ self.num_circuits = num_circuits # Size of the circuit pool
+ self.check_circuit_pool() # Bring up the pool of circs
+
+ def check_circuit_pool(self):
+ """ Init or check the status of the circuit-pool """
+ # Get current number of circuits
+ n = len(self.circuits.values())
+ i = self.num_circuits-n
+ if i > 0:
+ plog("INFO", "Checked pool of circuits: we need to build " +
+ str(i) + " circuits")
+ # Schedule (num_circs-n) circuit-buildups
+ while (n < self.num_circuits):
+ self.build_circuit("255.255.255.255", 80)
+ plog("DEBUG", "Scheduled circuit No. " + str(n+1))
+ n += 1
+
+ def build_circuit(self, host, port):
+ """ Build a circuit """
+ circ = None
+ while circ == None:
+ try:
+ self.selmgr.set_target(host, port)
+ circ = self.c.build_circuit(self.selmgr.pathlen,
+ self.selmgr.path_selector)
+ self.circuits[circ.circ_id] = circ
+ except TorCtl.ErrorReply, e:
+ # FIXME: How come some routers are non-existant? Shouldn't
+ # we have gotten an NS event to notify us they disappeared?
+ plog("NOTICE", "Error building circuit: " + str(e.args))
+ return circ
+
+ def close_circuit(self, id):
+ """ Close a circuit with given id """
+ # TODO: Pass streams to another circ before closing?
+ self.circuits[id].closed = True
+ try: self.c.close_circuit(id)
+ except TorCtl.ErrorReply, e:
+ plog("ERROR", "Failed closing circuit " + str(id) + ": " + str(e))
+
+ def circ_status_event(self, c):
+ """ Handle circuit status events """
+ output = [c.event_name, str(c.circ_id), c.status]
+ if c.path: output.append(",".join(c.path))
+ if c.reason: output.append("REASON=" + c.reason)
+ if c.remote_reason: output.append("REMOTE_REASON=" + c.remote_reason)
+ plog("DEBUG", " ".join(output))
+
+ # Circuits we don't control get built by Tor
+ if c.circ_id not in self.circuits:
+ plog("DEBUG", "Ignoring circuit " + str(c.circ_id) +
+ " (controlled by Tor)")
+ return
+
+ # EXTENDED
+ if c.status == "EXTENDED":
+ # Compute elapsed time
+ extend_time = c.arrived_at-self.circuits[c.circ_id].last_extended_at
+ self.circuits[c.circ_id].extend_times.append(extend_time)
+ plog("INFO", "Circuit " + str(c.circ_id) + " extended in " +
+ str(extend_time) + " sec")
+ self.circuits[c.circ_id].last_extended_at = c.arrived_at
+
+ # FAILED & CLOSED
+ elif c.status == "FAILED" or c.status == "CLOSED":
+ # XXX: Can still get a STREAM FAILED for this circ after this
+ circ = self.circuits[c.circ_id]
+ # Actual removal of the circ
+ del self.circuits[c.circ_id]
+ # Give away pending streams
+ for stream in circ.pending_streams:
+ plog("DEBUG", "Finding new circ for " + str(stream.strm_id))
+ self.attach_stream_any(stream, stream.detached_from)
+ # Check if there are enough circs
+ self.check_circuit_pool()
+ return
+
+ # BUILT
+ elif c.status == "BUILT":
+ circ = self.circuits[c.circ_id]
+ circ.built = True
+ for stream in circ.pending_streams:
+ try:
+ self.c.attach_stream(stream.strm_id, c.circ_id)
+ except TorCtl.ErrorReply, e:
+ # No need to retry here. We should get the failed
+ # event for either the circ or stream next
+ plog("WARN", "Error attaching stream: " + str(e.args))
+ # Compute duration by summing up extend_times
+ duration = reduce(lambda x, y: x+y, circ.extend_times, 0.0)
+ plog("INFO", "Circuit " + str(c.circ_id) + " needed " +
+ str(duration) + " seconds to be built")
+ # Save the duration to the circuit for later use
+ circ.setup_duration = duration
+
+ # OTHER?
+ else:
+ # If this was e.g. a LAUNCHED
+ pass
+
+################### StreamHandler ##############################
+
+class StreamHandler(CircuitHandler):
+ """ StreamHandler that extends from the CircuitHandler """
+ def __init__(self, c, selmgr, num_circs, RouterClass):
+ CircuitHandler.__init__(self, c, selmgr, num_circs, RouterClass)
+ self.sorted_circs = None # optional sorted list
+
+ def clear_dns_cache(self):
+ """ Send signal CLEARDNSCACHE """
+ lines = self.c.sendAndRecv("SIGNAL CLEARDNSCACHE\r\n")
+ for _, msg, more in lines:
+ plog("DEBUG", "CLEARDNSCACHE: " + msg)
+
+ def close_stream(self, id, reason):
+ """ Close a stream with given id and reason """
+ self.c.close_stream(id, reason)
+
+ def create_and_attach(self, stream, unattached_streams):
+ """ Create a new circuit and attach (stream + unattached_streams) """
+ circ = self.build_circuit(stream.host, stream.port)
+ for u in unattached_streams:
+ plog("DEBUG", "Attaching " + str(u.strm_id) +
+ " pending build of circuit " + str(circ.circ_id))
+ u.pending_circ = circ
+ circ.pending_streams.extend(unattached_streams)
+ self.circuits[circ.circ_id] = circ
+ self.last_exit = circ.exit
+
+ def attach_stream_any(self, stream, badcircs):
+ """ Attach a regular user stream """
+ unattached_streams = [stream]
+ if self.new_nym:
+ self.new_nym = False
+ plog("DEBUG", "Obeying new nym")
+ for key in self.circuits.keys():
+ if (not self.circuits[key].dirty
+ and len(self.circuits[key].pending_streams)):
+ plog("WARN", "New nym called, destroying circuit "+str(key)
+ +" with "+str(len(self.circuits[key].pending_streams))
+ +" pending streams")
+ unattached_streams.extend(self.circuits[key].pending_streams)
+ del self.circuits[key].pending_streams[:]
+ # FIXME: Consider actually closing circs if no streams
+ self.circuits[key].dirty = True
+
+ # Check if there is a sorted list of circs
+ if self.sorted_circs: list = self.sorted_circs
+ else: list = self.circuits.values()
+ for circ in list:
+ # Check each circuit
+ if circ.built and not circ.closed and circ.circ_id not in badcircs and not circ.dirty:
+ if circ.exit.will_exit_to(stream.host, stream.port):
+ try:
+ self.c.attach_stream(stream.strm_id, circ.circ_id)
+ stream.pending_circ = circ # Only one possible here
+ circ.pending_streams.append(stream)
+ self.last_exit = circ.exit
+ except TorCtl.ErrorReply, e:
+ # No need to retry here. We should get the failed
+ # event for either the circ or stream next
+ plog("WARN", "Error attaching stream: " + str(e.args))
+ return
+ break
+ else:
+ plog("DEBUG", "Circuit " + str(circ.circ_id) + " won't exit")
+ else:
+ self.create_and_attach(stream, unattached_streams)
+
+ def stream_status_event(self, s):
+ """ Catch user stream events """
+ # Construct debugging output
+ output = [s.event_name, str(s.strm_id), s.status, str(s.circ_id), s.target_host, str(s.target_port)]
+ if s.reason: output.append("REASON=" + s.reason)
+ if s.remote_reason: output.append("REMOTE_REASON=" + s.remote_reason)
+ plog("DEBUG", " ".join(output))
+
+ # If target_host is not an IP-address
+ if not re.match(r"\d+.\d+.\d+.\d+", s.target_host):
+ s.target_host = "255.255.255.255" # ignore DNS for exit policy check
+
+ # NEW or NEWRESOLVE
+ if s.status == "NEW" or s.status == "NEWRESOLVE":
+ if s.status == "NEWRESOLVE" and not s.target_port:
+ s.target_port = self.resolve_port
+ # Set up the new stream
+ stream = Stream(s.strm_id, s.target_host, s.target_port, s.status)
+ self.streams[s.strm_id] = stream
+ self.attach_stream_any(self.streams[s.strm_id], self.streams[s.strm_id].detached_from)
+
+ # DETACHED
+ elif s.status == "DETACHED":
+ # Stream not found
+ if s.strm_id not in self.streams:
+ plog("WARN", "Detached stream " + str(s.strm_id) + " not found")
+ self.streams[s.strm_id] = Stream(s.strm_id, s.target_host, s.target_port, "NEW")
+ # Circuit not found
+ if not s.circ_id:
+ plog("WARN", "Stream " + str(s.strm_id) + " detached from no circuit!")
+ else:
+ self.streams[s.strm_id].detached_from.append(s.circ_id)
+ # Detect timeouts on user streams
+ if s.reason == "TIMEOUT":
+ # TODO: Count timeouts on streams?
+ #self.streams[s.strm_id].timeout_counter += 1
+ plog("DEBUG", "User stream timed out on circuit " + str(s.circ_id))
+ # Stream was pending
+ if self.streams[s.strm_id] in self.streams[s.strm_id].pending_circ.pending_streams:
+ self.streams[s.strm_id].pending_circ.pending_streams.remove(self.streams[s.strm_id])
+ # Attach to another circ
+ self.streams[s.strm_id].pending_circ = None
+ self.attach_stream_any(self.streams[s.strm_id], self.streams[s.strm_id].detached_from)
+
+ # SUCCEEDED
+ if s.status == "SUCCEEDED":
+ if s.strm_id not in self.streams:
+ plog("NOTICE", "Succeeded stream " + str(s.strm_id) + " not found")
+ return
+ if s.circ_id and self.streams[s.strm_id].pending_circ.circ_id != s.circ_id:
+ # Hrmm.. this can happen on a new-nym.. Very rare, putting warn
+ # in because I'm still not sure this is correct
+ plog("WARN", "Mismatch of pending: "
+ + str(self.streams[s.strm_id].pending_circ.circ_id) + " vs "
+ + str(s.circ_id))
+ self.streams[s.strm_id].circ = self.circuits[s.circ_id]
+ else:
+ self.streams[s.strm_id].circ = self.streams[s.strm_id].pending_circ
+ self.streams[s.strm_id].pending_circ.pending_streams.remove(self.streams[s.strm_id])
+ self.streams[s.strm_id].pending_circ = None
+ self.streams[s.strm_id].attached_at = s.arrived_at
+
+ # FAILED or CLOSED
+ elif s.status == "FAILED" or s.status == "CLOSED":
+ if s.strm_id not in self.streams:
+ plog("NOTICE", "Failed stream " + str(s.strm_id) + " not found")
+ return
+ # if not s.circ_id:
+ # plog("WARN", "Stream " + str(s.strm_id) + " closed/failed from no circuit")
+ # We get failed and closed for each stream, let CLOSED do the cleanup
+ if s.status == "FAILED":
+ # Avoid busted circuits that will not resolve or carry traffic
+ self.streams[s.strm_id].failed = True
+ if s.circ_id in self.circuits: self.circuits[s.circ_id].dirty = True
+ elif self.streams[s.strm_id].attached_at != 0:
+ plog("WARN", "Failed stream on unknown circuit " + str(s.circ_id))
+ return
+ # CLOSED
+ if self.streams[s.strm_id].pending_circ:
+ self.streams[s.strm_id].pending_circ.pending_streams.remove(self.streams[s.strm_id])
+ # Actual removal of the stream
+ del self.streams[s.strm_id]
+
+ # REMAP
+ elif s.status == "REMAP":
+ if s.strm_id not in self.streams:
+ plog("WARN", "Remap id "+str(s.strm_id)+" not found")
+ else:
+ if not re.match(r"\d+.\d+.\d+.\d+", s.target_host):
+ s.target_host = "255.255.255.255"
+ plog("NOTICE", "Non-IP remap for "+str(s.strm_id) +
+ " to " + s.target_host)
+ self.streams[s.strm_id].host = s.target_host
+ self.streams[s.strm_id].port = s.target_port
+
########################## Unit tests ##########################
-
def do_unit(rst, r_list, plamb):
print "\n"
print "-----------------------------------"
Modified: torflow/trunk/op-addon.py
===================================================================
--- torflow/trunk/op-addon.py 2007-07-31 00:26:54 UTC (rev 11001)
+++ torflow/trunk/op-addon.py 2007-07-31 05:58:18 UTC (rev 11002)
@@ -52,7 +52,6 @@
GEOIP = "GeoIP"
RTT = "RTT"
-# Set global variables here
# Measure the circuits
measure_circs = config.getboolean(RTT, "measure_circs")
if measure_circs:
@@ -128,6 +127,9 @@
use_guards = config.getboolean(NODE_SELECTION, "use_guards"),
geoip_config = get_geoip_config())
+# Path to directory where to store files
+data_dir = "data/op-addon/"
+
## Connection #################################################################
class Connection(TorCtl.Connection):
@@ -200,7 +202,6 @@
## FileHandler ################################################################
-# TODO: Move this to TorCtl.TorUtil?
class FileHandler:
""" FileHandler class for writing/appending collected data to a file """
def __init__(self, filename):
@@ -236,11 +237,7 @@
self.timeout_counter = 0 # timeout limit
self.slowness_counter = 0 # slowness limit
self.rtt_created = False # if this was created from the model
- # TODO: Move these to PathSupport.py?
- self.closed = False # mark circuit closed
- self.extend_times = [] # list of all extend-times
- self.setup_duration = None # sum of extend-times
-
+
def add_rtt(self, rtt):
""" Add a new value and refresh the stats """
# Set current
@@ -276,7 +273,6 @@
## CircuitBuildingStats #######################################################
-# TODO: Move to TorCtl.TorUtil?
class CircuitBuildingStats(Stats):
""" Create an instance of this and gather overall circuit stats """
def __init__(self):
@@ -329,27 +325,43 @@
""" Create a string for printing out information """
s = ""
for l in self.links:
- # Get the single objects
- s += l.src.nickname + "--" + l.dest.nickname +\
- " (" + str(l.current_rtt) + ") " + ", "
- return "Route proposal: " + s + "--> " + str(self.rtt) + " sec"
+ s += str(l.src) + "--" + l.dest + " (" + str(l.current_rtt) + ") " + ", "
+ return s + "--> " + str(self.rtt) + " sec"
class NetworkModel:
""" This class is used to record measured RTTs for single links in a model
of the 'currently explored subnet' (undirected graph) """
- def __init__(self, rooter):
+ def __init__(self, logfile=None):
""" Constructor: pass the root of all our circuits """
- # Use XDiGraph() (= directed)?
- self.graph = networkx.XGraph(name="Explored Tor Subnet",
- selfloops=False, multiedges=False)
- # Initially add THIS proxy to the model
- self.root = rooter
- self.graph.add_node(self.root)
- self.proposals = []
- plog("DEBUG", "NetworkModel initiated: added " + self.root.nickname)
+ self.pickle_path = "data/op-addon/network-model.pickle"
+ self.logfile = logfile # Optional logfile
+ self.proposals = [] # Current list of circ-proposals
+ self.prefixes = {} # Prefixes for DFS
+ try:
+ self.graph = self.load_graph()
+ self.find_all_proposals()
+ self.print_info()
+ except:
+ plog("INFO", "Could not load a model, creating a new one ..")
+ self.graph = networkx.XGraph(name="Explored Tor Subnet")
+ self.graph.add_node(None)
+ plog("INFO", "NetworkModel initiated")
+ def save_graph(self):
+ """ Write the graph to a binary file """
+ start = time.time()
+ networkx.write_gpickle(self.graph, self.pickle_path)
+ plog("INFO", "Saved graph to '" + self.pickle_path +
+ "' in " + str(time.time()-start) + " sec")
+
+ def load_graph(self):
+ """ Load a graph from a binary file and return it """
+ graph = networkx.read_gpickle(self.pickle_path)
+ plog("INFO", "Loaded graph from '" + self.pickle_path + "'")
+ return graph
+
def add_link(self, src, dest, rtt):
- """ Add a link to the graph given src, dest & rtt """
+ """ Add link to the graph given src, dest (routers) & rtt (LinkInfo) """
self.graph.add_edge(src, dest, LinkInfo(src, dest, rtt))
def add_circuit(self, c):
@@ -363,14 +375,14 @@
# First hop --> add Link from Root to 1
if i == 1:
link_rtt = c.part_rtts[i]
- self.add_link(self.root, c.path[i-1], link_rtt)
+ self.add_link(None, c.path[i-1].idhex, link_rtt)
# Handle i -- (i+1)
if i+1 in c.part_rtts:
link_rtt = c.part_rtts[i+1] - c.part_rtts[i]
if link_rtt > 0:
plog("INFO", "Computed link-RTT " + str(i) + ": " + str(link_rtt))
# Save to NetworkModel
- self.add_link(c.path[i-1], c.path[i], link_rtt)
+ self.add_link(c.path[i-1].idhex, c.path[i].idhex, link_rtt)
else:
plog("WARN", "Negative link-RTT " + str(i) + ": " + str(link_rtt))
# Handle (n-1) -- n
@@ -380,7 +392,7 @@
if link_rtt > 0:
plog("INFO", "Computed link-RTT " + str(i) + ": " + str(link_rtt))
# Save to NetworkModel
- self.add_link(c.path[i-1], c.path[i], link_rtt)
+ self.add_link(c.path[i-1].idhex, c.path[i].idhex, link_rtt)
else:
plog("WARN", "Negative link-RTT " + str(i) + ": " + str(link_rtt))
@@ -392,36 +404,22 @@
links.append(self.graph.get_edge(path[i], path[i+1]))
return links
- def find_circuits(self):
+ def find_all_proposals(self):
+ """ Call visit on the root-node """
# Reset list of proposals and prefixes for DFS
self.proposals = []
- self.prefixes = {}
- # Measure for info
+ self.prefixes.clear()
start = time.time()
# Start the search
- self.visit(self.root, [])
+ self.visit(None, [])
# Sort proposals for their RTTs
sort_list(self.proposals, lambda x: x.rtt)
- # Some logging
- plog("DEBUG", "Finding " + str(len(self.proposals)) +
+ plog("INFO", "Finding " + str(len(self.proposals)) +
" proposals and sorting them took us " +
str(time.time()-start) + " seconds")
- # Print all of them for debugging/info
- for p in self.proposals:
- print(p.to_string())
- def get_proposals(self, n):
- """ Return all proposals with rtt <= n seconds """
- ret = []
- for p in self.proposals:
- if p.rtt <= n:
- ret.append(p)
- plog("DEBUG", "Found " + str(len(ret)) +
- " path proposals having RTT <= " + str(n) + " sec")
- return ret
-
def visit(self, node, path, i=1):
- """ Recursive Depth-First-Search: Maybe use some existing method? """
+ """ Recursive Depth-First-Search: Maybe use some existing methods """
if node not in path:
path.append(node)
# Root -- Exit
@@ -435,340 +433,57 @@
if n not in self.prefixes[i]:
self.visit(n, copy.copy(self.prefixes[i]), i+1)
- def print_graph(self):
- """ Print current info about the graph """
- print(self.graph.info())
+ def get_proposals(self, n):
+ """ Return all proposals having rtt <= n seconds """
+ ret = []
+ for p in self.proposals:
+ if p.rtt <= n:
+ ret.append(p)
+ plog("INFO", "Found " + str(len(ret)) +
+ " path proposals having RTT <= " + str(n) + " sec")
+ return ret
-## EventHandlers ##############################################################
-
-# TODO: Move to PathSupport
-class CircuitHandler(PathSupport.PathBuilder):
- """ CircuitHandler that extends from PathBuilder """
- def __init__(self, c, selmgr, num_circuits):
- # Init the PathBuilder
- PathSupport.PathBuilder.__init__(self, c, selmgr, GeoIPSupport.GeoIPRouter)
- self.num_circuits = num_circuits # size of the circuit pool
- self.check_circuit_pool() # bring up the pool of circs
- self.circ_stats = CircuitBuildingStats() # record setup-times
- # Filehandlers for saving stats about circuit building
- self.stats_logger = FileHandler("data/op-addon/circ-setup-stats")
- self.setup_logger = FileHandler("data/op-addon/circ-setup-durations")
-
- def check_circuit_pool(self):
- """ Init or check the status of our pool of circuits """
- # Get current number of circuits
- n = len(self.circuits.values())
- i = self.num_circuits - n
- if i > 0:
- plog("INFO", "Checked pool of circuits: we need to build " +
- str(i) + " circuits")
- # Schedule (num_circs - n) circuit-buildups
- while (n < self.num_circuits):
- self.build_idle_circuit()
- plog("DEBUG", "Scheduled circuit No. " + str(n+1))
- n += 1
-
- def close_circuit(self, id):
- """ Try to close a circuit with given id """
- # TODO: Pass streams to another circ before closing?
- self.circuits[id].closed = True
- try: self.c.close_circuit(id)
- except TorCtl.ErrorReply, e:
- plog("ERROR", "Failed closing circuit " + str(id) + ": " + str(e))
-
- def print_circuits(self, list=None):
- """ Print out the circuits + some info, optionally pass a (sorted) list """
- if list: circs = list
- else: circs = self.circuits.values()
- plog("INFO", "We have " + str(len(circs)) + " circuits:")
- for c in circs:
- print("+ " + c.to_string())
-
- def build_idle_circuit(self):
- """ Build an idle circuit """
- circ = None
- while circ == None:
- try:
- # Configure which port to use here
- self.selmgr.set_target("255.255.255.255", 80)
- circ = self.c.build_circuit(self.selmgr.pathlen,
- self.selmgr.path_selector)
- self.circuits[circ.circ_id] = circ
- except TorCtl.ErrorReply, e:
- # FIXME: How come some routers are non-existant? Shouldn't
- # we have gotten an NS event to notify us they disappeared?
- plog("NOTICE", "Error building circuit: " + str(e.args))
-
- def circ_status_event(self, c):
- """ Handle circuit status events """
- # Construct output for logging
- output = [c.event_name, str(c.circ_id), c.status]
- if c.path: output.append(",".join(c.path))
- if c.reason: output.append("REASON=" + c.reason)
- if c.remote_reason: output.append("REMOTE_REASON=" + c.remote_reason)
- plog("DEBUG", " ".join(output))
-
- # Circuits we don't control get built by Tor
- if c.circ_id not in self.circuits:
- plog("DEBUG", "Ignoring circuit " + str(c.circ_id) +
- " (controlled by Tor or not yet in the list)")
- return
-
- # EXTENDED
- if c.status == "EXTENDED":
- # Compute elapsed time
- extend_time = c.arrived_at - self.circuits[c.circ_id].last_extended_at
- # Add to the list
- self.circuits[c.circ_id].extend_times.append(extend_time)
- plog("DEBUG", "Circuit " + str(c.circ_id) + " extended in " +
- str(extend_time) + " sec")
- self.circuits[c.circ_id].last_extended_at = c.arrived_at
-
- # FAILED & CLOSED
- elif c.status == "FAILED" or c.status == "CLOSED":
- # XXX: Can still get a STREAM FAILED for this circ after this
- circ = self.circuits[c.circ_id]
-
- # Logging and statistics
- if not circ.built:
- message = ["FAILED"]
- if c.reason: message.append("REASON=" + c.reason)
- if c.remote_reason: message.append("REMOTE_REASON=" + c.remote_reason)
- self.setup_logger.append(" ".join(message) + ": " +
- str(circ.extend_times))
- # Increase counter and write circ_stats to file
- self.circ_stats.failures += 1
- self.stats_logger.write(self.circ_stats.to_string())
-
- # Actual removal of the circ
- del self.circuits[c.circ_id]
- # Give away pending streams
- for stream in circ.pending_streams:
- plog("DEBUG", "Finding new circ for " + str(stream.strm_id))
- self.attach_stream_any(stream, stream.detached_from)
- # Check if there are enough circs
- self.check_circuit_pool()
- return
-
- # BUILT
- elif c.status == "BUILT":
- self.circuits[c.circ_id].built = True
- for stream in self.circuits[c.circ_id].pending_streams:
- try:
- self.c.attach_stream(stream.strm_id, c.circ_id)
- except TorCtl.ErrorReply, e:
- # No need to retry here. We should get the failed
- # event for either the circ or stream next
- plog("WARN", "Error attaching stream: " + str(e.args))
-
- # Log setup durations to file
- self.setup_logger.append(str(self.circuits[c.circ_id].extend_times))
- # Compute duration by summing up extend_times
- duration = reduce(lambda x, y: x+y,
- self.circuits[c.circ_id].extend_times, 0.0)
- plog("DEBUG", "Circuit " + str(c.circ_id) + " needed " +
- str(duration) + " seconds to be built")
- # Add duration to circ_stats and write file
- self.circ_stats.add_value(duration)
- self.stats_logger.write(self.circ_stats.to_string())
- # Save the duration to the circuit for later use
- self.circuits[c.circ_id].setup_duration = duration
-
- # OTHER?
+ def print_info(self):
+ """ Create a string holding info and the proposals for printing """
+ out = str(self.graph.info())
+ for p in self.proposals:
+ out += "\nPath Proposal: " + p.to_string()
+ # Only print them out if there are not too much
+ if len(self.proposals) < 100:
+ print(out)
else:
- # If this was e.g. a LAUNCHED
- pass
+ plog("INFO", "More than 100 proposals!")
+ print(self.graph.info())
+ # But log all of them to the file if it exists
+ if self.logfile: self.logfile.write(out)
-## StreamHandler ##############################################################
-
-# TODO: Move to PathSupport
-class StreamHandler(CircuitHandler):
- """ This is a StreamHandler that extends from the CircuitHandler """
- def __init__(self, c, selmgr, num_circs):
- # Call constructor of superclass
- CircuitHandler.__init__(self, c, selmgr, num_circs)
- self.sorted_circs = None # optional
- #self.new_nym = True
-
- def clear_dns_cache(self):
- """ Send signal CLEARDNSCACHE """
- lines = self.c.sendAndRecv("SIGNAL CLEARDNSCACHE\r\n")
- for _, msg, more in lines:
- plog("DEBUG", "CLEARDNSCACHE: " + msg)
-
- def close_stream(self, id, reason):
- """ Close a stream with given id and reason """
- self.c.close_stream(id, reason)
-
- def create_and_attach(self, stream, unattached_streams):
- """ Create a new circuit and attach (stream + unattached_streams) """
- circ = None
- self.selmgr.set_target(stream.host, stream.port)
- while circ == None:
- try:
- circ = self.c.build_circuit(self.selmgr.pathlen, self.selmgr.path_selector)
- except TorCtl.ErrorReply, e:
- plog("NOTICE", "Error building circ: " + str(e.args))
- for u in unattached_streams:
- plog("DEBUG", "Attaching " + str(u.strm_id) + " pending build of circuit " + str(circ.circ_id))
- u.pending_circ = circ
- circ.pending_streams.extend(unattached_streams)
- self.circuits[circ.circ_id] = circ
- self.last_exit = circ.exit
-
- def attach_stream_any(self, stream, badcircs):
- """ Attach a regular user stream """
- unattached_streams = [stream]
- if self.new_nym:
- self.new_nym = False
- plog("DEBUG", "Obeying new nym")
- for key in self.circuits.keys():
- if (not self.circuits[key].dirty
- and len(self.circuits[key].pending_streams)):
- plog("WARN", "New nym called, destroying circuit "+str(key)
- +" with "+str(len(self.circuits[key].pending_streams))
- +" pending streams")
- unattached_streams.extend(self.circuits[key].pending_streams)
- del self.circuits[key].pending_streams[:]
- # FIXME: Consider actually closing circs if no streams
- self.circuits[key].dirty = True
-
- # Check if there is a sorted list of circs
- if self.sorted_circs: list = self.sorted_circs
- else: list = self.circuits.values()
- for circ in list:
- # Check each circuit
- if circ.built and not circ.closed and circ.circ_id not in badcircs and not circ.dirty:
- if circ.exit.will_exit_to(stream.host, stream.port):
- try:
- self.c.attach_stream(stream.strm_id, circ.circ_id)
- stream.pending_circ = circ # Only one possible here
- circ.pending_streams.append(stream)
- # Clear cache after the attach?
- #self.clear_dns_cache()
- self.last_exit = circ.exit
- except TorCtl.ErrorReply, e:
- # No need to retry here. We should get the failed
- # event for either the circ or stream next
- plog("WARN", "Error attaching stream: " + str(e.args))
- return
- break
- else:
- plog("DEBUG", "Circuit " + str(circ.circ_id) + " won't exit")
- else:
- self.create_and_attach(stream, unattached_streams)
-
- def stream_status_event(self, s):
- """ Catch user stream events """
- # Construct debugging output
- output = [s.event_name, str(s.strm_id), s.status, str(s.circ_id), s.target_host, str(s.target_port)]
- if s.reason: output.append("REASON=" + s.reason)
- if s.remote_reason: output.append("REMOTE_REASON=" + s.remote_reason)
- plog("DEBUG", " ".join(output))
-
- # If target_host is not an IP-address
- if not re.match(r"\d+.\d+.\d+.\d+", s.target_host):
- s.target_host = "255.255.255.255" # ignore DNS for exit policy check
-
- # NEW or NEWRESOLVE
- if s.status == "NEW" or s.status == "NEWRESOLVE":
- if s.status == "NEWRESOLVE" and not s.target_port:
- s.target_port = self.resolve_port
- # Set up the new stream
- stream = Stream(s.strm_id, s.target_host, s.target_port, s.status)
- self.streams[s.strm_id] = stream
- self.attach_stream_any(self.streams[s.strm_id], self.streams[s.strm_id].detached_from)
-
- # DETACHED
- elif s.status == "DETACHED":
- # Stream not found
- if s.strm_id not in self.streams:
- plog("WARN", "Detached stream " + str(s.strm_id) + " not found")
- self.streams[s.strm_id] = Stream(s.strm_id, s.target_host, s.target_port, "NEW")
- # Circuit not found
- if not s.circ_id:
- plog("WARN", "Stream " + str(s.strm_id) + " detached from no circuit!")
- else:
- self.streams[s.strm_id].detached_from.append(s.circ_id)
- # Detect timeouts on user streams
- if s.reason == "TIMEOUT":
- # TODO: Count timeouts on the stream?
- #self.streams[s.strm_id].timeout_counter += 1
- plog("DEBUG", "User stream timed out on circuit " + str(s.circ_id))
- # Stream was pending
- if self.streams[s.strm_id] in self.streams[s.strm_id].pending_circ.pending_streams:
- self.streams[s.strm_id].pending_circ.pending_streams.remove(self.streams[s.strm_id])
- # Attach to another circ
- self.streams[s.strm_id].pending_circ = None
- self.attach_stream_any(self.streams[s.strm_id], self.streams[s.strm_id].detached_from)
-
- # SUCCEEDED
- if s.status == "SUCCEEDED":
- if s.strm_id not in self.streams:
- plog("NOTICE", "Succeeded stream " + str(s.strm_id) + " not found")
- return
- if s.circ_id and self.streams[s.strm_id].pending_circ.circ_id != s.circ_id:
- # Hrmm.. this can happen on a new-nym.. Very rare, putting warn
- # in because I'm still not sure this is correct
- plog("WARN", "Mismatch of pending: "
- + str(self.streams[s.strm_id].pending_circ.circ_id) + " vs "
- + str(s.circ_id))
- self.streams[s.strm_id].circ = self.circuits[s.circ_id]
- else:
- self.streams[s.strm_id].circ = self.streams[s.strm_id].pending_circ
- self.streams[s.strm_id].pending_circ.pending_streams.remove(self.streams[s.strm_id])
- self.streams[s.strm_id].pending_circ = None
- self.streams[s.strm_id].attached_at = s.arrived_at
-
- # FAILED or CLOSED
- elif s.status == "FAILED" or s.status == "CLOSED":
- if s.strm_id not in self.streams:
- plog("NOTICE", "Failed stream " + str(s.strm_id) + " not found")
- return
- #if not s.circ_id: plog("WARN", "Stream " + str(s.strm_id) + " closed/failed from no circuit")
- # We get failed and closed for each stream. OK to return and let the CLOSED do the cleanup
- if s.status == "FAILED":
- # Avoid busted circuits that will not resolve or carry traffic
- self.streams[s.strm_id].failed = True
- if s.circ_id in self.circuits: self.circuits[s.circ_id].dirty = True
- elif self.streams[s.strm_id].attached_at != 0:
- plog("WARN", "Failed stream on unknown circuit " + str(s.circ_id))
- return
- # CLOSED
- if self.streams[s.strm_id].pending_circ:
- self.streams[s.strm_id].pending_circ.pending_streams.remove(self.streams[s.strm_id])
- # Actual removal of the stream
- del self.streams[s.strm_id]
-
- # REMAP
- elif s.status == "REMAP":
- if s.strm_id not in self.streams:
- plog("WARN", "Remap id "+str(s.strm_id)+" not found")
- else:
- if not re.match(r"\d+.\d+.\d+.\d+", s.target_host):
- s.target_host = "255.255.255.255"
- plog("NOTICE", "Non-IP remap for "+str(s.strm_id) + " to " + s.target_host)
- self.streams[s.strm_id].host = s.target_host
- self.streams[s.strm_id].port = s.target_port
-
## PingHandler ################################################################
-class PingHandler(StreamHandler):
+class PingHandler(PathSupport.StreamHandler):
""" This class extends the general StreamHandler to handle ping-requests """
- def __init__(self, c, selmgr, num_circs, router, partial=False):
+ def __init__(self, c, selmgr, num_circs, RouterClass, partial=False):
# Anything ping-related
self.ping_queue = Queue.Queue() # (circ_id, hop)-pairs
- self.start_times = {} # dict mapping (circ_id, hop):start_time
+ self.start_times = {} # dict (circ_id, hop):start_time
+
+ # Handle global testing_mode
+ if testing_mode:
+ self.latency_logger = FileHandler(data_dir + "mean-latencies")
+
# Additional stuff for measuring single links
self.partial_circs = partial
if self.partial_circs:
- self.router = router # object that represents this OR
- self.model = NetworkModel(self.router) # model for recording link-RTTs
- # Handle testing_mode
- if testing_mode:
- self.latency_logger= FileHandler("data/op-addon/mean-latencies")
+ self.model_logger = FileHandler(data_dir + "proposals")
+ self.model = NetworkModel(self.model_logger)
+
+ # Stuff for recording statistics
+ self.circ_stats = CircuitBuildingStats() # record setup-durations
+ self.stats_logger = FileHandler(data_dir + "circ-setup-stats")
+ self.setup_logger = FileHandler(data_dir + "circ-setup-durations")
+
# Init the StreamHandler
- StreamHandler.__init__(self, c, selmgr, num_circs)
+ PathSupport.StreamHandler.__init__(self, c, selmgr, num_circs, RouterClass)
+
# Sorted circuit list
self.sorted_circs = [] # list of circs sorted by current RTT
# Start the Pinger that triggers the connections
@@ -785,11 +500,19 @@
self.sorted_circs = sort_list(self.circuits.values(), notlambda)
plog("DEBUG", "Refreshed sorted list of circuits")
+ def print_circuits(self, list=None):
+ """ Print out the circuits + some info, optionally pass a (sorted) list """
+ if list: circs = list
+ else: circs = self.circuits.values()
+ plog("INFO", "We have " + str(len(circs)) + " circuits:")
+ for c in circs:
+ print("+ " + c.to_string())
+
def enqueue_pings(self):
- """ To be schedule_immediated by pinger before the initial connection is triggered """
+ """ schedule_immediate from pinger before triggering the initial ping """
print("")
self.refresh_sorted_list()
- # XXX: Check if there are any, else let the Pinger wait a bit?
+ # XXX: Check if there are any, else let the Pinger wait?
circs = self.circuits.values()
for c in circs:
if c.built:
@@ -806,7 +529,7 @@
plog("DEBUG", "Enqueued circuit " + str(id) + " hop None")
def established(self, circ_list):
- """ Check if there is at least one circuit built """
+ """ Check if there is at least one circuit established """
for c in circ_list:
if c.built:
return True
@@ -824,8 +547,8 @@
self.print_circuits(self.sorted_circs)
if self.partial_circs:
# Print out the model
- self.model.print_graph()
- self.model.find_circuits()
+ self.model.find_all_proposals()
+ self.model.print_info()
# Enqueue again all circs
self.enqueue_pings()
@@ -917,12 +640,14 @@
def stream_status_event(self, s):
""" Separate pings from regular streams directly """
- if not (s.target_host == ping_dummy_host and s.target_port == ping_dummy_port):
+ if not (s.target_host == ping_dummy_host and
+ s.target_port == ping_dummy_port):
# This is no ping, call the other method
- return StreamHandler.stream_status_event(self, s)
+ return PathSupport.StreamHandler.stream_status_event(self, s)
# Construct debugging output
- output = [s.event_name, str(s.strm_id), s.status, str(s.circ_id), s.target_host, str(s.target_port)]
+ output = [s.event_name, str(s.strm_id), s.status, str(s.circ_id),
+ s.target_host, str(s.target_port)]
if s.reason: output.append("REASON=" + s.reason)
if s.remote_reason: output.append("REMOTE_REASON=" + s.remote_reason)
plog("DEBUG", " ".join(output))
@@ -944,11 +669,13 @@
if (s.reason == "TIMEOUT"):
self.circuits[s.circ_id].timeout_counter += 1
self.circuits[s.circ_id].slowness_counter += 1
- plog("DEBUG", str(self.circuits[s.circ_id].timeout_counter) + " timeout(s) on circuit " + str(s.circ_id))
+ plog("DEBUG", str(self.circuits[s.circ_id].timeout_counter) +
+ " timeout(s) on circuit " + str(s.circ_id))
if timeout_limit > 0:
if self.circuits[s.circ_id].timeout_counter >= timeout_limit and not self.circuits[s.circ_id].closed:
# Close the circuit
- plog("DEBUG", "Reached limit on timeouts --> closing circuit " + str(s.circ_id))
+ plog("DEBUG", "Reached limit on timeouts --> closing circuit "
+ + str(s.circ_id))
self.close_circuit(s.circ_id)
# Set RTT for this circ to None
self.circuits[s.circ_id].current_rtt = None
@@ -965,6 +692,48 @@
# Only record
self.record_ping(s)
+ def circ_status_event(self, c):
+ """ Override to record statistics on circuit-setups and -failures """
+ if c.circ_id not in self.circuits:
+ return PathSupport.CircuitHandler.circ_status_event(self, c)
+
+ # Catch FAILED/CLOSED now since circ will be removed
+ elif c.status == "FAILED" or c.status == "CLOSED":
+ circ = self.circuits[c.circ_id]
+ # Do logging and statistics
+ # TODO: Log failures on built circuits
+ if not circ.built:
+ message = ["FAILED"]
+ if c.reason: message.append("REASON=" + c.reason)
+ if c.remote_reason: message.append("REMOTE_REASON=" + c.remote_reason)
+ self.setup_logger.append(" ".join(message) + ": " +
+ str(circ.extend_times))
+ # Increase counter and write circ_stats to file
+ if self.partial_circs:
+ if circ.rtt_created:
+ self.circ_stats.failures += 1
+ self.stats_logger.write(self.circ_stats.to_string())
+ else:
+ self.circ_stats.failures += 1
+ self.stats_logger.write(self.circ_stats.to_string())
+
+ # Call the underlying method in any case
+ PathSupport.CircuitHandler.circ_status_event(self, c)
+ self.refresh_sorted_list()
+
+ # Log something on BUILT
+ if c.status == "BUILT":
+ circ = self.circuits[c.circ_id]
+ self.setup_logger.append(str(circ.extend_times))
+ # Add duration to circ_stats and write file
+ if self.partial_circs:
+ if circ.rtt_created:
+ self.circ_stats.add_value(circ.setup_duration)
+ self.stats_logger.write(self.circ_stats.to_string())
+ else:
+ self.circ_stats.add_value(circ.setup_duration)
+ self.stats_logger.write(self.circ_stats.to_string())
+
def get_trad_circs(self):
""" Count the circuits with rtt_created == False """
trad_circs = 0
@@ -977,22 +746,45 @@
""" Check if we currently do not have (TODO: had?) a circuit
with the given path (= Routers) """
for c in self.circuits.values():
- if c.path == path: return False
- # XXX: Check if this path can exit?
+ if c.path == path:
+ plog("ERROR", "Proposed circuit already exists")
+ return False
+ # Additionally check if this path can exit
if not path[len(path)-1].will_exit_to("255.255.255.255", 80):
plog("ERROR", "Proposed circuit would not exit")
return False
return True
+ def keys_to_routers(self, keys):
+ """ See if we know the routers spec. by keys and return them """
+ routers = []
+ for k in keys:
+ if k in self.routers:
+ routers.append(self.routers[k])
+ else:
+ plog("WARN", "We do not know about a router having ID " + k)
+ return
+ if len(routers) == len(keys):
+ return routers
+
+ def probabilistic_selection(self, proposals):
+ """ Select a proposal in a probabilistic way """
+ # TODO:
+ # Compute the sum of all expected RTTs
+ # Choose a random number from range(0,sum)
+ # Go through the proposals and subtract
+ pass
+
def build_idle_circuit(self):
- """ Override from CircuitHandler to support circuit-creation from the NetworkModel """
+ """ Override from CircuitHandler to support circuit-creation from model """
if self.partial_circs:
circ = None
# This is to ensure expansion of the explored subnet
# Check if ratio would be ok when adding new rtt_created circ
trad = float(self.get_trad_circs())
ratio = trad/(len(self.circuits.values())+1)
- plog("DEBUG","Expected Ratio = " + str(ratio) + " >= " + str(min_ratio) + " ?")
+ plog("DEBUG","Expected Ratio = " + str(ratio) +
+ " >= " + str(min_ratio) + " ?")
if ratio >= min_ratio:
# Get the proposals RTT <= slow
proposals = self.model.get_proposals(slow)
@@ -1001,31 +793,35 @@
proposals = sort_list(proposals, lambda x: x.rtt)
# Check them out
while len(proposals) >= 1:
- # Random choice or choose the fastest!
-
- choice = random.choice(proposals)
- #choice = proposals[0]
- # TODO: Probabilistic selection
-
- # Check if we already have a circ with this path
- if self.path_is_ok(choice.path):
- plog("INFO", "Chosen proposal: " + choice.to_string())
- try:
- circ = self.c.build_circuit_from_path(choice.path)
- circ.rtt_created = True
- self.circuits[circ.circ_id] = circ
- return
- except TorCtl.ErrorReply, e:
- plog("NOTICE", "Error building circuit: " + str(e.args))
- else:
- # Remove this proposals
- plog("DEBUG", "Proposed circuit already exists")
- proposals.remove(choice)
-
+
+ # Random choice
+ choice = random.choice(proposals)
+ # Choose the fastest
+ #choice = proposals[0]
+
+ # Convert the chosen ids to routers
+ r_path = self.keys_to_routers(choice.path)
+ if r_path:
+ # Check if we already have a circ with this path
+ if self.path_is_ok(r_path):
+ plog("INFO", "Chosen proposal: " + choice.to_string())
+ try:
+ circ = self.c.build_circuit_from_path(r_path)
+ circ.rtt_created = True
+ self.circuits[circ.circ_id] = circ
+ return
+ except TorCtl.ErrorReply, e:
+ plog("NOTICE", "Error building circuit: " + str(e.args))
+ else:
+ # Remove this proposals
+ proposals.remove(choice)
+ else:
+ plog("WARN", "keys_to_routers() did not work!")
+
# Build a circuit with the standard method
plog("DEBUG", "Falling back to normal path selection")
- CircuitHandler.build_idle_circuit(self)
-
+ PathSupport.CircuitHandler.build_idle_circuit(self)
+
## Pinger #####################################################################
class Pinger(threading.Thread):
@@ -1072,20 +868,18 @@
global path_config
ip = None
try:
- # Try to get our IP
+ # Try to determine our IP
info = conn.get_info("address")
ip = info["address"]
+ # Get the country_code
+ country_code = GeoIPSupport.get_country(ip)
+ plog("INFO", "Our IP address is " + str(ip) + " [" + str(country_code) + "]")
except:
- plog("ERROR", "Could not get our IP")
- ip = "127.0.0.1"
- # Set up a router object
- router = GeoIPSupport.GeoIPRouter(TorCtl.Router(None,"ROOT",None,False,None,None,ip,None,None))
- # TODO: Check if ip == None?
- plog("INFO", "Our IP address is " + router.get_ip_dotted() + " [" + str(router.country_code) + "]")
- # Set entry_country here?
+ plog("ERROR", "Could not get our IP and country")
+ return False
# path_config.entry_country = router.country_code
- return router
-
+ return True
+
def configure(conn):
""" Set events and options """
conn.set_events([TorCtl.EVENT_TYPE.STREAM,
@@ -1106,8 +900,8 @@
except socket.error, e:
plog("ERROR", "Could not connect to Tor process .. running?")
return
- # Setup a router instance here
- router = setup_location(conn)
+ # Setup our location
+ setup_location(conn)
# Configure myself
configure(conn)
# Get the size of the circuit-pool from config
@@ -1116,19 +910,26 @@
if measure_circs:
# We measure latencies
if measure_partial_circs:
- handler = PingHandler(conn, __selmgr, num_circs, router, True)
+ handler = PingHandler(conn, __selmgr, num_circs,
+ GeoIPSupport.GeoIPRouter, True)
else:
- handler = PingHandler(conn, __selmgr, num_circs, router)
+ handler = PingHandler(conn, __selmgr, num_circs, GeoIPSupport.GeoIPRouter)
else:
# No pings, only a StreamHandler
- handler = StreamHandler(conn, __selmgr, num_circs)
+ handler = PathSupport.StreamHandler(conn, __selmgr, num_circs,
+ GeoIPSupport.GeoIPRouter)
conn.set_event_handler(handler)
# Go to sleep to be able to get killed from the commandline
- # TODO: Do this only if not in testing_mode?
+ # TODO: Do this only if _not_ in testing_mode?
try:
while True:
time.sleep(60)
except KeyboardInterrupt:
+ # XXX: Schedule this
+ if measure_circs:
+ if measure_partial_circs:
+ handler.model.save_graph()
+ # Stop other threads?
cleanup(conn)
sys.exit(1)
More information about the tor-commits
mailing list