[tor-commits] [nyx/master] Move application resolution into the lines

atagar at torproject.org atagar at torproject.org
Tue Sep 22 17:08:40 UTC 2015


commit eb37d9008ec6cd460ddf352b98ed1fa14f454125
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed Jul 29 10:17:20 2015 -0700

    Move application resolution into the lines
    
    Our panel resolved applications, then populated attributes on the lines. Ewww!
    
    The tracker caches results so the lines can just retrieve values from that
    on-demand. While doing this realized past changs made it so we can't
    differentiate between 'unknown' and 'still resolving', so should fix that next.
---
 nyx/connections/conn_entry.py           |   37 ++++++++++++-------------
 nyx/connections/conn_panel.py           |   45 ++++---------------------------
 nyx/util/tracker.py                     |   15 ++++++++++-
 test/util/tracker/port_usage_tracker.py |    6 ++---
 4 files changed, 39 insertions(+), 64 deletions(-)

diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py
index d945182..fe18485 100644
--- a/nyx/connections/conn_entry.py
+++ b/nyx/connections/conn_entry.py
@@ -77,12 +77,6 @@ class ConnectionLine(entries.ConnectionPanelLine):
     self._possible_client = True
     self._possible_directory = True
 
-    # attributes for SOCKS, HIDDEN, and CONTROL connections
-
-    self.application_name = None
-    self.application_pid = None
-    self.is_application_resolving = False
-
     socks_ports = controller.get_ports(Listener.SOCKS, [])
     or_ports = controller.get_ports(Listener.OR, [])
     dir_ports = controller.get_ports(Listener.DIR, [])
@@ -151,6 +145,16 @@ class ConnectionLine(entries.ConnectionPanelLine):
     nickname = nyx.util.tracker.get_consensus_tracker().get_relay_nickname(self.get_fingerprint())
     return nickname if nickname else default
 
