[Pkg-privacy-commits] [obfsproxy] 71/353: Fix transport callbacks to work with Twisted.

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 13:01:41 UTC 2015


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

infinity0 pushed a commit to branch master
in repository obfsproxy.

commit 2fceedb53e4a570f39128ed83b08af34f35f13d6
Author: George Kadianakis <desnacked at riseup.net>
Date:   Wed Sep 26 20:16:04 2012 +0300

    Fix transport callbacks to work with Twisted.
    
    Also, document the callbacks.
---
 obfsproxy/network/network.py  |  66 +++++++++++++++++--------
 obfsproxy/network/socks.py    |   7 +++
 obfsproxy/transports/base.py  | 110 ++++++++++++------------------------------
 obfsproxy/transports/dummy.py |   1 -
 4 files changed, 85 insertions(+), 99 deletions(-)

diff --git a/obfsproxy/network/network.py b/obfsproxy/network/network.py
index d9e1f79..e267301 100644
--- a/obfsproxy/network/network.py
+++ b/obfsproxy/network/network.py
@@ -73,9 +73,10 @@ class Circuit(Protocol):
 
     def __init__(self, transport):
         self.transport = transport # takes a transport
+        self.downstream = None # takes a connection
+        self.upstream = None # takes a connection
 
-        self.downstream = None # takes a twisted transport
-        self.upstream = None # takes a twisted transport
+        self.closed = False # True if the circuit is closed.
 
         self.name = "circ_%s" % hex(id(self))
 
@@ -88,11 +89,17 @@ class Circuit(Protocol):
         assert(not self.downstream)
         self.downstream = conn
 
-        """We just completed the circuit, do a dummy dataReceived on
-        the initiating connection in case it had any buffered data
-        that must be flushed to the network."""
+        """We just completed the circuit.
+
+        Do a dummy dataReceived on the initiating connection in case
+        it has any buffered data that must be flushed to the network.
+
+        Also, call the transport-specific handshake method since this
+        is a good time to perform a handshake.
+        """
         if self.circuitIsReady():
-            self.upstream.dataReceived('')
+            self.upstream.dataReceived('') # XXX kind of a hack.
+            self.transport.handshake(self)
 
     def setUpstreamConnection(self, conn):
         """
@@ -103,11 +110,17 @@ class Circuit(Protocol):
         assert(not self.upstream)
         self.upstream = conn
 
-        """We just completed the circuit, do a dummy dataReceived on
-        the initiating connection in case it had any buffered data
-        that must be flushed to the network."""
+        """We just completed the circuit.
+
+        Do a dummy dataReceived on the initiating connection in case
+        it has any buffered data that must be flushed to the network.
+
+        Also, call the transport-specific handshake method since this
+        is a good time to perform a handshake.
+        """
         if self.circuitIsReady():
             self.downstream.dataReceived('')
+            self.transport.handshake(self)
 
     def circuitIsReady(self):
         """
@@ -141,10 +154,15 @@ class Circuit(Protocol):
         """
         Tear down the circuit.
         """
+        if self.closed: return # NOP if already closed
+
+        log.info("%s: Tearing down circuit." % self.name)
 
-        log.info("%s: Closing down circuit." % self.name)
         if self.downstream: self.downstream.close()
         if self.upstream: self.upstream.close()
+        self.closed = True
+
+        self.transport.circuitDestroyed(self)
 
 class StaticDestinationProtocol(Protocol):
     """
@@ -167,6 +185,8 @@ class StaticDestinationProtocol(Protocol):
         self.circuit = circuit
         self.direction = None # XXX currently unused
 
+        self.closed = False # True if connection is closed.
+
         self.name = "conn_%s" % hex(id(self))
 
     def connectionMade(self):
@@ -208,9 +228,11 @@ class StaticDestinationProtocol(Protocol):
 
     def connectionLost(self, reason):
         log.info("%s: Connection was lost (%s)." % (self.name, reason.getErrorMessage()))
+        self.circuit.close()
 
     def connectionFailed(self, reason):
         log.info("%s: Connection failed to connect (%s)." % (self.name, reason.getErrorMessage()))
+        self.circuit.close()
 
     def dataReceived(self, data):
         """
