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

# Source Code for Module tlslite.integration.tlsasyncdispatchermixin

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