Skip to content

Commit 696dcea

Browse files
authored
Merge pull request RustPython#5255 from youknowone/lib-socket
Update socket and test from CPython 3.12.2
2 parents ade45c2 + 9e2f6bd commit 696dcea

File tree

2 files changed

+324
-97
lines changed

2 files changed

+324
-97
lines changed

Lib/socket.py

+25-17
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
socketpair() -- create a pair of new socket objects [*]
1414
fromfd() -- create a socket object from an open file descriptor [*]
1515
send_fds() -- Send file descriptor to the socket.
16-
recv_fds() -- Recieve file descriptors from the socket.
16+
recv_fds() -- Receive file descriptors from the socket.
1717
fromshare() -- create a socket object from data received from socket.share() [*]
1818
gethostname() -- return the current hostname
1919
gethostbyname() -- map a hostname to its IP number
@@ -28,6 +28,7 @@
2828
socket.setdefaulttimeout() -- set the default timeout value
2929
create_connection() -- connects to an address, with an optional timeout and
3030
optional source address.
31+
create_server() -- create a TCP socket and bind it to a specified address.
3132
3233
[*] not available on all platforms!
3334
@@ -122,7 +123,7 @@ def _intenum_converter(value, enum_klass):
122123
errorTab[10014] = "A fault occurred on the network??" # WSAEFAULT
123124
errorTab[10022] = "An invalid operation was attempted."
124125
errorTab[10024] = "Too many open files."
125-
errorTab[10035] = "The socket operation would block"
126+
errorTab[10035] = "The socket operation would block."
126127
errorTab[10036] = "A blocking operation is already in progress."
127128
errorTab[10037] = "Operation already in progress."
128129
errorTab[10038] = "Socket operation on nonsocket."
@@ -254,17 +255,18 @@ def __repr__(self):
254255
self.type,
255256
self.proto)
256257
if not closed:
258+
# getsockname and getpeername may not be available on WASI.
257259
try:
258260
laddr = self.getsockname()
259261
if laddr:
260262
s += ", laddr=%s" % str(laddr)
261-
except error:
263+
except (error, AttributeError):
262264
pass
263265
try:
264266
raddr = self.getpeername()
265267
if raddr:
266268
s += ", raddr=%s" % str(raddr)
267-
except error:
269+
except (error, AttributeError):
268270
pass
269271
s += '>'
270272
return s
@@ -380,7 +382,7 @@ def _sendfile_use_sendfile(self, file, offset=0, count=None):
380382
if timeout and not selector_select(timeout):
381383
raise TimeoutError('timed out')
382384
if count:
383-
blocksize = count - total_sent
385+
blocksize = min(count - total_sent, blocksize)
384386
if blocksize <= 0:
385387
break
386388
try:
@@ -783,11 +785,11 @@ def getfqdn(name=''):
783785
784786
First the hostname returned by gethostbyaddr() is checked, then
785787
possibly existing aliases. In case no FQDN is available and `name`
786-
was given, it is returned unchanged. If `name` was empty or '0.0.0.0',
788+
was given, it is returned unchanged. If `name` was empty, '0.0.0.0' or '::',
787789
hostname from gethostname() is returned.
788790
"""
789791
name = name.strip()
790-
if not name or name == '0.0.0.0':
792+
if not name or name in ('0.0.0.0', '::'):
791793
name = gethostname()
792794
try:
793795
hostname, aliases, ipaddrs = gethostbyaddr(name)
@@ -806,7 +808,7 @@ def getfqdn(name=''):
806808
_GLOBAL_DEFAULT_TIMEOUT = object()
807809

808810
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
809-
source_address=None):
811+
source_address=None, *, all_errors=False):
810812
"""Connect to *address* and return the socket object.
811813
812814
Convenience function. Connect to *address* (a 2-tuple ``(host,
@@ -816,11 +818,13 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
816818
global default timeout setting returned by :func:`getdefaulttimeout`
817819
is used. If *source_address* is set it must be a tuple of (host, port)
818820
for the socket to bind as a source address before making the connection.
819-
A host of '' or port 0 tells the OS to use the default.
821+
A host of '' or port 0 tells the OS to use the default. When a connection
822+
cannot be created, raises the last error if *all_errors* is False,
823+
and an ExceptionGroup of all errors if *all_errors* is True.
820824
"""
821825

822826
host, port = address
823-
err = None
827+
exceptions = []
824828
for res in getaddrinfo(host, port, 0, SOCK_STREAM):
825829
af, socktype, proto, canonname, sa = res
826830
sock = None
@@ -832,20 +836,24 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
832836
sock.bind(source_address)
833837
sock.connect(sa)
834838
# Break explicitly a reference cycle
835-
err = None
839+
exceptions.clear()
836840
return sock
837841

838-
except error as _:
839-
err = _
842+
except error as exc:
843+
if not all_errors:
844+
exceptions.clear() # raise only the last error
845+
exceptions.append(exc)
840846
if sock is not None:
841847
sock.close()
842848

843-
if err is not None:
849+
if len(exceptions):
844850
try:
845-
raise err
851+
if not all_errors:
852+
raise exceptions[0]
853+
raise ExceptionGroup("create_connection failed", exceptions)
846854
finally:
847855
# Break explicitly a reference cycle
848-
err = None
856+
exceptions.clear()
849857
else:
850858
raise error("getaddrinfo returns an empty list")
851859

@@ -902,7 +910,7 @@ def create_server(address, *, family=AF_INET, backlog=None, reuse_port=False,
902910
# address, effectively preventing this one from accepting
903911
# connections. Also, it may set the process in a state where
904912
# it'll no longer respond to any signals or graceful kills.
905-
# See: msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx
913+
# See: https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
906914
if os.name not in ('nt', 'cygwin') and \
907915
hasattr(_socket, 'SO_REUSEADDR'):
908916
try:

0 commit comments

Comments
 (0)