Re: M2Crypto.httpslib.HTTPSConnection only works once?

Ng Pheng Siong <[email protected]>
Newsgroups gmane.comp.python.cryptography
Message-ID <[email protected]>
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 <[email protected]>

http://sandbox.rulemaker.net/ngps -+- M2Crypto, ZServerSSL for Zope, Blog
http://www.sqlcrypt.com -+- Database Engine with Transparent AES Encryption
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.