commit aba3b74ea029d5732af34192c55df101cf465fbf Author: Damian Johnson atagar@torproject.org Date: Thu Jul 30 08:56:09 2015 -0700
Differentiate between unknown and resolving apps
Be a bit smarter about showing 'resolving...' when an application can't be determined and 'UNKNOWN' if it can't be determined. --- nyx/connections/conn_entry.py | 26 +++++++------------------ nyx/connections/conn_panel.py | 10 +++++----- nyx/util/tracker.py | 32 ++++++++++++++++++++++++++++--- test/util/tracker/port_usage_tracker.py | 6 +++--- 4 files changed, 44 insertions(+), 30 deletions(-)
diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py index fe18485..1eae80f 100644 --- a/nyx/connections/conn_entry.py +++ b/nyx/connections/conn_entry.py @@ -145,16 +145,6 @@ 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 @@ -350,17 +340,15 @@ class ConnectionLine(entries.ConnectionPanelLine): # for applications show the command/pid
if self.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL): - display_label = '' - process = self.get_process() + port = self.connection.local_port if self.get_type() == Category.HIDDEN else self.connection.remote_port
- if process: - if process.pid: - display_label = '%s (%s)' % (process.name, process.pid) - else: - display_label = process.name - else: - # TODO: We should differentiate between 'resolving...' and 'unknown' + try: + process = nyx.util.tracker.get_port_usage_tracker().fetch(port) + display_label = '%s (%s)' % (process.name, process.pid) if process.pid else process.name + except nyx.util.tracker.UnresolvedResult: display_label = 'resolving...' + except nyx.util.tracker.UnknownApplication: + display_label = 'UNKNOWN'
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 b8f97ad..629a559 100644 --- a/nyx/connections/conn_panel.py +++ b/nyx/connections/conn_panel.py @@ -495,12 +495,12 @@ class ConnectionPanel(panel.Panel, threading.Thread): self._last_resource_fetch = current_resolution_count
if CONFIG['features.connection.resolveApps']: - local_ports, remote_ports = [] + local_ports, remote_ports = [], []
for line in self._entry_lines: - if line.get_type() == conn_entry.Category.HIDDEN: - local_ports.append(line.connection.local_port) - elif line.get_type() in (conn_entry.Category.SOCKS, conn_entry.Category.CONTROL): - remote_ports.append(line.connection.remote_port) + if line.get_type() in (conn_entry.Category.SOCKS, conn_entry.Category.CONTROL): + local_ports.append(line.connection.remote_port) + elif line.get_type() == conn_entry.Category.HIDDEN: + remote_ports.append(line.connection.local_port)
nyx.util.tracker.get_port_usage_tracker().query(local_ports, remote_ports) diff --git a/nyx/util/tracker.py b/nyx/util/tracker.py index 57562f5..88a53c3 100644 --- a/nyx/util/tracker.py +++ b/nyx/util/tracker.py @@ -91,6 +91,14 @@ Process = collections.namedtuple('Process', [ ])
+class UnresolvedResult(Exception): + 'Indicates the application being used by a port is still being determined.' + + +class UnknownApplication(Exception): + 'No application could be determined for this port.' + + def get_connection_tracker(): """ Singleton for tracking the connections established by tor. @@ -253,7 +261,8 @@ def _process_for_ports(local_ports, remote_ports): :param list local_ports: local port numbers to look up :param list remote_ports: remote port numbers to look up
- :returns: **dict** mapping the ports to the associated **Process** + :returns: **dict** mapping the ports to the associated **Process**, or + **None** if it can't be determined
:raises: **IOError** if unsuccessful """ @@ -322,6 +331,9 @@ def _process_for_ports(local_ports, remote_ports): except ValueError as exc: raise IOError('unrecognized output from lsof (%s): %s' % (exc, line))
+ for unknown_port in set(local_ports).union(remote_ports).difference(results.keys()): + results[unknown_port] = None + return results
raise IOError('no results from lsof') @@ -679,10 +691,24 @@ class PortUsageTracker(Daemon):
:param int port: port number to look up
- :returns: **Process** using the given port, or **None** if it's unavailable + :returns: **Process** using the given port + + :raises: + * :class:`nyx.util.tracker.UnresolvedResult` if the application is still + being determined + * :class:`nyx.util.tracker.UnknownApplication` if the we tried to resolve + the application but it couldn't be determined """
- return self._processes_for_ports.get(port) + try: + result = self._processes_for_ports[port] + + if result is None: + raise UnknownApplication() + else: + return result + except KeyError: + raise UnresolvedResult()
def query(self, local_ports, remote_ports): """ diff --git a/test/util/tracker/port_usage_tracker.py b/test/util/tracker/port_usage_tracker.py index 64c4c09..31bdd4c 100644 --- a/test/util/tracker/port_usage_tracker.py +++ b/test/util/tracker/port_usage_tracker.py @@ -47,8 +47,8 @@ class TestPortUsageTracker(unittest.TestCase): @patch('nyx.util.tracker.system.call', Mock(return_value = LSOF_OUTPUT.split('\n'))) def test_process_for_ports(self): self.assertEqual({}, _process_for_ports([], [])) - self.assertEqual({}, _process_for_ports([80, 443], [])) - self.assertEqual({}, _process_for_ports([], [80, 443])) + self.assertEqual({80: None, 443: None}, _process_for_ports([80, 443], [])) + self.assertEqual({80: None, 443: None}, _process_for_ports([], [80, 443]))
self.assertEqual({37277: Process(2462, 'python'), 51849: Process(2001, 'tor')}, _process_for_ports([37277], [51849]))
@@ -63,7 +63,7 @@ class TestPortUsageTracker(unittest.TestCase):
for test_input in test_inputs: call_mock.return_value = test_input.split('\n') - self.assertEqual({}, _process_for_ports([80], [443])) + self.assertEqual({80: None, 443: None}, _process_for_ports([80], [443]))
# Isuses that are reported as errors.