Commits

trevp  committed 45441e4

0.2.4 - cleaned up asyncore, twisted proof-of-concept

  • Participants
  • Parent commits 0339ed3

Comments (0)

Files changed (2)

File tlslite/AsyncStateMachine.py

+"""
+This class implements a state machine for using TLS Lite with select-based
+asynchronous communications (like Twisted or asyncore).
+
+The class signals wantsReadsEvent() and wantsWriteEvent().  When passed
+an event through readEvent() or writeEvent() calls, the class updates its
+state and "forwards" an event to its superclass, if applicable.
+"""
+
+class AsyncStateMachine:
+
+    def __init__(self):
+        self.clear()
+
+    def clear(self):
+        #These store the various asynchronous operations
+        #(i.e. generators).  Only one of them, at most,
+        #is ever active at a time.
+        self.handshaker = None
+        self.closer = None
+        self.reader = None
+        self.writer = None
+
+        #This stores the result from the last call to the
+        #currently active operation.  If 0 it indicates
+        #that the operation wants to read, if 1 it
+        #indicates that the operation wants to write.  If
+        #None, there is no active operation.
+        self.result = None
+
+    def checkAssert(self, maxActive=1):
+        #This checks that only one operation, at most, is
+        #active, and that self.result is set appropriately.
+        activeOps = 0
+        if self.handshaker:
+            activeOps += 1
+        if self.closer:
+            activeOps += 1
+        if self.reader:
+            activeOps += 1
+        if self.writer:
+            activeOps += 1
+
+        if self.result == None:
+            assert(activeOps == 0)
+        elif self.result in (0,1):
+            assert(activeOps == 1)
+        else:
+            assert()
+        assert (activeOps <= maxActive)
+
+    def wantsReadEvent(self):
+        #If there's an active operation, does it want to read?
+        if self.result != None:
+            return self.result == 0
+        return None
+
+    def wantsWriteEvent(self):
+        #If there's an active operation, does it want to write?
+        if self.result != None:
+            return self.result == 1
+        return None
+
+    #Superclass implements these to be notified when events occur
+
+    def forwardConnectEvent(self):
+        pass
+
+    def forwardCloseEvent(self):
+        pass
+
+    def forwardReadEvent(self, readBuffer):
+        pass
+
+    def forwardWriteEvent(self):
+        pass
+
+    def readEvent(self):
+        try:
+            self.checkAssert()
+            if self.handshaker:
+                self.doHandshakeOp()
+            elif self.closer:
+                self.doCloseOp()
+            elif self.reader:
+                self.doReadOp()
+            elif self.writer:
+                self.doWriteOp()
+            else:
+                self.reader = self.tlsConnection.readAsync(16384)
+                self.doReadOp()
+        except:
+            self.clear()
+            raise
+
+    def writeEvent(self):
+        try:
+            self.checkAssert()
+            if self.handshaker:
+                self.doHandshakeOp()
+            elif self.closer:
+                self.doCloseOp()
+            elif self.reader:
+                self.doReadOp()
+            elif self.writer:
+                self.doWriteOp()
+            else:
+                self.forwardWriteEvent()
+        except:
+            self.clear()
+            raise
+
+    def doHandshakeOp(self):
+        try:
+            self.result = self.handshaker.next()
+        except StopIteration:
+            self.handshaker = None
+            self.result = None
+            self.forwardConnectEvent()
+
+    def doCloseOp(self):
+        try:
+            self.result = self.closer.next()
+        except StopIteration:
+            self.closer = None
+            self.result = None
+            self.forwardCloseEvent()
+
+    def doReadOp(self):
+        self.result = self.reader.next()
+        if not self.result in (0,1):
+            readBuffer = self.result
+            self.reader = None
+            self.result = None
+            self.forwardReadEvent(readBuffer)
+
+    def doWriteOp(self):
+        try:
+            self.result = self.writer.next()
+        except StopIteration:
+            self.writer = None
+            self.result = None
+
+    def setHandshakeOp(self, handshaker):
+        try:
+            self.checkAssert(0)
+            self.handshaker = handshaker
+            self.doHandshakeOp()
+        except:
+            self.clear()
+            raise
+
+    def setServerHandshakeOp(self, **args):
+        handshaker = self.tlsConnection.handshakeServerAsync(**args)
+        self.setHandshakeOp(handshaker)
+
+    def setCloseOp(self):
+        try:
+            self.checkAssert(0)
+            self.closer = self.tlsConnection.closeAsync()
+            self.doCloseOp()
+        except:
+            self.clear()
+            raise
+
+    def setWriteOp(self, writeBuffer):
+        try:
+            self.checkAssert(0)
+            self.writer = self.tlsConnection.writeAsync(writeBuffer)
+            self.doWriteOp()
+        except:
+            self.clear()
+            raise
+

File tlslite/TLSTwistedMixIn.py

+
+from TLSConnection import TLSConnection
+from AsyncStateMachine import AsyncStateMachine
+
+
+class TLSTwistedMixIn(AsyncStateMachine):
+
+    def __init__(self, sock=None):
+        AsyncStateMachine.__init__(self)
+
+        if sock:
+            self.tlsConnection = TLSConnection(sock)
+
+        #Calculate the sibling I'm being mixed in with.
+        #This is necessary since we override functions
+        #like doRead(), doWrite(), etc., but we
+        #also want to call the sibling's versions.
+        for cl in self.__class__.__bases__:
+            if cl != TLSTwistedMixIn and cl != AsyncStateMachine:
+                self.siblingClass = cl
+                break
+        else:
+            assert()
+
+    def readable(self):
+        result = self.wantsReadEvent()
+        if result != None:
+            return result
+        return self.siblingClass.readable(self)
+
+    def writable(self):
+        result = self.wantsWriteEvent()
+        if result != None:
+            return result
+        return self.siblingClass.writable(self)
+
+
+    def doRead(self):
+        self.readEvent()
+        if self.wantsReadEvent():
+            self.startReading()
+        if self.wantsWriteEvent():
+            self.startWriting()
+
+    def doWrite(self):
+        self.writeEvent()
+        if self.wantsReadEvent():
+            self.startReading()
+        if self.wantsWriteEvent():
+            self.startWriting()
+
+    def forwardConnectEvent(self):
+        pass
+
+    def forwardCloseEvent(self):
+        pass
+        #asyncore.dispatcher.close(self)
+
+    def forwardReadEvent(self, readBuffer):
+        self.protocol.dataReceived(readBuffer)
+
+    def forwardWriteEvent(self):
+        self.siblingClass.doWrite(self)
+
+    def writeSomeData(self, data):
+        self.setWriteOp(data)
+        return len(data)
+
+    def loseConnection(self):
+        pass
+        #if hasattr(self, "tlsConnection"):
+        #    self.setCloseOp()
+        #else:
+        #    asyncore.dispatcher.close(self)