Skip to content

Commit b2247bb

Browse files
[3.15] gh-161076: Ignore setsockopt(TCP_NODELAY) errors in asyncio (GH-161253) (#161301)
gh-161076: Ignore setsockopt(TCP_NODELAY) errors in asyncio (GH-161253) (cherry picked from commit 405f127) Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
1 parent fa0cd47 commit b2247bb

3 files changed

Lines changed: 23 additions & 1 deletion

File tree

‎Lib/asyncio/base_events.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,13 @@ def _set_nodelay(sock):
195195
if (sock.family in {socket.AF_INET, socket.AF_INET6} and
196196
sock.type == socket.SOCK_STREAM and
197197
sock.proto == socket.IPPROTO_TCP):
198-
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
198+
try:
199+
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
200+
except OSError:
201+
# TCP_NODELAY is only a latency optimization. It can fail
202+
# on a connection already reset by the peer (e.g. EINVAL
203+
# on macOS); the error will surface on the next I/O.
204+
pass
199205
else:
200206
def _set_nodelay(sock):
201207
pass

‎Lib/test/test_asyncio/test_base_events.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,6 +2426,17 @@ def test_set_nodelay(self):
24262426
sock.setblocking(False)
24272427
self.check_set_nodelay(sock)
24282428

2429+
@unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
2430+
'need socket.TCP_NODELAY')
2431+
def test_set_nodelay_error(self):
2432+
# gh-161076: a failing setsockopt() must not break transport creation.
2433+
sock = mock.Mock(family=socket.AF_INET, type=socket.SOCK_STREAM,
2434+
proto=socket.IPPROTO_TCP)
2435+
sock.setsockopt.side_effect = OSError(errno.EINVAL, 'Invalid argument')
2436+
base_events._set_nodelay(sock)
2437+
sock.setsockopt.assert_called_once_with(
2438+
socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
2439+
24292440

24302441

24312442
if __name__ == '__main__':
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix :mod:`asyncio` leaving a half-created transport registered with the
2+
event loop and the server when setting ``TCP_NODELAY`` on a socket fails.
3+
Such a failure could make :meth:`asyncio.Server.wait_closed` hang and
4+
prevent new connections from being served. Errors from
5+
``setsockopt(TCP_NODELAY)`` are now ignored.

0 commit comments

Comments
 (0)