@@ -221,7 +243,7 @@ class StaticDestinationProtocol(Protocol):
         Circuit.setDownstreamConnection(). Document or split function.
         """
         if (not self.buffer) and (not data):
-            log.info("%s: dataReceived called without a reason.")
+            log.info("%s: dataReceived called without a reason.", self.name)
             return
 
         log.debug("%s: Received %d bytes (and %d cached):\n%s" \
@@ -238,12 +260,23 @@ class StaticDestinationProtocol(Protocol):
         self.buffer = self.circuit.dataReceived(self.buffer + data, self)
 
     def write(self, buf):
+        """
+        Write 'buf' to the underlying transport.
+        """
         log.debug("%s: Writing %d bytes." % (self.name, len(buf)))
+
         self.transport.write(buf)
 
     def close(self):
+        """
+        Close the connection.
+        """
+        if self.closed: return # NOP if already closed
+
         log.debug("%s: Closing connection." % self.name)
+
         self.transport.loseConnection()
+        self.closed = True
 
 class StaticDestinationClientFactory(Factory):
     """
@@ -264,12 +297,10 @@ class StaticDestinationClientFactory(Factory):
         log.debug("%s: Client factory started connecting." % self.name)
 
     def clientConnectionLost(self, connector, reason):
-        log.info("%s: Connection was lost (%s)." % (self.name, reason.getErrorMessage()))
-        self.circuit.close()
+        pass # connectionLost event is handled on the Protocol.
 
     def clientConnectionFailed(self, connector, reason):
-        log.debug("%s: Connection failed to connect (%s)." % (self.name, reason.getErrorMessage()))
-        self.circuit.close()
+        pass # connectionFailed event is handled on the Protocol.
 
 class StaticDestinationServerFactory(Factory):
     """
@@ -285,7 +316,6 @@ class StaticDestinationServerFactory(Factory):
     mode: 'server' or 'client'
     transport: the pluggable transport we should use to
                obfuscate traffic on this connection.
-    circuits: A list with all the circuits this listener has created.
     """
 
     def __init__(self, remote_addrport, mode, transport):
@@ -296,9 +326,6 @@ class StaticDestinationServerFactory(Factory):
 
         self.name = "fact_s_%s" % hex(id(self))
 
-        # XXX currently unused. Remove to reduce memory fpr?
-        self.circuits = []
-
         assert(self.mode == 'client' or self.mode == 'server')
 
     def startFactory(self):
@@ -308,7 +335,6 @@ class StaticDestinationServerFactory(Factory):
         log.info("%s: New connection." % self.name)
 
         circuit = Circuit(self.transport)
-        self.circuits.append(circuit) # XXX when do we remove this?
 
         # XXX instantiates a new factory for each client
         clientFactory = StaticDestinationClientFactory(circuit, self.mode)
diff --git a/obfsproxy/network/socks.py b/obfsproxy/network/socks.py
index 20c05d6..46bd46d 100644
--- a/obfsproxy/network/socks.py
+++ b/obfsproxy/network/socks.py
@@ -87,6 +87,13 @@ class SOCKSv4Protocol(socks.SOCKSv4):
 
         self.buffer = self.circuit.dataReceived(self.buffer + data, self)
 
+    def connectionLost(self, reason):
+        log.info("%s: Connection was lost (%s)." % (self.name, reason.getErrorMessage()))
+        self.circuit.close()
+
+    def connectionFailed(self, reason):
+        log.info("%s: Connection failed to connect (%s)." % (self.name, reason.getErrorMessage()))
+        self.circuit.close()
 
 class SOCKSv4Factory(Factory):
     """
diff --git a/obfsproxy/transports/base.py b/obfsproxy/transports/base.py
index fcab386..f395b9b 100644
--- a/obfsproxy/transports/base.py
+++ b/obfsproxy/transports/base.py
@@ -4,15 +4,13 @@
 import obfsproxy.common.log as log
 
 """
