[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r9737: Well, stats are written. Not doing anything with them yet th (in torflow/trunk: . TorCtl)



Author: mikeperry
Date: 2007-03-05 02:31:01 -0500 (Mon, 05 Mar 2007)
New Revision: 9737

Modified:
   torflow/trunk/TorCtl/PathSupport.py
   torflow/trunk/metatroller.py
Log:
Well, stats are written. Not doing anything with them yet though, nor have
they been verified to be sane.



Modified: torflow/trunk/TorCtl/PathSupport.py
===================================================================
--- torflow/trunk/TorCtl/PathSupport.py	2007-03-05 02:40:58 UTC (rev 9736)
+++ torflow/trunk/TorCtl/PathSupport.py	2007-03-05 07:31:01 UTC (rev 9737)
@@ -16,7 +16,7 @@
 "AtLeastNNodeRestriction", "NotNodeRestriction", "Subnet16Restriction",
 "UniqueRestriction", "UniformGenerator", "OrderedExitGenerator",
 "PathSelector", "Connection", "NickRestriction", "IdHexRestriction",
-"PathBuilder"]
+"PathBuilder", "SelectionManager"]
 
 #################### Path Support Interfaces #####################
 
@@ -156,6 +156,9 @@
 #          - If middle node on the same continent as exit, exit learns nothing
 #          - else, exit has a bias on the continent of origin of user
 #            - Language and browser accept string determine this anyway
+#      - EchelonPhobicRestrictor
+#        - Does not cross international boundaries for client->Entry or
+#          Exit->destination hops
 
 class PercentileRestriction(NodeRestriction):
     """If used, this restriction MUST be FIRST in the RestrictionList."""
@@ -422,7 +425,7 @@
     def __init__(self, resolve_port, num_circuits, pathlen, order_exits,
                  percent_fast, percent_skip, min_bw, use_all_exits,
                  uniform, use_exit, use_guards):
-        self.__ordered_exit_gen = None # except this one ;)
+        self.__ordered_exit_gen = None 
         self.last_exit = None
         self.new_nym = False
         self.resolve_port = resolve_port
@@ -516,13 +519,14 @@
         self.pending_streams = [] # Which stream IDs are pending us
 
 class Stream:
-    def __init__(self, sid, host, port):
+    def __init__(self, sid, host, port, kind):
         self.sid = sid
         self.detached_from = [] # circ id #'s
         self.pending_circ = None
         self.circ = None
         self.host = host
         self.port = port
+        self.kind = kind
 
 # TODO: Make passive "PathWatcher" so people can get aggregate 
 # node reliability stats for normal usage without us attaching streams
@@ -648,7 +652,7 @@
         if s.status == "NEW" or s.status == "NEWRESOLVE":
             if s.status == "NEWRESOLVE" and not s.target_port:
                 s.target_port = self.selmgr.resolve_port
-            self.streams[s.strm_id] = Stream(s.strm_id, s.target_host, s.target_port)
+            self.streams[s.strm_id] = Stream(s.strm_id, s.target_host, s.target_port, s.status)
 
             self.attach_stream_any(self.streams[s.strm_id],
                                    self.streams[s.strm_id].detached_from)

Modified: torflow/trunk/metatroller.py
===================================================================
--- torflow/trunk/metatroller.py	2007-03-05 02:40:58 UTC (rev 9736)
+++ torflow/trunk/metatroller.py	2007-03-05 07:31:01 UTC (rev 9737)
@@ -15,6 +15,7 @@
 import threading
 import struct
 import copy
+import time
 from TorCtl import *
 from TorCtl.TorUtil import *
 from TorCtl.PathSupport import *
@@ -48,25 +49,145 @@
 class StatsRouter(TorCtl.Router):
     def __init__(self, router): # Promotion constructor :)
         self.__dict__ = router.__dict__
-        self.failed = 0
-        self.suspected = 0
-        self.circ_selections = 0
-        self.strm_selections = 0
-        self.unhibernated_at = 0
-        self.active_uptime = 0
+        self.circ_failed = 0
+        self.circ_succeeded = 0
+        self.circ_suspected = 0
+        self.circ_selections = 0 # above 3 should add to this
+        self.strm_failed = 0 # Only exits should have these
+        self.strm_succeeded = 0
+        self.strm_suspected = 0
+        self.strm_selections = 0 # above 3 should add to this
         self.reason_suspected = {}
         self.reason_failed = {}
+        self.became_active_at = 0
+        self.total_active_uptime = 0
+        self.max_bw = 0
+        self.min_bw = 0
+        self.avg_bw = 0
 
 class StatsHandler(PathSupport.PathBuilder):
     def __init__(self, c, slmgr):
         PathBuilder.__init__(self, c, slmgr, StatsRouter)
+    
+    def heartbeat_event(self, event):
+        PathBuilder.heartbeat_event(self, event)
 
-    def circ_status_event(self, event):
-        PathBuilder.circ_status_event(self, event)
+    # TODO: Use stream bandwidth events to implement reputation system
+    # from
+    # http://www.cs.colorado.edu/department/publications/reports/docs/CU-CS-1025-07.pdf
+    # (though my bet's on it not working on a real Tor network)
 
