tlslite.integration.tlsasyncdispatchermixin

Package tlslite :: Package integration :: Module tlsasyncdispatchermixin |
[hide private]
[frames] | no frames]

# Source Code for Module tlslite.integration.tlsasyncdispatchermixin

      1  # Author: Trevor Perrin
      2  # See the LICENSE file for legal information regarding use of this file.
      3
      4  """TLS Lite + asyncore."""
      5
      6
      7  import asyncore
      8  from tlslite.tlsconnection import TLSConnection
      9  from asyncstatemachine import AsyncStateMachine
     10
     11
     12 -class TLSAsyncDispatcherMixIn(AsyncStateMachine):
     13      """This class can be "mixed in" with an
     14      L{asyncore.dispatcher} to add TLS support.
     15
     16      This class essentially sits between the dispatcher and the select
     17      loop, intercepting events and only calling the dispatcher when
     18      applicable.
     19
     20      In the case of handle_read(), a read operation will be activated,
     21      and when it completes, the bytes will be placed in a buffer where
     22      the dispatcher can retrieve them by calling recv(), and the
     23      dispatcher's handle_read() will be called.
     24
     25      In the case of handle_write(), the dispatcher's handle_write() will
     26      be called, and when it calls send(), a write operation will be
     27      activated.
     28
     29      To use this class, you must combine it with an asyncore.dispatcher,
     30      and pass in a handshake operation with setServerHandshakeOp().
     31
     32      Below is an example of using this class with medusa.  This class is
     33      mixed in with http_channel to create http_tls_channel.  Note:
     34       1. the mix-in is listed first in the inheritance list
     35
     36       2. the input buffer size must be at least 16K, otherwise the
     37         dispatcher might not read all the bytes from the TLS layer,
     38         leaving some bytes in limbo.
     39
     40       3. IE seems to have a problem receiving a whole HTTP response in a
     41       single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't
     42       be displayed on IE.
     43
     44      Add the following text into 'start_medusa.py', in the 'HTTP Server'
     45      section::
     46
     47          from tlslite import *
     48          s = open("./serverX509Cert.pem").read()
     49          x509 = X509()
     50          x509.parse(s)
     51          certChain = X509CertChain([x509])
     52
     53          s = open("./serverX509Key.pem").read()
     54          privateKey = parsePEMKey(s, private=True)
     55
     56          class http_tls_channel(TLSAsyncDispatcherMixIn,
     57                                 http_server.http_channel):
     58              ac_in_buffer_size = 16384
     59
     60              def __init__ (self, server, conn, addr):
     61                  http_server.http_channel.__init__(self, server, conn, addr)
     62                  TLSAsyncDispatcherMixIn.__init__(self, conn)
     63                  self.tlsConnection.ignoreAbruptClose = True
     64                  self.setServerHandshakeOp(certChain=certChain,
     65                                            privateKey=privateKey)
     66
     67          hs.channel_class = http_tls_channel
     68
     69      If the TLS layer raises an exception, the exception will be caught
     70      in asyncore.dispatcher, which will call close() on this class.  The
     71      TLS layer always closes the TLS connection before raising an
     72      exception, so the close operation will complete right away, causing
     73      asyncore.dispatcher.close() to be called, which closes the socket
     74      and removes this instance from the asyncore loop.
     75
     76      """
     77
     78
     79 -    def __init__(self, sock=None):
     80          AsyncStateMachine.__init__(self)
     81
     82          if sock:
     83              self.tlsConnection = TLSConnection(sock)
     84
     85          #Calculate the sibling I'm being mixed in with.
     86          #This is necessary since we override functions
     87          #like readable(), handle_read(), etc., but we
     88          #also want to call the sibling's versions.
     89          for cl in self.__class__.__bases__:
     90              if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine:
     91                  self.siblingClass = cl
     92                  break
     93          else:
     94              raise AssertionError()
     95
     96 -    def readable(self):
     97          result = self.wantsReadEvent()
     98          if result != None:
     99              return result
    100          return self.siblingClass.readable(self)
    101
    102 -    def writable(self):
    103          result = self.wantsWriteEvent()
    104          if result != None:
    105              return result
    106          return self.siblingClass.writable(self)
    107
    108 -    def handle_read(self):
    109          self.inReadEvent()
    110
    111 -    def handle_write(self):
    112          self.inWriteEvent()
    113
    114 -    def outConnectEvent(self):
    115          self.siblingClass.handle_connect(self)
    116
    117 -    def outCloseEvent(self):
    118          asyncore.dispatcher.close(self)
    119
    120 -    def outReadEvent(self, readBuffer):
    121          self.readBuffer = readBuffer
    122          self.siblingClass.handle_read(self)
    123
    124 -    def outWriteEvent(self):
    125          self.siblingClass.handle_write(self)
    126
    127 -    def recv(self, bufferSize=16384):
    128          if bufferSize < 16384 or self.readBuffer == None:
    129              raise AssertionError()
    130          returnValue = self.readBuffer
    131          self.readBuffer = None
    132          return returnValue
    133
    134 -    def send(self, writeBuffer):
    135          self.setWriteOp(writeBuffer)
    136          return len(writeBuffer)
    137
    138 -    def close(self):
    139          if hasattr(self, "tlsConnection"):
    140              self.setCloseOp()
    141          else:
    142              asyncore.dispatcher.close(self)
    143