[PYTHON-CRYPTO] M2Crypto.httpslib.HTTPSConnection only works once?

Ng Pheng Siong ngps at NETMEMETIC.COM
Mon Jan 31 16:17:56 CET 2005


On Fri, Jan 28, 2005 at 01:42:36PM -0800, Heikki Toivonen wrote:
> M2Crypto.SSL.SSLError: bad write retry
> Has anyone else seen this?

I suppose your code uses non-blocking sockets. I've just blogged about this
very topic here:

    http://sandbox.rulemaker.net/ngps/199

In essence, "bad write retry" arises from the way OpenSSL behaves in
non-blocking mode; specifically, if a write cannot complete (because of
SSL-layer protocol happenings) then the operation should be attempted again
with the same data.

The fix alluded to in my blog post is as follows:

- Changed the 'send' method in class https_channel in ZServerSSL's
  https_server.py to this:

    def send(self, data):
        try:
            if self._wbuf is not None:
                if len(data) > len(self._wbuf):
                    result = self._send_buffered(self._wbuf)
                    if result > 0:
                        data = data[len(self._wbuf):]
                        self._wbuf = None
                        return self.send(data)
                    else:
                        return 0
                else:
                    self._wbuf = None
                    return self.send(data)
            else:
                result = self.socket._write_nbio(data)
                if result <= 0:
                    if result == -1:
                        self._wbuf = data
                    return 0
                else:
                    self.server.bytes_out.increment(result)
                    return result
        except SSL.SSL_ReadWrite_Retry_Error, which:
            if which[0] == SSL.SSL_ERROR_WANT_READ:
                self._ssl_writable = None
                self._ssl_readable = 1
            return 0
        except SSL.SSLError, why:
            self.close()
            self.log_info('send: closing channel %s %s' % (repr(self), why))
            return 0

- Added a new method '_send_buffered':

    def _send_buffered(self, data):
        try:
            result = self.socket._write_nbio(data)
            if result <= 0:
                return 0
            else:
                self.server.bytes_out.increment(result)
                return result
        except SSL.SSL_ReadWrite_Retry_Error, which:
            if which[0] == SSL.SSL_ERROR_WANT_READ:
                self._ssl_writable = None
                self._ssl_readable = 1
            return -1
        except SSL.SSLError, why:
            self.close()
            self.log_info('send: closing channel %s %s' % (repr(self), why))
            return -1

- Add the necessary assignment 'self._wbuf = None' in the class's __init__
  method.

(BTW, Heikki, are you the one who added the
"except SSL.SSL_ReadWrite_Retry_Error" stuff?)

Now, if you are using blocking sockets, then this will be a very curious
situation, because, for the longest time, in SWIG/_ssl.i's bio_set_ssl():

    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

which supposedly means that OpenSSL will retry automatically without
bothering the application.

Cheers.

--
Ng Pheng Siong <ngps at netmemetic.com>

http://sandbox.rulemaker.net/ngps -+- M2Crypto, ZServerSSL for Zope, Blog
http://www.sqlcrypt.com -+- Database Engine with Transparent AES Encryption





More information about the python-crypto mailing list