Update find_unused_port to Python 3.9 version
-# These helpers are copied from test_support.py in the Python 2.7 standard
+# These helpers are copied from test/support/socket_helper.py in the Python 3.9 standard
# library test suite.
import socket
@@ -36,7 +36,7 @@ def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM):
the SO_REUSEADDR socket option having different semantics on Windows versus
Unix/Linux. On Unix, you can't have two AF_INET SOCK_STREAM sockets bind,
listen and then accept connections on identical host/ports. An EADDRINUSE
- socket.error will be raised at some point (depending on the platform and
+ OSError will be raised at some point (depending on the platform and
the order bind and listen were called on each socket).
However, on Windows, if SO_REUSEADDR is set on the sockets, no EADDRINUSE
@@ -63,9 +63,9 @@ def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM):
other process when we close and delete our temporary socket but before our
calling code has a chance to bind the returned port. We can deal with this
issue if/when we come across it."""
- tempsock = socket.socket(family, socktype)
+
+ with socket.socket(family, socktype) as tempsock:
port = bind_port(tempsock)
- tempsock.close()
del tempsock
return port
@@ -84,6 +84,7 @@ def bind_port(sock, host=HOST):
on Windows), it will be set on the socket. This will prevent anyone else
from bind()'ing to our host/port for the duration of the test.
"""
+
if sock.family == socket.AF_INET and sock.type == socket.SOCK_STREAM:
if hasattr(socket, "SO_REUSEADDR"):
if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) == 1:
@@ -92,11 +93,17 @@ def bind_port(sock, host=HOST):
"socket option on TCP/IP sockets!"
)
if hasattr(socket, "SO_REUSEPORT"):
+ try:
if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT) == 1:
raise ValueError(
"tests should never set the SO_REUSEPORT "
"socket option on TCP/IP sockets!"
)
+ except OSError:
+ # Python's socket module was compiled using modern headers
+ # thus defining SO_REUSEPORT but this process is running
+ # under an older kernel that does not support SO_REUSEPORT.
+ pass
if hasattr(socket, "SO_EXCLUSIVEADDRUSE"):
sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