+  def get_process(self):
+    """
+    Local process using this connection. This is only available for socks,
+    hidden service, and controller connections. This is **None** if the
+    application is either still being resolved or can't be determined.
+    """
+
+    port = self.connection.local_port if self.get_type() == Category.HIDDEN else self.connection.remote_port
+    return nyx.util.tracker.get_port_usage_tracker().fetch(port)
+
   def get_listing_entry(self, width, current_time, listing_type):
     """
     Provides the tuple list for this connection's listing. Lines are composed
@@ -195,13 +199,6 @@ class ConnectionLine(entries.ConnectionPanelLine):
 
     return my_listing
 
-  def is_unresolved_application(self):
-    """
-    True if our display uses application information that hasn't yet been resolved.
-    """
-
-    return self.application_name is None and self.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL)
-
   def _get_listing_entry(self, width, current_time, listing_type):
     entry_type = self.get_type()
 
@@ -354,16 +351,16 @@ class ConnectionLine(entries.ConnectionPanelLine):
 
     if self.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
       display_label = ''
+      process = self.get_process()
 
-      if self.application_name:
-        if self.application_pid:
-          display_label = '%s (%s)' % (self.application_name, self.application_pid)
+      if process:
+        if process.pid:
+          display_label = '%s (%s)' % (process.name, process.pid)
         else:
-          display_label = self.application_name
-      elif self.is_application_resolving:
-        display_label = 'resolving...'
+          display_label = process.name
       else:
-        display_label = 'UNKNOWN'
+        # TODO: We should differentiate between 'resolving...' and 'unknown'
+        display_label = 'resolving...'
 
       if len(display_label) < width:
         return ('%%-%is' % width) % display_label
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index e40a431..5163ec9 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -13,7 +13,7 @@ import nyx.popups
 import nyx.util.tracker
 
 from nyx.connections import descriptor_popup, entries, conn_entry
-from nyx.util import panel, tor_controller, tracker, ui_tools
+from nyx.util import panel, tor_controller, ui_tools
 
 from stem.control import State
 from stem.util import conf, connection, enum
@@ -115,10 +115,6 @@ class ConnectionPanel(panel.Panel, threading.Thread):
 
     self._last_resource_fetch = -1
 
-    # resolver for the command/pid associated with SOCKS, HIDDEN, and CONTROL connections
-
-    self._app_resolver = tracker.get_port_usage_tracker()
-
     # mark the initially exitsing connection uptimes as being estimates
 
     for entry in self._entries:
@@ -509,41 +505,10 @@ class ConnectionPanel(panel.Panel, threading.Thread):
     if not CONFIG['features.connection.resolveApps']:
       return
 
-    unresolved_lines = [l for l in self._entry_lines if isinstance(l, conn_entry.ConnectionLine) and l.is_unresolved_application()]
-
-    # get the ports used for unresolved applications
-
     app_ports = []
 
-    for line in unresolved_lines:
-      app_ports.append(line.connection.local_port if line.get_type() == conn_entry.Category.HIDDEN else line.connection.remote_port)
-
-    # Queue up resolution for the unresolved ports (skips if it's still working
-    # on the last query).
-
-    if app_ports and not self._app_resolver.is_alive():
-      self._app_resolver.get_processes_using_ports(app_ports)
+    for line in self._entry_lines:
+      if line.get_type() in (conn_entry.Category.SOCKS, conn_entry.Category.HIDDEN, conn_entry.Category.CONTROL):
+        app_ports.append(line.connection.local_port if line.get_type() == conn_entry.Category.HIDDEN else line.connection.remote_port)
 
-    # Fetches results. If the query finishes quickly then this is what we just
-    # asked for, otherwise these belong to an earlier resolution.
-    #
-    # The application resolver might have given up querying (for instance, if
-    # the lsof lookups aren't working on this platform or lacks permissions).
-    # The is_application_resolving flag lets the unresolved entries indicate if there's
-    # a lookup in progress for them or not.
-
-    time.sleep(0.2)  # TODO: previous resolver only blocked while awaiting a lookup
-    app_results = self._app_resolver.get_processes_using_ports(app_ports)
-
-    for line in unresolved_lines:
-      is_local = line.get_type() == conn_entry.Category.HIDDEN
-      line_port = line.connection.local_port if is_local else line.connection.remote_port
-
-      if line_port in app_results:
-        result = app_results[line_port]
-
-        line.application_name = result.name
-        line.application_pid = result.pid
-        line.is_application_resolving = False
-      else:
-        line.is_application_resolving = self._app_resolver.is_alive
+    nyx.util.tracker.get_port_usage_tracker().query(app_ports)
diff --git a/nyx/util/tracker.py b/nyx/util/tracker.py
index f6219ad..5d9c81e 100644
--- a/nyx/util/tracker.py
+++ b/nyx/util/tracker.py
@@ -670,7 +670,20 @@ class PortUsageTracker(Daemon):
     self._processes_for_ports = {}
     self._failure_count = 0  # number of times in a row we've failed to get results
 
-  def get_processes_using_ports(self, ports):
+  def fetch(self, port):
+    """
+    Provides the process running on the given port. This retrieves the results
+    from our cache, so it only works if we've already issued a query() request
+    for it and gotten results.
+
+    :param int port: port number to look up
+
+    :returns: **Process** using the given port, or **None** if it's unavailable
+    """
+
+    return self._processes_for_ports.get(port)
+
+  def query(self, ports):
     """
     Registers a given set of ports for further lookups, and returns the last
     set of 'port => process' mappings we retrieved. Note that this means that
diff --git a/test/util/tracker/port_usage_tracker.py b/test/util/tracker/port_usage_tracker.py
index 8528e69..41d88d0 100644
--- a/test/util/tracker/port_usage_tracker.py
+++ b/test/util/tracker/port_usage_tracker.py
@@ -91,10 +91,10 @@ class TestPortUsageTracker(unittest.TestCase):
     with PortUsageTracker(0.02) as daemon:
       time.sleep(0.01)
 
-      self.assertEqual({}, daemon.get_processes_using_ports([37277, 51849]))
+      self.assertEqual({}, daemon.query([37277, 51849]))
       time.sleep(0.04)
 
-      self.assertEqual({37277: 'python', 51849: 'tor'}, daemon.get_processes_using_ports([37277, 51849]))
+      self.assertEqual({37277: 'python', 51849: 'tor'}, daemon.query([37277, 51849]))
 
   @patch('nyx.util.tracker.tor_controller')
   @patch('nyx.util.tracker._process_for_ports')
@@ -110,7 +110,7 @@ class TestPortUsageTracker(unittest.TestCase):
       time.sleep(0.05)
       self.assertEqual(0, daemon._failure_count)
 
-      daemon.get_processes_using_ports([37277, 51849])
+      daemon.query([37277, 51849])
       time.sleep(0.03)
       self.assertTrue(daemon.is_alive())
       time.sleep(0.1)





More information about the tor-commits mailing list