Skip to content

Commit 9791123

Browse files
asvetlovmiss-islington
authored andcommitted
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 d16d33a commit 9791123

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
@@ -193,7 +193,13 @@ def _set_nodelay(sock):
193193
if (sock.family in {socket.AF_INET, socket.AF_INET6} and
194194
sock.type == socket.SOCK_STREAM and
195195
sock.proto == socket.IPPROTO_TCP):
196-
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
196+
try:
197+
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
198+
except OSError:
199+
# TCP_NODELAY is only a latency optimization. It can fail
200+
# on a connection already reset by the peer (e.g. EINVAL
201+
# on macOS); the error will surface on the next I/O.
202+
pass
197203
else:
198204
def _set_nodelay(sock):
199205
pass

‎Lib/test/test_asyncio/test_base_events.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2330,6 +2330,17 @@ def test_set_nodelay(self):
23302330
sock.setblocking(False)
23312331
self.check_set_nodelay(sock)
23322332

2333+
@unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
2334+
'need socket.TCP_NODELAY')
2335+
def test_set_nodelay_error(self):
2336+
# gh-161076: a failing setsockopt() must not break transport creation.
2337+
sock = mock.Mock(family=socket.AF_INET, type=socket.SOCK_STREAM,
2338+
proto=socket.IPPROTO_TCP)
2339+
sock.setsockopt.side_effect = OSError(errno.EINVAL, 'Invalid argument')
2340+
base_events._set_nodelay(sock)
2341+
sock.setsockopt.assert_called_once_with(
2342+
socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
2343+
23332344

23342345

23352346
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)