where to buy misoprostol online how to buy valtrex
SSL support in asynchat.async_chat | Evan Fosmark

SSL support in asynchat.async_chat

A while back I needed to be able to use SSL connections in async_chat, but I found it to be horribly incompatible. After quite a bit of investigation I found a suitable solution.

import asynchat
import socket
import ssl
import errno
 
class async_chat_ssl(asynchat.async_chat):
    """ Asynchronous connection with SSL support. """
 
    def connect(self, host, use_ssl=False):
        self.use_ssl = use_ssl
        if use_ssl:
            self.send = self._ssl_send
            self.recv = self._ssl_recv
        asynchat.async_chat.connect(self, host)
 
    def handle_connect(self):
        """ Initializes SSL support after the connection has been made. """
        if self.use_ssl:
            self.ssl = ssl.wrap_socket(self.socket)
            self.set_socket(self.ssl)
 
    def _ssl_send(self, data):
        """ Replacement for self.send() during SSL connections. """
        try:
            result = self.write(data)
            return result
        except ssl.SSLError, why:
            if why[0] in (asyncore.EWOULDBLOCK, errno.ESRCH):
                return 0
            else:
                raise ssl.SSLError, why
            return 0
 
    def _ssl_recv(self, buffer_size):
        """ Replacement for self.recv() during SSL connections. """
        try:
            data = self.read(buffer_size)
            if not data:
                self.handle_close()
                return ''
            return data
        except ssl.SSLError, why:
            if why[0] in (asyncore.ECONNRESET, asyncore.ENOTCONN, 
                          asyncore.ESHUTDOWN):
                self.handle_close()
                return ''
            elif why[0] == errno.ENOENT:
                # Required in order to keep it non-blocking
                return ''
            else:
                raise

It should fit in place of typical use of asynchat.async_chat. In order to specify that you’re wanting to use SSL, just set the flag in:

connect(host, use_ssl=True)

It would be nice if SSL support with asynchat.async_chat worked by default. Hopefully I’m not the only one who finds the above solution useful.

And as always, if you see any errors above, I encourage you to post a comment explaining the it!

 

 

4 Comments

  1. Jean-Paul Calderone wrote,

    Unfortunately, you may not find this as useful as you would have expected. The ssl module does not support non-blocking reads:

    >>> import socket
    >>> import time
    >>> import ssl
    >>> s = ssl.wrap_socket(socket.socket())
    >>> s.connect((‘localhost’, 8443))
    >>> s.send(‘GET /async.rpy HTTP/1.1\r\n\r\n’)
    27
    >>> s.setblocking(False)
    >>> a = time.time(); s.recv(1024); b = time.time()
    ‘HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nDate: Thu, 02 Sep 2010 11:51:03 GMT\r\nContent-Type: text/html\r\nServer: TwistedWeb/10.1.0+r29954\r\n\r\n4c\r\n<html><body>Sorry to keep you waiting.</body></html>\r\n0\r\n\r\n’
    >>> print b – a
    4.13403391838
    >>>

    Even worse than the fact that it blocks is the fact that it is busy looping while it does so. Expect to see 100% CPU when using this approach any time there’s a network hiccup or someone decides to DoS your service. :(

  2. Giampaolo RodolĂ  wrote,

    @jp: what python version are you using?
    Python 2.6.6 should already include a fix for that: http://bugs.python.org/issue3890

  3. Jean-Paul Calderone wrote,

    @Giampaolo: It seems that bug was deemed important enough to include twice. ;) The one in ssl.py does appear to be fixed, but the one in _ssl.c is still there: see the do loop in PySSL_SSLRead at http://svn.python.org/view/*checkout*/python/trunk/Modules/_ssl.c?revision=82210&content-type=text/plain

  4. Erdal wrote,

    ok, so which version of Python works with the non-blocking socket?

Leave a comment