-This module contains BaseDaemon, a base class for implementing pluggable transport clients and server.
-It is not necessary to subclass BaseDaemon in order to implement pluggable transports.
-However, BaseDaemon provides utility methods that are useful for a variety of common transports.
+This module contains BaseDaemon, a pluggable transport skeleton class.
 """
 
 def addrport(string):
     """
-    Receive '<addr>:<port>' and return [<addr>,<port>]. Used during
-    argparse CLI parsing.
+    Receive '<addr>:<port>' and return [<addr>,<port>].
+    Used during argparse CLI parsing.
     """
 
     addrport = string.split(':')
@@ -24,14 +22,41 @@ def addrport(string):
     return addrport
 
 class BaseDaemon:
-
     """
-    The BaseDaemon class is a skeleton class for implementing pluggable transports.
+    The BaseDaemon class is a skeleton class for pluggable transports.
+    It contains callbacks that your pluggable transports should
+    override and customize.
     """
 
     def __init__(self):
         pass
 
+    def handshake(self, circuit):
+        """
+        The Circuit 'circuit' was completed, and this is a good time
+        to do your transport-specific handshake on its downstream side.
+        """
+        pass
+
+    def circuitDestroyed(self, circuit):
+        """
+        Circuit 'circuit' was tore down.
+        Both connections of the circuit are closed when this callback triggers.
+        """
+        pass
+
+    def receivedDownstream(self, data, circuit):
+        """
+        Received 'data' in the downstream side of 'circuit'.
+        """
+        pass
+
+    def receivedUpstream(self, data, circuit):
+        """
+        Received 'data' in the upstream side of 'circuit'.
+        """
+        pass
+
     @classmethod
     def register_external_mode_cli(cls, subparser):
         """
@@ -63,74 +88,3 @@ class BaseDaemon:
             return False
 
         return True
-
-    def read(
-        self,
-        socket,
-        data,
-        maxlen,
-        ):
-        """
-        This read method is a convience method which takes a socket to read from, some existing data, and a maxlength.
-        It reads bytes from socket and appends them to data until data is equal to maxlen, or the socket has no more bytes ready.
-        It returns a new data object which is a combination of data and the bytes read from socket and which is <= maxlen.
-        """
-
-        remaining = maxlen - len(data)
-        return data + socket.read(remaining)
-
-    def checkTransition(
-        self,
-        data,
-        maxlen,
-        newState,
-        ):
-        """
-        This is a convience method for state-based protocols which need to read fixed length data from the socket before they can change states.
-        The checkTransition method takes some data, a max length, and state identifier.
-        If len(data) == maxlen then the state is set to the state is set to newState and True is returned.
-        Otherwise, the state stays the same and False is returned.
-        """
-
-        if len(data) == maxlen:
-            state = newState
-            return True
-        else:
-            return False
-
-    def start(self):
-        """
-        This is the callback method which is called by the framework when a new connection has been made.
-        In BaseDaemon it does nothing.
-        It is overridden by subclasses.
-        """
-
-        pass
-
-    # XXX update with the new API
-    def receivedDownstream(self):
-        """
-        This is the callback method which is called by the framework when bytes have been received on the downstream socket.
-        In BaseDaemon it does nothing.
-        It is overridden by subclasses.
-        """
-
-        pass
-
-    def receivedUpstream(self):
-        """
-        This is the callback method which is called by the framework when bytes have been received on the upstream socket.
-        In BaseDaemon it does nothing.
-        It is overridden by subclasses.
-        """
-
-        pass
-
-    def end(self):
-        """
-        This is the callback method which is called by the framework when the connection is closed.
-        In BaseDaemon it does nothing.
-        It is overridden by subclasses.
-        """
-
-        pass
diff --git a/obfsproxy/transports/dummy.py b/obfsproxy/transports/dummy.py
index 8c52e90..706a358 100644
--- a/obfsproxy/transports/dummy.py
+++ b/obfsproxy/transports/dummy.py
@@ -7,7 +7,6 @@ from obfsproxy.transports.base import BaseDaemon
 
 
 class DummyDaemon(BaseDaemon):
-
     """
     DummyDaemon is the base class for DummyClient and DummyServer.
     Since the protocol is so simple, DummyDaemon provides all of the

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



More information about the Pkg-privacy-commits mailing list