Commit 912f0d66 authored by Antoine Pitrou's avatar Antoine Pitrou

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.
........
parent cd6815c9
...@@ -113,12 +113,7 @@ class SSLSocket(socket): ...@@ -113,12 +113,7 @@ class SSLSocket(socket):
keyfile, certfile, keyfile, certfile,
cert_reqs, ssl_version, ca_certs) cert_reqs, ssl_version, ca_certs)
if do_handshake_on_connect: if do_handshake_on_connect:
timeout = self.gettimeout() self.do_handshake()
try:
self.settimeout(None)
self.do_handshake()
finally:
self.settimeout(timeout)
self.keyfile = keyfile self.keyfile = keyfile
self.certfile = certfile self.certfile = certfile
self.cert_reqs = cert_reqs self.cert_reqs = cert_reqs
......
...@@ -457,7 +457,8 @@ else: ...@@ -457,7 +457,8 @@ else:
asyncore.dispatcher_with_send.__init__(self, conn) asyncore.dispatcher_with_send.__init__(self, conn)
self.socket = ssl.wrap_socket(conn, server_side=True, self.socket = ssl.wrap_socket(conn, server_side=True,
certfile=certfile, certfile=certfile,
do_handshake_on_connect=True) do_handshake_on_connect=False)
self._ssl_accepting = True
def readable(self): def readable(self):
if isinstance(self.socket, ssl.SSLSocket): if isinstance(self.socket, ssl.SSLSocket):
...@@ -465,9 +466,28 @@ else: ...@@ -465,9 +466,28 @@ else:
self.handle_read_event() self.handle_read_event()
return True 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): def handle_read(self):
data = self.recv(1024) if self._ssl_accepting:
self.send(data.lower()) self._do_ssl_handshake()
else:
data = self.recv(1024)
self.send(data.lower())
def handle_close(self): def handle_close(self):
self.close() self.close()
...@@ -1226,6 +1246,61 @@ else: ...@@ -1226,6 +1246,61 @@ else:
server.stop() server.stop()
server.join() 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): def test_main(verbose=False):
if skip_expected: if skip_expected:
......
...@@ -33,6 +33,12 @@ Core and Builtins ...@@ -33,6 +33,12 @@ Core and Builtins
Library 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 - Issue #5238: Calling makefile() on an SSL object would prevent the
underlying socket from being closed until all objects get truely destroyed. underlying socket from being closed until all objects get truely destroyed.
......
...@@ -445,7 +445,12 @@ static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) ...@@ -445,7 +445,12 @@ static PyObject *PySSL_SSLdo_handshake(PySSLObject *self)
{ {
int ret; int ret;
int err; 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 */ /* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */ /* XXX If SSL_do_handshake() returns 0, it's also a failure. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment