[or-cvs] r20078: {arm} Miscellaneous fix and feature batch. added: relay's flags to (arm/trunk/interface)

atagar at seul.org atagar at seul.org
Sat Jul 18 07:16:16 UTC 2009


Author: atagar
Date: 2009-07-18 03:16:16 -0400 (Sat, 18 Jul 2009)
New Revision: 20078

Modified:
   arm/trunk/interface/confPanel.py
   arm/trunk/interface/connPanel.py
   arm/trunk/interface/controller.py
   arm/trunk/interface/headerPanel.py
   arm/trunk/interface/logPanel.py
Log:
Miscellaneous fix and feature batch.
added: relay's flags to the header
added: listing by relay nickname
added: additional event aliases and option for NEWCONSENSUS
fix: updates cached consensus mappings with NEWDESC and NEWCONSENSUS events
change: use constant "Listing" label for sorting rather than current view
change: removed 'reload torrc' option (deceptive and useless)



Modified: arm/trunk/interface/confPanel.py
===================================================================
--- arm/trunk/interface/confPanel.py	2009-07-18 06:07:13 UTC (rev 20077)
+++ arm/trunk/interface/confPanel.py	2009-07-18 07:16:16 UTC (rev 20078)
@@ -40,7 +40,6 @@
     elif key == curses.KEY_PPAGE: self.scroll = max(self.scroll - pageHeight, 0)
     elif key == curses.KEY_NPAGE: self.scroll = max(0, min(self.scroll + pageHeight, len(self.confContents) - pageHeight))
     elif key == ord('n') or key == ord('N'): self.showLineNum = not self.showLineNum
-    elif key == ord('r') or key == ord('R'): self.reset()
     elif key == ord('s') or key == ord('S'):
       self.stripComments = not self.stripComments
       self.scroll = 0

Modified: arm/trunk/interface/connPanel.py
===================================================================
--- arm/trunk/interface/connPanel.py	2009-07-18 06:07:13 UTC (rev 20077)
+++ arm/trunk/interface/connPanel.py	2009-07-18 07:16:16 UTC (rev 20078)
@@ -10,17 +10,17 @@
 import hostnameResolver
 
 # enums for listing types
