summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-02-26 23:24:06 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-02-26 23:24:06 (GMT)
commite93bf7aed201b542334428e6b7bb742cd6c380ec (patch)
treeb68e263d9653972a486f06e86d86d02613bb065a
parent2e7965e8b001826f6381877aa8a9ec60574b3ca3 (diff)
downloadcpython-e93bf7aed201b542334428e6b7bb742cd6c380ec.zip
cpython-e93bf7aed201b542334428e6b7bb742cd6c380ec.tar.gz
cpython-e93bf7aed201b542334428e6b7bb742cd6c380ec.tar.bz2
Issue #11326: Add the missing connect_ex() implementation for SSL sockets,
and make it work for non-blocking connects.
-rw-r--r--Lib/ssl.py30
-rw-r--r--Lib/test/test_ssl.py43
-rw-r--r--Misc/NEWS3
3 files changed, 68 insertions, 8 deletions
diff --git a/Lib/ssl.py b/Lib/ssl.py
index f1a0e45..84aa6dc 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -237,6 +237,7 @@ class SSLSocket(socket):
self._closed = False
self._sslobj = None
+ self._connected = connected
if connected:
# create the SSL object
try:
@@ -430,23 +431,36 @@ class SSLSocket(socket):
finally:
self.settimeout(timeout)
- def connect(self, addr):
- """Connects to remote ADDR, and then wraps the connection in
- an SSL channel."""
+ def _real_connect(self, addr, return_errno):
if self.server_side:
raise ValueError("can't connect in server-side mode")
# Here we assume that the socket is client-side, and not
# connected at the time of the call. We connect it, then wrap it.
- if self._sslobj:
+ if self._connected:
raise ValueError("attempt to connect already-connected SSLSocket!")
- socket.connect(self, addr)
self._sslobj = self.context._wrap_socket(self, False, self.server_hostname)
try:
+ socket.connect(self, addr)
if self.do_handshake_on_connect:
self.do_handshake()
- except:
- self._sslobj = None
- raise
+ except socket_error as e:
+ if return_errno:
+ return e.errno
+ else:
+ self._sslobj = None
+ raise e
+ self._connected = True
+ return 0
+
+ def connect(self, addr):
+ """Connects to remote ADDR, and then wraps the connection in
+ an SSL channel."""
+ self._real_connect(addr, False)
+
+ def connect_ex(self, addr):
+ """Connects to remote ADDR, and then wraps the connection in
+ an SSL channel."""
+ return self._real_connect(addr, True)
def accept(self):
"""Accepts a new connection from a remote client, and returns
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 4ea1a63..3347e9e 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -451,6 +451,49 @@ class NetworkedTests(unittest.TestCase):
finally:
s.close()
+ def test_connect_ex(self):
+ # Issue #11326: check connect_ex() implementation
+ with support.transient_internet("svn.python.org"):
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
+ try:
+ self.assertEqual(0, s.connect_ex(("svn.python.org", 443)))
+ self.assertTrue(s.getpeercert())
+ finally:
+ s.close()
+
+ def test_non_blocking_connect_ex(self):
+ # Issue #11326: non-blocking connect_ex() should allow handshake
+ # to proceed after the socket gets ready.
+ with support.transient_internet("svn.python.org"):
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=SVN_PYTHON_ORG_ROOT_CERT,
+ do_handshake_on_connect=False)
+ try:
+ s.setblocking(False)
+ rc = s.connect_ex(('svn.python.org', 443))
+ self.assertIn(rc, (0, errno.EINPROGRESS))
+ # Wait for connect to finish
+ select.select([], [s], [], 5.0)
+ # Non-blocking handshake
+ while True:
+ try:
+ s.do_handshake()
+ break
+ except ssl.SSLError as err:
+ if err.args[0] == ssl.SSL_ERROR_WANT_READ:
+ select.select([s], [], [], 5.0)
+ elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
+ select.select([], [s], [], 5.0)
+ else:
+ raise
+ # SSL established
+ self.assertTrue(s.getpeercert())
+ finally:
+ s.close()
+
def test_connect_with_context(self):
with support.transient_internet("svn.python.org"):
# Same as test_connect, but with a separately created context
diff --git a/Misc/NEWS b/Misc/NEWS
index 5cad446..bfd73fd 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -35,6 +35,9 @@ Core and Builtins
Library
-------
+- Issue #11326: Add the missing connect_ex() implementation for SSL sockets,
+ and make it work for non-blocking connects.
+
- Issue #11297: Add collections.ChainMap().
- Issue #10755: Add the posix.fdlistdir() function. Patch by Ross Lagerwall.