-    def stream_status_event(self, event):
-        PathBuilder.stream_status_event(self, event)
+    def circ_status_event(self, c):
+        if c.circ_id in self.circuits:
+            # XXX: Hrmm, consider making this sane in TorCtl.
+            if c.reason: lreason = c.reason
+            else: lreason = "NONE"
+            if c.remote_reason: rreason = c.remote_reason
+            else: rreason = "NONE"
+            reason = c.status+":"+lreason+":"+rreason
+            if c.status == "FAILED":
+                # update selection count
+                for r in self.circuits[c.circ_id].path: r.circ_selections += 1
 
+                # Count failed
+                for r in self.circuits[c.circ_id].path[len(c.path)-1:len(c.path)+1]:
+                    r.circ_failed += 1
+                    if not reason in r.reason_failed: r.reason_failed[reason] = 1
+                    else: r.reason_failed[reason]+=1
+                
+                # Don't count if failed was set this round, don't set 
+                # suspected..
+                if len(c.path)-2 < 0: end_susp = 0
+                else: end_susp = len(c.path)-2
+                for r in self.circuits[c.circ_id].path[:end_susp]:
+                    r.circ_suspected += 1
+                    if not reason in r.reason_suspected:
+                        r.reason_suspected[reason] = 1
+                    else: r.reason_suspected[reason]+=1
+            elif c.status == "CLOSED":
+                # Since PathBuilder deletes the circuit on a failed, 
+                # we only get this for a clean close
+                # Update circ_selections count
+                for r in self.circuits[c.circ_id].path: r.circ_selections += 1
+                
+                if lreason in ("REQUESTED", "FINISHED", "ORIGIN"):
+                    r.circ_succeeded += 1
+                else:
+                    for r in self.circuits[c.circ_id].path:
+                        if not reason in r.reason_suspected:
+                            r.reason_suspected[reason] = 1
+                        else: r.reason_suspected[reason] += 1
+                        r.circ_suspected+= 1
+        PathBuilder.circ_status_event(self, c)
+    
+    def stream_status_event(self, s):
+        if s.strm_id in self.streams:
+            # XXX: Hrmm, consider making this sane in TorCtl.
+            if s.reason: lreason = s.reason
+            else: lreason = "NONE"
+            if s.remote_reason: rreason = s.remote_reason
+            else: rreason = "NONE"
+            reason = s.status+":"+lreason+":"+rreason+":"+self.streams[s.strm_id].kind
+            if s.status in ("DETACHED", "FAILED", "CLOSED", "SUCCEEDED") \
+                    and not s.circ_id:
+                plog("WARN", "Stream "+str(s.strm_id)+" detached from no circuit!")
+                PathBuilder.stream_status_event(self, s)
+                return
+            if s.status == "DETACHED" or s.status == "FAILED":
+                    
+                # Update strm_selections count
+                for r in self.circuits[s.circ_id].path: r.strm_selections += 1
+                # Update failed count,reason_failed for exit
+                r = self.circuits[s.circ_id].exit
+                if not reason in r.reason_failed: r.reason_failed[reason] = 1
+                else: r.reason_failed[reason]+=1
+                r.strm_failed += 1
+
+                # If reason=timeout, update suspected for all
+                if lreason in ("TIMEOUT", "INTERNAL", "TORPROTOCOL", "DESTROY"):
+                    for r in self.circuits[s.circ_id].path[:-1]:
+                        r.strm_suspected += 1
+                        if not reason in r.reason_suspected:
+                            r.reason_suspected[reason] = 1
+                        else: r.reason_suspected[reason]+=1
+            elif s.status == "CLOSED":
+                # Always get both a closed and a failed.. 
+                #   - Check if the circuit exists still
+                if s.circ_id in self.circuits:
+                    if lreason in ("TIMEOUT", "INTERNAL", "TORPROTOCOL", "DESTROY"):
+                        for r in self.circuits[s.circ_id].path[:-1]:
+                            r.strm_suspected += 1
+                            if not reason in r.reason_suspected:
+                                r.reason_suspected[reason] = 1
+                            else: r.reason_suspected[reason]+=1
+                    r = self.circuits[s.circ_id].exit
+                    if lreason == "DONE":
+                        r.strm_succeeded += 1
+                    else:
+                        if not reason in r.reason_failed:
+                            r.reason_failed[reason] = 1
+                        else: r.reason_failed[reason]+=1
+                        r.strm_failed += 1
+            elif s.status == "SUCCEEDED":
+                # Update strm_selections count
+                # XXX: use SENTRESOLVE/SENTCONNECT instead?
+                for r in self.circuits[s.circ_id].path: r.strm_selections += 1
+        PathBuilder.stream_status_event(self, s)
+
+    def ns_event(self, n):
+        PathBuilder.ns_event(self, n)
+        for ns in n.nslist:
+            if not ns.idhex in self.routers:
+                continue
+            if "Running" in ns.flags:
+                if not self.routers[ns.idhex].became_active_at:
+                    self.routers[ns.idhex].became_active_at = time.time()
+            else:
+                self.routers[ns.idhex].total_active_uptime += \
+                    (time.time() - self.routers[ns.idhex].became_active_at)
+                self.routers[ns.idhex].became_active_at = 0
+                
+
 def clear_dns_cache(c):
     lines = c.sendAndRecv("SIGNAL CLEARDNSCACHE\r\n")
     for _,msg,more in lines: