[Pkg-privacy-commits] [pyptlib] 49/136: Improve the code a bit.

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 13:25:06 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository pyptlib.

commit fcb2f4be8e18787738ecf359f04ae9ba49c09d9d
Author: George Kadianakis <desnacked at riseup.net>
Date:   Tue Sep 18 18:16:18 2012 +0300

    Improve the code a bit.
    
    * Make better use of exceptions instead of relying on retvals.
    * If Tor asks us for a transport we don't support, we now send back an
      {S,C}METHOD-ERROR.
---
 pyptlib/client.py        | 49 +++++++++++++++---------------
 pyptlib/client_config.py | 42 ++++++++++++-------------
 pyptlib/config.py        | 48 ++++++++++++-----------------
 pyptlib/server.py        | 52 +++++++++++++++++++------------
 pyptlib/server_config.py | 79 +++++++++++++++++++++++++++++++-----------------
 5 files changed, 149 insertions(+), 121 deletions(-)

diff --git a/pyptlib/client.py b/pyptlib/client.py
index 9486190..eccea49 100644
--- a/pyptlib/client.py
+++ b/pyptlib/client.py
@@ -1,13 +1,15 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-""" The pyptlib.easy.client module includes a convenient API for writing pluggable transport clients. """
+"""
+This module provides a convenient API for writing pluggable transport clients.
+"""
 
 from pyptlib.config import EnvException
 from pyptlib.client_config import ClientConfig
 
 
-def init(transports):
+def init(supported_transports):
     """
     Initialize the pluggable transport by parsing the environment
     variables and generating output to report any errors.  The given
@@ -20,45 +22,44 @@ def init(transports):
     'state_loc' : Directory where the managed proxy should dump its
     state files (if needed).
 
-    'transports' : The names of the transports that must be launched.
+    'transports' : The names of the transports that must be
+    launched. The list can be empty.
 
-    Returns None if something went wrong.
+    Throws EnvException.
     """
 
     supportedTransportVersion = '1'
 
-    try:
-        config = ClientConfig()
-    except EnvException:
-        return None
+    config = ClientConfig()
 
     if config.checkManagedTransportVersion(supportedTransportVersion):
         config.writeVersion(supportedTransportVersion)
     else:
         config.writeVersionError()
-        return None
-
-    matchedTransports = []
-    for transport in transports:
-        if config.checkTransportEnabled(transport):
-            matchedTransports.append(transport)
-
-    # XXX the XXXs from server.py are valid here too.
+        raise EnvException("Unsupported managed proxy protocol version (%s)" %
+                           str(config.getManagedTransportVersions()))
 
     retval = {}
     retval['state_loc'] = config.getStateLocation()
-    retval['transports'] = matchedTransports
+    retval['transports'] = getTransportsList(supported_transports, config)
 
     return retval
 
+def getTransportsList(supported_transports, config):
+    transports = []
+
+    if config.getAllTransportsEnabled():
+        return supported_transports
+
+    for transport in config.getClientTransports():
+        if transport in supported_transports:
+            transports.append(transport)
+        else:
+            config.writeMethodError(transport, "not supported")
+
+    return transports
 
-def reportSuccess(
-    name,
-    socksVersion,
-    address,
-    args,
-    optArgs,
-    ):
+def reportSuccess(name, socksVersion, address, args, optArgs):
     """
         This method should be called to report when a transport has been successfully launched.
         It generates output to Tor informing that the transport launched successfully and can be used.
diff --git a/pyptlib/client_config.py b/pyptlib/client_config.py
index 31cdaf5..4acc6f7 100644
--- a/pyptlib/client_config.py
+++ b/pyptlib/client_config.py
@@ -2,53 +2,50 @@
 # -*- coding: utf-8 -*-
 
 """
-    The pyptlib.client module contains a low-level API which closely follows the Tor Proposal 180: Pluggable transports for circumvention.
-    This module inherits from pyptlib.config and contains just the parts of the API which are specific to the client implementations of the protocol.
+This module inherits from pyptlib.config and contains just the parts
+of the API which are specific to the client implementations of the
+protocol.
 """
 
-import os
-
 from pyptlib.config import Config
 
 __docformat__ = 'restructuredtext'
 
 
 class ClientConfig(Config):
-
     """
-    The ClientConfig class contains a low-level API which closely follows the Tor Proposal 180: Pluggable transports for circumvention.
-    This class inherits from pyptlib.config.Config and contains just the parts of the API which are specific to the client implementations of the protocol.
+    This class inherits from pyptlib.config.Config and contains just
+    the parts of the API which are specific to the client
+    implementations of the protocol.
     """
 
   # Public methods
 
-    def __init__(self):  # throws EnvError
+    def __init__(self):
         """
         Initialize the ClientConfig object.
         This causes the state location, managed transport, and transports version to be set.
+
+        Throws EnvException.
         """
 
         Config.__init__(self)
 
-        self.transports = self.get('TOR_PT_CLIENT_TRANSPORTS').split(','
-                )
+        self.transports = self.get('TOR_PT_CLIENT_TRANSPORTS').split(',')
         if '*' in self.transports:
             self.allTransportsEnabled = True
             self.transports.remove('*')
 
-    def getClientTransports(self):
-        """ Returns a list of strings representing the client transports reported by Tor. If present, '*' is stripped from this list and used to set allTransportsEnabled to True. """
+    def getClientTransports(self): # XXX why is this client-specific ???
+        """
+        Returns a list of strings representing the client transports
+        reported by Tor. If present, '*' is stripped from this list
+        and used to set allTransportsEnabled to True.
+        """
 
         return self.transports
 
-    def writeMethod(  # CMETHOD
-        self,
-        name,
-        socksVersion,
-        address,
-        args,
-        optArgs,
-        ):
+    def writeMethod(self, name, socksVersion, address, args, optArgs):
         """
         Write a message to stdout specifying a supported transport
         Takes: str, int, (str, int), [str], [str]
@@ -71,7 +68,10 @@ class ClientConfig(Config):
         self.emit('CMETHOD-ERROR %s %s' % (name, message))
 
     def writeMethodEnd(self):  # CMETHODS DONE
-        """ Write a message to stdout specifying that the list of supported transports has ended """
+        """
+        Write a message to stdout specifying that the list of
+        supported transports has ended.
+        """
 
         self.emit('CMETHODS DONE')
 
diff --git a/pyptlib/config.py b/pyptlib/config.py
index 5889b70..b6d4e77 100644
--- a/pyptlib/config.py
+++ b/pyptlib/config.py
@@ -2,24 +2,14 @@
 # -*- coding: utf-8 -*-
 
 """
-    The pyptlib.config module contains a low-level API which closely follows the Tor Proposal 180: Pluggable transports for circumvention.
-    This module contains the parts of the API which are shared by both client and server implementations of the protocol.
+This module contains parts of the managed proxy specification which
+are shared by both client and server implementations of the protocol.
 """
 
 import os, sys
 
 __docformat__ = 'restructuredtext'
 
-"""Receive "<addr>:<port>" in 'string', and return [<addr>,<port>]."""
-def parse_addrport(string):
-    addrport = string.split(':')
-
-    if (len(addrport) != 2):
-        return None
-    addrport[1] = int(addrport[1]) # XXX lame integer check
-
-    return addrport
-
 class Config:
 
     """
@@ -34,12 +24,16 @@ class Config:
 
   # Public methods
 
-    def __init__(self):  # throws EnvError
-        """ Initialize the Config object. this causes the state location and managed transport version to be set. """
+    def __init__(self):
+        """
+        Initialize the Config object. this causes the state location
+        and managed transport version to be set.
+
+        Throws EnvException.
+        """
 
         self.stateLocation = self.get('TOR_PT_STATE_LOCATION')
-        self.managedTransportVer = \
-            self.get('TOR_PT_MANAGED_TRANSPORT_VER').split(',')
+        self.managedTransportVer = self.get('TOR_PT_MANAGED_TRANSPORT_VER').split(',')
 
     def checkClientMode(self):
         """ Check to see if the daemon is being run as a client or a server. This is determined by looking for the presence of the TOR_PT_CLIENT_TRANSPORTS environment variable. """
@@ -105,7 +99,11 @@ class Config:
         return key in os.environ
 
     def get(self, key):
-        """ Attempts to fetch the given key from the environment variables. If it is present, it is returned, otherwise an EnvException is thrown. """
+        """
+        Attempts to fetch the given key from the environment
+        variables. If it is present, it is returned, otherwise an
+        EnvException is thrown.
+        """
 
         if key in os.environ:
             return os.environ[key]
@@ -118,15 +116,9 @@ class Config:
         print msg
         sys.stdout.flush()
 
-# Exception thrown when there is an error parsing the configuration parameters provided by Tor in environment variables
-
-class EnvException(Exception):
-
-    """ The EnvException exception is thrown whenever a required environment variable is not presented or cannot be parsed. """
-
-    message = None
-
-    def __init__(self, message):
-        self.message = message
-
 
+"""
+Exception thrown when there is an error parsing managed proxy
+environment variables. Also sends an ENV-ERROR to Tor.
+"""
+class EnvException(Exception): pass
diff --git a/pyptlib/server.py b/pyptlib/server.py
index b36ceee..bcc2ae8 100644
--- a/pyptlib/server.py
+++ b/pyptlib/server.py
@@ -7,7 +7,7 @@ from pyptlib.config import EnvException
 from pyptlib.server_config import ServerConfig
 
 
-def init(transports):
+def init(supported_transports):
     """
     Initialize the pluggable transport by parsing the environment
     variables and generating output to report any errors.  The
@@ -24,47 +24,59 @@ def init(transports):
     of Tor's ORPort.
 
     'ext_orport' : [<addr>, <port>] tuple containing the address and
-    port of Tor's Extended ORPort.
+    port of Tor's Extended ORPort, or None if the Extended ORPort it's
+    not supported.
 
     'transports' : A dictionary {<transport> : [<addr>, <port>]},
     where <transport> is the name of the transport that must be
     spawned, and [<addr>, <port>] is a list containing the location
-    where that transport should bind.
+    where that transport should bind. The dictionary can be empty.
 
-    Returns None if something went wrong.
+    Throws EnvException.
     """
 
     supportedTransportVersion = '1'
 
-    try:
-        config = ServerConfig()
-    except EnvException: # don't throw exceptions; return None
-        return None
+    config = ServerConfig()
 
     if config.checkManagedTransportVersion(supportedTransportVersion):
         config.writeVersion(supportedTransportVersion)
     else:
         config.writeVersionError()
-        return None
-
-    matchedTransports = []
-    for transport in transports:
-        if config.checkTransportEnabled(transport):
-            matchedTransports.append(transport)
-
-    # XXX Must issue SMETHOD-ERROR when Tor asked us to spawn a
-    # XXX transport but we don't support it!!!!
-
-    # XXX what to do if matchedTransports is empty ???
+        raise EnvException("Unsupported managed proxy protocol version (%s)" %
+                           str(config.getManagedTransportVersions()))
 
     retval = {}
     retval['state_loc'] = config.getStateLocation()
     retval['orport'] = config.getORPort()
     retval['ext_orport'] = config.getExtendedORPort()
-    retval['transports'] = config.getServerBindAddresses()
+    retval['transports'] = getTransportsDict(supported_transports, config)
 
     return retval
 
+def getTransportsDict(supported_transports, config):
+    """
+    Given the transport names that the managed proxy support in
+    'transports', and Tor's configuration in 'config', figure out
+    which transports Tor wants us to spawn and create the appropriate
+    dictionary.
+    """
+    transports = {}
+
+    if config.getAllTransportsEnabled():
+        return config.getServerBindAddresses()
+
+    for transport in config.getServerTransports():
+        if transport in supported_transports:
+            assert(transport in config.getServerBindAddresses())
+            transports[transport] = config.getServerBindAddresses()[transport]
+        else:
+            # Issue SMETHOD-ERROR when Tor asks us to spawn a
+            # transport that we do not support.
+            config.writeMethodError(transport, "not supported")
+
+    return transports
+
 def reportSuccess(name, address, options):
     """
         This method should be called to report when a transport has been successfully launched.
diff --git a/pyptlib/server_config.py b/pyptlib/server_config.py
index 854b55b..181c071 100644
--- a/pyptlib/server_config.py
+++ b/pyptlib/server_config.py
@@ -2,8 +2,9 @@
 # -*- coding: utf-8 -*-
 
 """
-    The pyptlib.client module contains a low-level API which closely follows the Tor Proposal 180: Pluggable transports for circumvention.
-    This module inherits from pyptlib.config and contains just the parts of the API which are specific to the server implementations of the protocol.
+This module inherits from pyptlib.config and contains just the parts
+of the API which are specific to the server implementations of the
+protocol.
 """
 
 import os
@@ -13,36 +14,37 @@ import pyptlib.config as config
 __docformat__ = 'restructuredtext'
 
 class ServerConfig(config.Config):
-
     """
-    The ServerConfig class contains a low-level API which closely follows the Tor Proposal 180: Pluggable transports for circumvention.
-    This class inherits from pyptlib.config.Config and contains just the parts of the API which are specific to the client implementations of the protocol.
+    This class inherits from pyptlib.config.Config and contains just
+    the parts of the API which are specific to the client
+    implementations of the protocol.
     """
-
-    extendedServerPort = None  # TOR_PT_EXTENDED_SERVER_PORT
-    ORPort = None  # TOR_PT_ORPORT
-    serverBindAddr = {}  # TOR_PT_SERVER_BINADDR
-
   # Public methods
 
-    def __init__(self):  # throws EnvError
+    def __init__(self):
         """
-            Initialize the ClientConfig object.
-            This causes the state location, managed transport, and transports version to be set.
+        Initialize the ClientConfig object.
+        This causes the state location, managed transport, and transports version to be set.
+
+        Throws EnvException.
         """
 
         config.Config.__init__(self)
 
-        # extendedORPort can also be 'None'
-        self.extendedORPort = config.parse_addrport(self.get('TOR_PT_EXTENDED_SERVER_PORT'))
-        self.ORPort = config.parse_addrport(self.get('TOR_PT_ORPORT'))
-
-        if self.ORPort is None:
-            raise config.EnvException("ORPort was corrupted")
+        # TOR_PT_EXTENDED_SERVER_PORT is optional; tor uses the empty
+        # string as its value if it does not support the Extended
+        # ORPort.
+        ext_orport_tmp = self.get('TOR_PT_EXTENDED_SERVER_PORT')
+        if ext_orport_tmp == '':
+            self.extendedORPort = None
+        else:
+            self.extendedORPort = self.get_addrport('TOR_PT_EXTENDED_SERVER_PORT')
 
+        self.ORPort = self.get_addrport('TOR_PT_ORPORT')
 
-        binds = self.get('TOR_PT_SERVER_BINDADDR').split(',')
-        for bind in binds:
+        self.serverBindAddr = {}
+        bindaddrs = self.get('TOR_PT_SERVER_BINDADDR').split(',')
+        for bind in bindaddrs:
             (key, value) = bind.split('-')
             self.serverBindAddr[key] = value.split(":") # XXX ugly code
             self.serverBindAddr[key][1] = int(self.serverBindAddr[key][1]) # XXX ugly code
@@ -68,16 +70,15 @@ class ServerConfig(config.Config):
         return self.serverBindAddr
 
     def getServerTransports(self):
-        """ Returns a list of strings representing the server transports reported by Tor. If present, '*' is stripped from this list and used to set allTransportsEnabled to True. """
+        """
+        Returns a list of strings representing the server
+        transports reported by Tor. If present, '*' is stripped from
+        this list and used to set allTransportsEnabled to True.
+        """
 
         return self.transports
 
-    def writeMethod(  # SMETHOD
-        self,
-        name,
-        address,
-        options,
-        ):
+    def writeMethod(self, name, address, options):
         """
         Write a message to stdout specifying a supported transport
         Takes: str, (str, int), MethodOptions
@@ -103,6 +104,28 @@ class ServerConfig(config.Config):
 
         self.emit('SMETHODS DONE')
 
+    def get_addrport(self, key):
+        """
+        Given an environment variable name in 'key' with an
+        '<addr>:<port>' value, return [<addr>,<port>].
+
+        Throws EnvException.
+        """
+        string = self.get(key)
+
+        addrport = string.split(':')
+
+        if (len(addrport) != 2) or (not addrport[1].isdigit()):
+            message = '%s: Parsing error (%s).' % (key, string)
+            self.writeEnvError(message)
+            raise config.EnvException(message)
+
+        if (not 0 <= int(addrport[1]) < 65536):
+            message = '%s: Port out of range (%s).' % (key, string)
+            self.writeEnvError(message)
+            raise config.EnvException(message)
+
+        return addrport
 
 class MethodOptions:
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/pyptlib.git



More information about the Pkg-privacy-commits mailing list