diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2010-04-24 20:13:37 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2010-04-24 20:13:37 (GMT) |
commit | c689d96044be67ea6ad1195527e22390f17104b1 (patch) | |
tree | 1eb9832aa26c8574d5da86d8c2750f566b0c3aa1 | |
parent | 2ec87deede7a5452fe336951ab30d2eb7bc4da47 (diff) | |
download | cpython-c689d96044be67ea6ad1195527e22390f17104b1.zip cpython-c689d96044be67ea6ad1195527e22390f17104b1.tar.gz cpython-c689d96044be67ea6ad1195527e22390f17104b1.tar.bz2 |
Merged revisions 80451-80452 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r80451 | antoine.pitrou | 2010-04-24 21:57:01 +0200 (sam., 24 avril 2010) | 4 lines
The do_handshake() method of SSL objects now adjusts the blocking mode of
the SSL structure if necessary (as other methods already do).
........
r80452 | antoine.pitrou | 2010-04-24 22:04:58 +0200 (sam., 24 avril 2010) | 4 lines
Issue #5103: SSL handshake would ignore the socket timeout and block
indefinitely if the other end didn't respond.
........
-rw-r--r-- | Lib/ssl.py | 7 | ||||
-rw-r--r-- | Lib/test/test_ssl.py | 81 | ||||
-rw-r--r-- | Misc/NEWS | 6 | ||||
-rw-r--r-- | Modules/_ssl.c | 7 |
4 files changed, 91 insertions, 10 deletions
@@ -113,12 +113,7 @@ class SSLSocket(socket): keyfile, certfile, cert_reqs, ssl_version, ca_certs) if do_handshake_on_connect: - timeout = self.gettimeout() - try: - self.settimeout(None) - self.do_handshake() - finally: - self.settimeout(timeout) + self.do_handshake() self.keyfile = keyfile self.certfile = certfile self.cert_reqs = cert_reqs diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 440c802..9c79af9 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -457,7 +457,8 @@ else: asyncore.dispatcher_with_send.__init__(self, conn) self.socket = ssl.wrap_socket(conn, server_side=True, certfile=certfile, - do_handshake_on_connect=True) + do_handshake_on_connect=False) + self._ssl_accepting = True def readable(self): if isinstance(self.socket, ssl.SSLSocket): @@ -465,9 +466,28 @@ else: self.handle_read_event() return True + def _do_ssl_handshake(self): + try: + self.socket.do_handshake() + except ssl.SSLError, err: + if err.args[0] in (ssl.SSL_ERROR_WANT_READ, + ssl.SSL_ERROR_WANT_WRITE): + return + elif err.args[0] == ssl.SSL_ERROR_EOF: + return self.handle_close() + raise + except socket.error, err: + if err.args[0] == errno.ECONNABORTED: + return self.handle_close() + else: + self._ssl_accepting = False + def handle_read(self): - data = self.recv(1024) - self.send(data.lower()) + if self._ssl_accepting: + self._do_ssl_handshake() + else: + data = self.recv(1024) + self.send(data.lower()) def handle_close(self): self.close() @@ -1226,6 +1246,61 @@ else: server.stop() server.join() + def test_handshake_timeout(self): + # Issue #5103: SSL handshake must respect the socket timeout + server = socket.socket(socket.AF_INET) + host = "127.0.0.1" + port = test_support.bind_port(server) + started = threading.Event() + finish = False + + def serve(): + server.listen(5) + started.set() + conns = [] + while not finish: + r, w, e = select.select([server], [], [], 0.1) + if server in r: + # Let the socket hang around rather than having + # it closed by garbage collection. + conns.append(server.accept()[0]) + + t = threading.Thread(target=serve) + t.start() + started.wait() + + try: + try: + c = socket.socket(socket.AF_INET) + c.settimeout(0.2) + c.connect((host, port)) + # Will attempt handshake and time out + try: + ssl.wrap_socket(c) + except ssl.SSLError, e: + self.assertTrue("timed out" in str(e), str(e)) + else: + self.fail("SSLError wasn't raised") + finally: + c.close() + try: + c = socket.socket(socket.AF_INET) + c.settimeout(0.2) + c = ssl.wrap_socket(c) + # Will attempt handshake and time out + try: + c.connect((host, port)) + except ssl.SSLError, e: + self.assertTrue("timed out" in str(e), str(e)) + else: + self.fail("SSLError wasn't raised") + finally: + c.close() + finally: + finish = True + t.join() + server.close() + def test_main(verbose=False): if skip_expected: @@ -33,6 +33,12 @@ Core and Builtins Library ------- +- Issue #5103: SSL handshake would ignore the socket timeout and block + indefinitely if the other end didn't respond. + +- The do_handshake() method of SSL objects now adjusts the blocking mode of + the SSL structure if necessary (as other methods already do). + - Issue #5238: Calling makefile() on an SSL object would prevent the underlying socket from being closed until all objects get truely destroyed. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 4925fe7..b59ee7c 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -445,7 +445,12 @@ static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) { int ret; int err; - int sockstate; + int sockstate, nonblocking; + + /* just in case the blocking state of the socket has been changed */ + nonblocking = (self->Socket->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); /* Actually negotiate SSL connection */ /* XXX If SSL_do_handshake() returns 0, it's also a failure. */ |