-LIST_IP, LIST_HOSTNAME, LIST_FINGERPRINT = range(3)
-LIST_LABEL = {LIST_IP: "IP", LIST_HOSTNAME: "Hostname", LIST_FINGERPRINT: "Fingerprint"}
+LIST_IP, LIST_HOSTNAME, LIST_FINGERPRINT, LIST_NICKNAME = range(4)
+LIST_LABEL = {LIST_IP: "IP Address", LIST_HOSTNAME: "Hostname", LIST_FINGERPRINT: "Fingerprint", LIST_NICKNAME: "Nickname"}
 
 # enums for sorting types (note: ordering corresponds to SORT_TYPES for easy lookup)
 # TODO: add ORD_BANDWIDTH -> (ORD_BANDWIDTH, "Bandwidth", lambda x, y: ???)
 ORD_TYPE, ORD_FOREIGN_LISTING, ORD_SRC_LISTING, ORD_DST_LISTING, ORD_COUNTRY, ORD_FOREIGN_PORT, ORD_SRC_PORT, ORD_DST_PORT = range(8)
 SORT_TYPES = [(ORD_TYPE, "Connection Type",
                 lambda x, y: TYPE_WEIGHTS[x[CONN_TYPE]] - TYPE_WEIGHTS[y[CONN_TYPE]]),
-              (ORD_FOREIGN_LISTING, "* (Foreign)", None),
-              (ORD_SRC_LISTING, "* (Source)", None),
-              (ORD_DST_LISTING, "* (Dest.)", None),
+              (ORD_FOREIGN_LISTING, "Listing (Foreign)", None),
+              (ORD_SRC_LISTING, "Listing (Source)", None),
+              (ORD_DST_LISTING, "Listing (Dest.)", None),
               (ORD_COUNTRY, "Country Code",
                 lambda x, y: cmp(x[CONN_COUNTRY], y[CONN_COUNTRY])),
               (ORD_FOREIGN_PORT, "Port (Foreign)",
@@ -36,7 +36,34 @@
 # enums for indexes of ConnPanel 'connections' fields
 CONN_TYPE, CONN_L_IP, CONN_L_PORT, CONN_F_IP, CONN_F_PORT, CONN_COUNTRY = range(6)
 
-# provides bi-directional mapping of sorts with their associated labels (with getSortLabel)
+# provides bi-directional mapping of sorts with their associated labels
+def getSortLabel(sortType, withColor = False):
+  """
+  Provides label associated with a type of sorting. Throws ValueEror if no such
+  sort exists. If adding color formatting this wraps with the following mappings:
+  Connection Type     red
+  Listing *           blue
+  Port *              green
+  Bandwidth           cyan
+  Country Code        yellow
+  """
+  
+  for (type, label, func) in SORT_TYPES:
+    if sortType == type:
+      color = None
+      
+      if withColor:
+        if label == "Connection Type": color = "red"
+        elif label.startswith("Listing"): color = "blue"
+        elif label.startswith("Port"): color = "green"
+        elif label == "Bandwidth": color = "cyan"
+        elif label == "Country Code": color = "yellow"
+      
+      if color: return "<%s>%s</%s>" % (color, label, color)
+      else: return label
+  
+  raise ValueError(sortType)
+
 def getSortType(sortLabel):
   """
   Provides sort type associated with a given label. Throws ValueEror if label
@@ -45,8 +72,6 @@
   
   for (type, label, func) in SORT_TYPES:
     if sortLabel == label: return type
-    elif label.startswith("*"):
-      if sortLabel in [label.replace("*", listingType) for listingType in LIST_LABEL.values()]: return type
   raise ValueError(sortLabel)
 
 class ConnPanel(TorCtl.PostEventListener, util.Panel):
@@ -66,7 +91,9 @@
     self.isPaused = False
     self.resolver = hostnameResolver.HostnameResolver()
     self.fingerprintLookupCache = {}                              # chache of (ip, port) -> fingerprint
+    self.nicknameLookupCache = {}                                 # chache of (ip, port) -> nickname
     self.fingerprintMappings = _getFingerprintMappings(self.conn) # mappings of ip -> [(port, OR identity), ...]
+    self.nickname = self.conn.get_option("Nickname")[0][1]
     
     # gets process id to make sure we get the correct netstat data
     psCall = os.popen('ps -C tor -o pid')
@@ -92,13 +119,44 @@
     self.reset()
   
   # when consensus changes update fingerprint mappings
-  def new_consensus_event(self, n):
-    self.fingerprintLookupCache = {}
-    self.fingerprintMappings = _getFingerprintMappings(self.conn)
+  def new_consensus_event(self, event):
+    self.fingerprintLookupCache.clear()
+    self.nicknameLookupCache.clear()
+    self.fingerprintMappings = _getFingerprintMappings(self.conn, event.nslist)
   
-  def new_desc_event(self, d):
-    self.fingerprintLookupCache = {}
-    self.fingerprintMappings = _getFingerprintMappings(self.conn)
+  def new_desc_event(self, event):
+    for fingerprint in event.idlist:
+      # clears entries with this fingerprint from the cache
+      if fingerprint in self.fingerprintLookupCache.values():
+        invalidEntries = set(k for k, v in self.fingerprintLookupCache.iteritems() if v == fingerprint)
+        for k in invalidEntries:
+          # nicknameLookupCache keys are a subset of fingerprintLookupCache
+          del self.fingerprintLookupCache[k]
+          if k in self.nicknameLookupCache.keys(): del self.nicknameLookupCache[k]
+      
+      # gets consensus data for the new description
+      nsData = self.conn.get_network_status("id/%s" % fingerprint)
+      if len(nsData) > 1:
+        # multiple records for fingerprint (shouldn't happen)
+        self.logger.monitor_event("WARN", "Multiple consensus entries for fingerprint: %s" % fingerprint)
+        return
+      nsEntry = nsData[0]
+      
+      # updates fingerprintMappings with new data
+      if nsEntry.ip in self.fingerprintMappings.keys():
+        # if entry already exists with the same orport, remove it
+        orportMatch = None
+        for entryPort, entryFingerprint in self.fingerprintMappings[nsEntry.ip]:
+          if entryPort == nsEntry.orport:
+            orportMatch = (entryPort, entryFingerprint)
+            break
+        
+        if orportMatch: self.fingerprintMappings[nsEntry.ip].remove(orportMatch)
+        
+        # add new entry
+        self.fingerprintMappings[nsEntry.ip].append((nsEntry.orport, nsEntry.idhash))
+      else:
+        self.fingerprintMappings[nsEntry.ip] = [(nsEntry.orport, nsEntry.idhash)]
   
   def reset(self):
     """
@@ -192,11 +250,16 @@
               
               dst = "%s:%s" % (hostname if hostname else entry[CONN_F_IP], entry[CONN_F_PORT])
               dst = "%-37s" % dst
-            else:
+            elif self.listingType == LIST_FINGERPRINT:
               src = "localhost  "
               if entry[CONN_TYPE] == "control": dst = "localhost"
               else: dst = self.getFingerprint(entry[CONN_F_IP], entry[CONN_F_PORT])
               dst = "%-41s" % dst
+            else:
+              src = "%-11s" % self.nickname
+              if entry[CONN_TYPE] == "control": dst = self.nickname
+              else: dst = self.getNickname(entry[CONN_F_IP], entry[CONN_F_PORT])
+              dst = "%-41s" % dst
             
             if type == "inbound": src, dst = dst, src
             self.addfstr(lineNum, 0, "<%s>%s -->   %s   (<b>%s</b>)</%s>" % (color, src, dst, type.upper(), color))
@@ -229,40 +292,26 @@
       self.fingerprintLookupCache[(ipAddr, port)] = match
       return match
   
-  def setPaused(self, isPause):
+  def getNickname(self, ipAddr, port):
     """
-    If true, prevents connection listing from being updated.
+    Attempts to provide the nickname for an ip/port combination, "UNKNOWN"
+    if this can't be determined.
     """
     
-    self.isPaused = isPause
+    if (ipAddr, port) in self.nicknameLookupCache:
+      return self.nicknameLookupCache[(ipAddr, port)]
+    else:
+      match = self.getFingerprint(ipAddr, port)
+      if match != "UNKNOWN": match = self.conn.get_network_status("id/%s" % match)[0].nickname
+      self.nicknameLookupCache[(ipAddr, port)] = match
+      return match
   
-  def getSortLabel(self, sortType, withColor = False):
+  def setPaused(self, isPause):
     """
-    Provides label associated with a type of sorting. Throws ValueEror if no such
-    sort exists. If adding color formatting this wraps with the following mappings:
-    Connection Type     red
-    [Listing] *         blue
-    Port *              green
-    Bandwidth           cyan
-    Country Code        yellow
+    If true, prevents connection listing from being updated.
     """
     
-    for (type, label, func) in SORT_TYPES:
-      if sortType == type:
-        color = None
-        
-        if withColor:
-          if label == "Connection Type": color = "red"
-          elif label.startswith("*"): color = "blue"
-          elif label.startswith("Port"): color = "green"
-          elif label == "Bandwidth": color = "cyan"
-          elif label == "Country Code": color = "yellow"
-        
-        if label.startswith("*"): label = label.replace("*", LIST_LABEL[self.listingType])
-        if color: return "<%s>%s</%s>" % (color, label, color)
-        else: return label
-    
-    raise ValueError(sortType)
+    self.isPaused = isPause
   
   def sortConnections(self):
     """
@@ -281,10 +330,13 @@
       listingWrapper = lambda ip, port: _ipToInt(ip)
     elif self.listingType == LIST_HOSTNAME:
       # alphanumeric hostnames followed by unresolved IP addresses
-      listingWrapper = lambda ip, port: self.resolver.resolve(ip).upper() if self.resolver.resolve(ip) else "ZZZZZ%099i" % _ipToInt(ip)
+      listingWrapper = lambda ip, port: self.resolver.resolve(ip).upper() if self.resolver.resolve(ip) else "zzzzz%099i" % _ipToInt(ip)
     elif self.listingType == LIST_FINGERPRINT:
       # alphanumeric fingerprints followed by UNKNOWN entries
-      listingWrapper = lambda ip, port: self.getFingerprint(ip, port) if self.getFingerprint(ip, port) != "UNKNOWN" else "ZZZZZ%099i" % _ipToInt(ip)
+      listingWrapper = lambda ip, port: self.getFingerprint(ip, port) if self.getFingerprint(ip, port) != "UNKNOWN" else "zzzzz%099i" % _ipToInt(ip)
+    elif self.listingType == LIST_NICKNAME:
+      # alphanumeric nicknames followed by Unnamed then UNKNOWN entries
+      listingWrapper = lambda ip, port: self.getNickname(ip, port) if self.getNickname(ip, port) not in ("UNKNOWN", "Unnamed") else "zzzzz%i%099i" % (0 if self.getNickname(ip, port) == "Unnamed" else 1, _ipToInt(ip))
     
     for entry in self.sortOrdering:
       if entry == ORD_FOREIGN_LISTING:
@@ -312,18 +364,16 @@
   return total
 
 # uses consensus data to map IP addresses to port / fingerprint combinations
-def _getFingerprintMappings(conn):
+def _getFingerprintMappings(conn, nsList = None):
   ipToFingerprint = {}
   
-  try:
-    lastIp, lastPort = None, None
-    for line in conn.get_info("desc/all-recent")["desc/all-recent"].split("\n"):
-      if line.startswith("router "): lastIp, lastPort = line.split()[2], line.split()[3]
-      elif line.startswith("opt fingerprint "):
-        fingerprint = "".join(line.split()[2:])
-        if lastIp in ipToFingerprint.keys(): ipToFingerprint[lastIp].append((lastPort, fingerprint))
-        else: ipToFingerprint[lastIp] = [(lastPort, fingerprint)]
-  except TorCtl.TorCtlClosed: pass
+  if not nsList:
+    try: nsList = conn.get_network_status()
+    except TorCtl.TorCtlClosed: nsList = []
   
+  for entry in nsList:
+    if entry.ip in ipToFingerprint.keys(): ipToFingerprint[entry.ip].append((entry.orport, entry.idhex))
+    else: ipToFingerprint[entry.ip] = [(entry.orport, entry.idhex)]
+  
   return ipToFingerprint
 

Modified: arm/trunk/interface/controller.py
===================================================================
--- arm/trunk/interface/controller.py	2009-07-18 06:07:13 UTC (rev 20077)
+++ arm/trunk/interface/controller.py	2009-07-18 07:16:16 UTC (rev 20078)
@@ -35,6 +35,9 @@
 PAGE_COUNT = 3 # all page numbering is internally represented as 0-indexed
 # TODO: page for configuration information
 
+# events needed for panels other than the event log
+REQ_EVENTS = ["BW", "NEWDESC", "NEWCONSENSUS"]
+
 class ControlPanel(util.Panel):
   """ Draws single line label for interface controls. """
   
@@ -98,7 +101,7 @@
     try:
       # adds BW events if not already included (so bandwidth monitor will work)
       # removes UNKNOWN since not an actual event type
-      connEvents = loggedEvents.union(set(["BW"]))
+      connEvents = loggedEvents.union(set(REQ_EVENTS))
       connEvents.discard("UNKNOWN")
       conn.set_events(connEvents)
       eventsSet = True
@@ -255,11 +258,7 @@
           popup.addstr(2, 2, "page up: scroll up a page")
           popup.addstr(2, 41, "page down: scroll down a page")
           
-          listingEnum = panels["conn"].listingType
-          if listingEnum == connPanel.LIST_IP: listingType = "ip address"
-          elif listingEnum == connPanel.LIST_HOSTNAME: listingType = "hostname"
-          else: listingType = "fingerprint"
-          
+          listingType = connPanel.LIST_LABEL[panels["conn"].listingType].lower()
           popup.addfstr(3, 2, "l: listed identity (<b>%s</b>)" % listingType)
           
           allowDnsLabel = "allow" if panels["conn"].allowDNS else "disallow"
@@ -277,8 +276,6 @@
           
           lineNumLabel = "on" if panels["torrc"].showLineNum else "off"
           popup.addfstr(3, 41, "n: line numbering (<b>%s</b>)" % lineNumLabel)
-          
-          popup.addfstr(4, 2, "r: reload torrc")
         
         popup.addstr(7, 2, "Press any key...")
         
@@ -316,7 +313,7 @@
         popup.addstr(0, 0, "Event Types:", util.LABEL_ATTR)
         lineNum = 1
         for line in logPanel.EVENT_LISTING.split("\n"):
-          line = "  " + line.strip()
+          line = line[6:]
           popup.addstr(lineNum, 0, line)
           lineNum += 1
         popup.refresh()
@@ -348,7 +345,7 @@
         cursesLock.release()
     elif (page == 1 and (key == ord('l') or key == ord('L'))) or (key == 27 and panels["conn"].listingType == connPanel.LIST_HOSTNAME and panels["control"].resolvingCounter != -1):
       # either pressed 'l' on connection listing or canceling hostname resolution (esc on any page)
-      panels["conn"].listingType = (panels["conn"].listingType + 1) % 3
+      panels["conn"].listingType = (panels["conn"].listingType + 1) % len(connPanel.LIST_LABEL)
       
       if panels["conn"].listingType == connPanel.LIST_HOSTNAME:
         curses.halfdelay(10) # refreshes display every second until done resolving
@@ -376,18 +373,12 @@
         
         # listing of inital ordering
         prevOrdering = "<b>Current Order: "
-        for sort in panels["conn"].sortOrdering: prevOrdering += panels["conn"].getSortLabel(sort, True) + ", "
+        for sort in panels["conn"].sortOrdering: prevOrdering += connPanel.getSortLabel(sort, True) + ", "
         prevOrdering = prevOrdering[:-2] + "</b>"
         
         # Makes listing of all options
         options = []
-        for (type, label, func) in connPanel.SORT_TYPES:
-          label = panels["conn"].getSortLabel(type)
-          
-          # replaces 'Fingerprint' listings with shorter description
-          if label.startswith("Fingerprint"): label = label.replace("Fingerprint", "Tor ID")
-          
-          options.append(label)
+        for (type, label, func) in connPanel.SORT_TYPES: options.append(connPanel.getSortLabel(type))
         options.append("Cancel")
         
         while len(selections) < 3:
@@ -399,7 +390,7 @@
           # provides new ordering
           newOrdering = "<b>New Order: "
           if selections:
-            for sort in selections: newOrdering += panels["conn"].getSortLabel(sort, True) + ", "
+            for sort in selections: newOrdering += connPanel.getSortLabel(sort, True) + ", "
             newOrdering = newOrdering[:-2] + "</b>"
           else: newOrdering += "</b>"
           popup.addfstr(2, 2, newOrdering)

Modified: arm/trunk/interface/headerPanel.py
===================================================================
--- arm/trunk/interface/headerPanel.py	2009-07-18 06:07:13 UTC (rev 20077)
+++ arm/trunk/interface/headerPanel.py	2009-07-18 07:16:16 UTC (rev 20078)
@@ -9,6 +9,11 @@
 
 import util
 
+FLAG_COLORS = {"Authority": "white",  "BadExit": "red",     "BadDirectory": "red",    "Exit": "cyan",
+               "Fast": "yellow",      "Guard": "green",     "HSDir": "magenta",       "Named": "blue",
+               "Stable": "blue",      "Running": "yellow",  "Unnamed": "magenta",     "Valid": "green",
+               "V2Dir": "cyan",       "V3Dir": "white"}
+
 class HeaderPanel(util.Panel):
   """
   Draws top area containing static information.
@@ -26,7 +31,7 @@
   """
   
   def __init__(self, lock, conn):
-    util.Panel.__init__(self, lock, 5)
+    util.Panel.__init__(self, lock, 6)
     self.vals = []            # mapping of information to be presented
     self.conn = conn          # Tor control port connection
     self.isPaused = False
@@ -69,17 +74,15 @@
       # Line 4 (fingerprint)
       self.addstr(3, 0, "fingerprint: %s" % self.vals["fingerprint"])
       
+      # Line 5 (flags)
+      flagLine = "flags: "
+      for flag in self.vals["flags"]:
+        flagColor = FLAG_COLORS[flag] if flag in FLAG_COLORS.keys() else "white"
+        flagLine += "<b><%s>%s</%s></b>, " % (flagColor, flag, flagColor)
       
-      # Lines 3-5
-      #self.addstr(3, 0, "Config: %s" % self.vals["config-file"])
-      #exitPolicy = self.vals["ExitPolicy"]
+      if len(self.vals["flags"]) > 0: flagLine = flagLine[:-2]
+      self.addfstr(4, 0, flagLine)
       
-      # adds note when default exit policy is appended
-      #if exitPolicy == None: exitPolicy = "<default>"
-      #elif not exitPolicy.endswith("accept *:*") and not exitPolicy.endswith("reject *:*"):
-      #  exitPolicy += ", <default>"
-      #self.addstr(4, 0, "Exit Policy: %s" % exitPolicy)
-      
       self.refresh()
   
   def setPaused(self, isPause):
@@ -93,10 +96,10 @@
     """
     Updates mapping of static Tor settings and system information to their
     corresponding string values. Keys include:
-    info - version, config-file, *address, *fingerprint
+    info - version, *address, *fingerprint, *flags
     sys - sys-name, sys-os, sys-version
     ps - *%cpu, *rss, *%mem, *pid, *etime
-    config - Nickname, ORPort, DirPort, ControlPort, ExitPolicy
+    config - Nickname, ORPort, DirPort, ControlPort
     config booleans - IsPasswordAuthSet, IsCookieAuthSet, IsAccountingEnabled
     
     * volatile parameter that'll be reset (otherwise won't be checked if
@@ -114,7 +117,7 @@
       self.vals["sys-version"] = unameVals[2]
       
       # parameters from the user's torrc
-      configFields = ["Nickname", "ORPort", "DirPort", "ControlPort", "ExitPolicy"]
+      configFields = ["Nickname", "ORPort", "DirPort", "ControlPort"]
       self.vals.update(dict([(key, self.conn.get_option(key)[0][1]) for key in configFields]))
       
       # simply keeps booleans for if authentication info is set
@@ -134,6 +137,13 @@
         # Can be caused if tor crashed
         if not self.vals[param]: self.vals[param] = "Unknown"
     
+    # flags held by relay
+    self.vals["flags"] = []
+    if self.vals["fingerprint"] != "Unknown":
+      try: self.vals["flags"] = self.conn.get_network_status("id/%s" % self.vals["fingerprint"])[0].flags
+      except TorCtl.TorCtlClosed: pass
+      except socket.error: pass
+    
     # ps call provides header followed by params for tor
     psParams = ["%cpu", "rss", "%mem", "pid", "etime"]
     psCall = os.popen('ps -C %s -o %s' % ("tor", ",".join(psParams)))

Modified: arm/trunk/interface/logPanel.py
===================================================================
--- arm/trunk/interface/logPanel.py	2009-07-18 06:07:13 UTC (rev 20077)
+++ arm/trunk/interface/logPanel.py	2009-07-18 07:16:16 UTC (rev 20078)
@@ -13,18 +13,21 @@
 RUNLEVEL_EVENT_COLOR = {"DEBUG": "magenta", "INFO": "blue", "NOTICE": "green", "WARN": "yellow", "ERR": "red"}
 
 EVENT_TYPES = {
-  "d": "DEBUG",   "a": "ADDRMAP",     "l": "NEWDESC",   "u": "AUTHDIR_NEWDESCS",
-  "i": "INFO",    "b": "BW",          "m": "NS",        "v": "CLIENTS_SEEN",
-  "n": "NOTICE",  "c": "CIRC",        "o": "ORCONN",    "x": "STATUS_GENERAL",
-  "w": "WARN",    "f": "DESCCHANGED", "s": "STREAM",    "y": "STATUS_CLIENT",
-  "e": "ERR",     "g": "GUARD",       "t": "STREAM_BW", "z": "STATUS_SERVER"}
+  "d": "DEBUG",   "a": "ADDRMAP",       "l": "NEWDESC",     "v": "AUTHDIR_NEWDESCS",
+  "i": "INFO",    "b": "BW",            "m": "NS",          "x": "STATUS_GENERAL",
+  "n": "NOTICE",  "c": "CIRC",          "o": "ORCONN",      "y": "STATUS_CLIENT",
+  "w": "WARN",    "f": "DESCCHANGED",   "s": "STREAM",      "z": "STATUS_SERVER",
+  "e": "ERR",     "g": "GUARD",         "t": "STREAM_BW",
+                  "k": "NEWCONSENSUS",  "u": "CLIENTS_SEEN"}
 
-EVENT_LISTING = """        d DEBUG     a ADDRMAP       l NEWDESC         u AUTHDIR_NEWDESCS
-        i INFO      b BW            m NS              v CLIENTS_SEEN
-        n NOTICE    c CIRC          o ORCONN          x STATUS_GENERAL
-        w WARN      f DESCCHANGED   s STREAM          y STATUS_CLIENT
-        e ERR       g GUARD         t STREAM_BW       z STATUS_SERVER
-        Aliases:    A All Events    U Unknown Events  R Runlevels (dinwe)"""
+EVENT_LISTING = """        d DEBUG     a ADDRMAP         l NEWDESC         v AUTHDIR_NEWDESCS
+        i INFO      b BW              m NS              x STATUS_GENERAL
+        n NOTICE    c CIRC            o ORCONN          y STATUS_CLIENT
+        w WARN      f DESCCHANGED     s STREAM          z STATUS_SERVER
+        e ERR       g GUARD           t STREAM_BW
+                    k NEWCONSENSUS    u CLIENTS_SEEN
+        Aliases:    A All Events      X No Events       U Unknown Events
+                    DINWE Runlevel and higher severity"""
   
 def expandEvents(eventAbbr):
   """
@@ -46,10 +49,15 @@
       expandedEvents = set(EVENT_TYPES.values())
       expandedEvents.add("UNKNOWN")
       break
-    elif flag == "U":
-      expandedEvents.add("UNKNOWN")
-    elif flag == "R":
-      expandedEvents = expandedEvents.union(set(["DEBUG", "INFO", "NOTICE", "WARN", "ERR"]))
+    elif flag == "X":
+      expandedEvents = set()
+      break
+    elif flag == "U": expandedEvents.add("UNKNOWN")
+    elif flag == "D": expandedEvents = expandedEvents.union(set(["DEBUG", "INFO", "NOTICE", "WARN", "ERR"]))
+    elif flag == "I": expandedEvents = expandedEvents.union(set(["INFO", "NOTICE", "WARN", "ERR"]))
+    elif flag == "N": expandedEvents = expandedEvents.union(set(["NOTICE", "WARN", "ERR"]))
+    elif flag == "W": expandedEvents = expandedEvents.union(set(["WARN", "ERR"]))
+    elif flag == "E": expandedEvents.add("ERR")
     elif flag in EVENT_TYPES:
       expandedEvents.add(EVENT_TYPES[flag])
     else:
@@ -70,7 +78,7 @@
     self.isPaused = False
     self.pauseBuffer = []                 # location where messages are buffered if paused
     self.loggedEvents = loggedEvents      # events we're listening to
-    self.lastHeartbeat = time.time()      # time of last BW event
+    self.lastHeartbeat = time.time()      # time of last event
   
   # Listens for all event types and redirects to registerEvent
   def circ_status_event(self, event):
@@ -104,15 +112,16 @@
       self.registerEvent("STREAM_BW", "DEBUG -> ID: %s READ: %s WRITTEN: %s" % (type(event.strm_id), type(event.bytes_read), type(event.bytes_written)), "white")
   
   def bandwidth_event(self, event):
-    self.lastHeartbeat = time.time()
+    self.lastHeartbeat = time.time() # ensures heartbeat at least once a second
     if "BW" in self.loggedEvents: self.registerEvent("BW", "READ: %i, WRITTEN: %i" % (event.read, event.written), "cyan")
   
   def msg_event(self, event):
     self.registerEvent(event.level, event.msg, RUNLEVEL_EVENT_COLOR[event.level])
   
   def new_desc_event(self, event):
-    idlistStr = [str(item) for item in event.idlist]
-    self.registerEvent("NEWDESC", ", ".join(idlistStr), "white")
+    if "NEWDESC" in self.loggedEvents:
+      idlistStr = [str(item) for item in event.idlist]
+      self.registerEvent("NEWDESC", ", ".join(idlistStr), "white")
   
   def address_mapped_event(self, event):
     self.registerEvent("ADDRMAP", "%s, %s -> %s" % (event.when, event.from_addr, event.to_addr), "white")
@@ -126,10 +135,11 @@
     self.registerEvent("NS", "Listed (%i): %s" % (len(event.nslist), msg), "blue")
   
   def new_consensus_event(self, event):
-    msg = ""
-    for ns in event.nslist:
-      msg += ", %s (%s:%i)" % (ns.nickname, ns.ip, ns.orport)
-    self.registerEvent("NEWCONSENSUS", "Listed (%i): %s" % (len(event.nslist), msg), "magenta")
+    if "NEWCONSENSUS" in self.loggedEvents:
+      msg = ""
+      for ns in event.nslist:
+        msg += ", %s (%s:%i)" % (ns.nickname, ns.ip, ns.orport)
+      self.registerEvent("NEWCONSENSUS", "Listed (%i): %s" % (len(event.nslist), msg), "magenta")
   
   def unknown_event(self, event):
     if "UNKNOWN" in self.loggedEvents: self.registerEvent("UNKNOWN", event.event_string, "red")
@@ -143,6 +153,8 @@
     Notes event and redraws log. If paused it's held in a temporary buffer.
     """
     
+    self.lastHeartbeat = time.time()
+    
     # strips control characters to avoid screwing up the terminal
     msg = "".join([char for char in msg if isprint(char)])
     
@@ -222,7 +234,9 @@
   
   def getHeartbeat(self):
     """
-    Provides the number of seconds since the last BW event.
+    Provides the number of seconds since the last registered event (this always
+    listens to BW events so should be less than a second if relay's still
+    responsive).
     """
     
     return time.time() - self.lastHeartbeat



More information about the tor-commits mailing list