Merged revisions 80394 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/py3k

................
  r80394 | antoine.pitrou | 2010-04-23 02:16:21 +0200 (ven., 23 avril 2010) | 15 lines

  Merged revisions 80392 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r80392 | antoine.pitrou | 2010-04-23 01:33:02 +0200 (ven., 23 avril 2010) | 9 lines

    Issue #8108: Fix the unwrap() method of SSL objects when the socket has
    a non-infinite timeout.  Also make that method friendlier with applications
    wanting to continue using the socket in clear-text mode, by disabling
    OpenSSL's internal readahead.  Thanks to Darryl Miles for guidance.

    Issue #8108: test_ftplib's non-blocking SSL server now has proper handling
    of SSL shutdowns.
  ........
................
This commit is contained in:
Antoine Pitrou 2010-04-23 21:11:10 +00:00
parent 6c889ac96b
commit 5a1c4d1880
2 changed files with 68 additions and 6 deletions

View File

@ -40,6 +40,11 @@ Core and Builtins
Library
-------
- Issue #8108: Fix the unwrap() method of SSL objects when the socket has
a non-infinite timeout. Also make that method friendlier with applications
wanting to continue using the socket in clear-text mode, by disabling
OpenSSL's internal readahead. Thanks to Darryl Miles for guidance.
- Issue #8468: bz2.BZ2File() accepts str with surrogates and bytes filenames
- Issue #8496: make mailcap.lookup() always return a list, rather than an

View File

@ -9,6 +9,9 @@
directly.
XXX should partial writes be enabled, SSL_MODE_ENABLE_PARTIAL_WRITE?
XXX integrate several "shutdown modes" as suggested in
http://bugs.python.org/issue8108#msg102867 ?
*/
#include "Python.h"
@ -116,6 +119,7 @@ typedef struct {
SSL_CTX* ctx;
SSL* ssl;
X509* peer_cert;
int shutdown_seen_zero;
} PySSLObject;
@ -1377,7 +1381,8 @@ Read up to len bytes from the SSL socket.");
static PyObject *PySSL_SSLshutdown(PySSLObject *self)
{
int err;
int err, ssl_err, sockstate, nonblocking;
int zeros = 0;
PySocketSockObject *sock
= (PySocketSockObject *) PyWeakref_GetObject(self->Socket);
@ -1388,13 +1393,65 @@ static PyObject *PySSL_SSLshutdown(PySSLObject *self)
return NULL;
}
PySSL_BEGIN_ALLOW_THREADS
err = SSL_shutdown(self->ssl);
if (err == 0) {
/* we need to call it again to finish the shutdown */
/* Just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
while (1) {
PySSL_BEGIN_ALLOW_THREADS
/* Disable read-ahead so that unwrap can work correctly.
* Otherwise OpenSSL might read in too much data,
* eating clear text data that happens to be
* transmitted after the SSL shutdown.
* Should be safe to call repeatedly everytime this
* function is used and the shutdown_seen_zero != 0
* condition is met.
*/
if (self->shutdown_seen_zero)
SSL_set_read_ahead(self->ssl, 0);
err = SSL_shutdown(self->ssl);
PySSL_END_ALLOW_THREADS
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
if (err > 0)
break;
if (err == 0) {
/* Don't loop endlessly; instead preserve legacy
behaviour of trying SSL_shutdown() only twice.
This looks necessary for OpenSSL < 0.9.8m */
if (++zeros > 1)
break;
/* Shutdown was sent, now try receiving */
self->shutdown_seen_zero = 1;
continue;
}
/* Possibly retry shutdown until timeout or failure */
ssl_err = SSL_get_error(self->ssl, err);
if (ssl_err == SSL_ERROR_WANT_READ)
sockstate = check_socket_and_wait_for_timeout(sock, 0);
else if (ssl_err == SSL_ERROR_WANT_WRITE)
sockstate = check_socket_and_wait_for_timeout(sock, 1);
else
break;
if (sockstate == SOCKET_HAS_TIMED_OUT) {
if (ssl_err == SSL_ERROR_WANT_READ)
PyErr_SetString(PySSLErrorObject,
"The read operation timed out");
else
PyErr_SetString(PySSLErrorObject,
"The write operation timed out");
return NULL;
}
else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
PyErr_SetString(PySSLErrorObject,
"Underlying socket too large for select().");
return NULL;
}
else if (sockstate != SOCKET_OPERATION_OK)
/* Retain the SSL error code */
break;
}
PySSL_END_ALLOW_THREADS
if (err < 0)
return PySSL_SetError(self, err, __FILE__, __LINE__);