diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2011-02-26 23:24:06 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2011-02-26 23:24:06 (GMT) |
commit | e93bf7aed201b542334428e6b7bb742cd6c380ec (patch) | |
tree | b68e263d9653972a486f06e86d86d02613bb065a | |
parent | 2e7965e8b001826f6381877aa8a9ec60574b3ca3 (diff) | |
download | cpython-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.py | 30 | ||||
-rw-r--r-- | Lib/test/test_ssl.py | 43 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
3 files changed, 68 insertions, 8 deletions
@@ -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 @@ -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. |