aboutsummaryrefslogtreecommitdiffstats
path: root/python/gevent/socket.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/gevent/socket.py')
-rw-r--r--python/gevent/socket.py71
1 files changed, 47 insertions, 24 deletions
diff --git a/python/gevent/socket.py b/python/gevent/socket.py
index 50f7a59..1bb039e 100644
--- a/python/gevent/socket.py
+++ b/python/gevent/socket.py
@@ -13,8 +13,8 @@ as well as the constants from the :mod:`socket` module are imported into this mo
# Our import magic sadly makes this warning useless
# pylint: disable=undefined-variable
-import sys
from gevent._compat import PY3
+from gevent._compat import exc_clear
from gevent._util import copy_globals
@@ -60,21 +60,31 @@ except AttributeError:
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
- """Connect to *address* and return the socket object.
+ """
+ create_connection(address, timeout=None, source_address=None) -> socket
+
+ Connect to *address* and return the :class:`gevent.socket.socket`
+ object.
- Convenience function. Connect to *address* (a 2-tuple ``(host,
- port)``) and return the socket object. Passing the optional
+ Convenience function. Connect to *address* (a 2-tuple ``(host,
+ port)``) and return the socket object. Passing the optional
*timeout* parameter will set the timeout on the socket instance
- before attempting to connect. If no *timeout* is supplied, the
- global default timeout setting returned by :func:`getdefaulttimeout`
- is used. If *source_address* is set it must be a tuple of (host, port)
- for the socket to bind as a source address before making the connection.
- A host of '' or port 0 tells the OS to use the default.
+ before attempting to connect. If no *timeout* is supplied, the
+ global default timeout setting returned by
+ :func:`getdefaulttimeout` is used. If *source_address* is set it
+ must be a tuple of (host, port) for the socket to bind as a source
+ address before making the connection. A host of '' or port 0 tells
+ the OS to use the default.
"""
host, port = address
- err = None
- for res in getaddrinfo(host, port, 0 if has_ipv6 else AF_INET, SOCK_STREAM):
+ # getaddrinfo is documented as returning a list, but our interface
+ # is pluggable, so be sure it does.
+ addrs = list(getaddrinfo(host, port, 0, SOCK_STREAM))
+ if not addrs:
+ raise error("getaddrinfo returns an empty list")
+
+ for res in addrs:
af, socktype, proto, _, sa = res
sock = None
try:
@@ -84,21 +94,34 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
if source_address:
sock.bind(source_address)
sock.connect(sa)
- return sock
- except error as ex:
- # without exc_clear(), if connect() fails once, the socket is referenced by the frame in exc_info
- # and the next bind() fails (see test__socket.TestCreateConnection)
- # that does not happen with regular sockets though, because _socket.socket.connect() is a built-in.
- # this is similar to "getnameinfo loses a reference" failure in test_socket.py
- if not PY3:
- sys.exc_clear() # pylint:disable=no-member,useless-suppression
+ except error:
if sock is not None:
sock.close()
- err = ex
- if err is not None:
- raise err # pylint:disable=raising-bad-type
- else:
- raise error("getaddrinfo returns an empty list")
+ sock = None
+ if res is addrs[-1]:
+ raise
+ # without exc_clear(), if connect() fails once, the socket
+ # is referenced by the frame in exc_info and the next
+ # bind() fails (see test__socket.TestCreateConnection)
+ # that does not happen with regular sockets though,
+ # because _socket.socket.connect() is a built-in. this is
+ # similar to "getnameinfo loses a reference" failure in
+ # test_socket.py
+ exc_clear()
+ except BaseException:
+ # Things like GreenletExit, Timeout and KeyboardInterrupt.
+ # These get raised immediately, being sure to
+ # close the socket
+ if sock is not None:
+ sock.close()
+ sock = None
+ raise
+ else:
+ try:
+ return sock
+ finally:
+ sock = None
+
# This is promised to be in the __all__ of the _source, but, for circularity reasons,
# we implement it in this module. Mostly for documentation purposes, put it