diff --git a/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py b/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py index b935320c..b6e8e123 100644 --- a/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py +++ b/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py @@ -480,6 +480,10 @@ def start_server(port): pydev_log.info(msg) new_socket, _addr = s.accept() + try: + new_socket.setsockopt(socket_module.IPPROTO_TCP, socket_module.TCP_NODELAY, 1) + except (AttributeError, OSError): + pass # May not be available everywhere. pydev_log.info("Connection accepted") # closing server socket is not necessary but we don't need it s.close() @@ -525,6 +529,10 @@ def start_client(host, port): s.setsockopt(socket_module.IPPROTO_TCP, socket_module.TCP_KEEPCNT, 5) except (AttributeError, OSError): pass # May not be available everywhere. + try: + s.setsockopt(socket_module.IPPROTO_TCP, socket_module.TCP_NODELAY, 1) + except (AttributeError, OSError): + pass # May not be available everywhere. try: # 10 seconds default timeout diff --git a/src/debugpy/_vendored/pydevd/tests_python/test_pydevd_comm.py b/src/debugpy/_vendored/pydevd/tests_python/test_pydevd_comm.py new file mode 100644 index 00000000..8a62544c --- /dev/null +++ b/src/debugpy/_vendored/pydevd/tests_python/test_pydevd_comm.py @@ -0,0 +1,68 @@ +from unittest import mock + +import pytest + +from _pydevd_bundle import pydevd_comm + + +def start_client(monkeypatch, sock): + monkeypatch.setattr(pydevd_comm, "socket", mock.Mock(return_value=sock)) + monkeypatch.setattr( + pydevd_comm.socket_module, + "getaddrinfo", + lambda *_: [(pydevd_comm.AF_INET, pydevd_comm.SOCK_STREAM, 0, "", ("127.0.0.1", 5678))], + ) + assert pydevd_comm.start_client("localhost", 5678) is sock + sock.connect.assert_called_once_with(("localhost", 5678)) + + +def test_start_client_sets_tcp_nodelay(monkeypatch): + sock = mock.Mock() + monkeypatch.setattr(pydevd_comm.socket_module, "TCP_NODELAY", mock.sentinel.tcp_nodelay, raising=False) + + start_client(monkeypatch, sock) + sock.setsockopt.assert_any_call(pydevd_comm.socket_module.IPPROTO_TCP, mock.sentinel.tcp_nodelay, 1) + + +@pytest.mark.parametrize("error", [AttributeError, OSError]) +def test_start_client_ignores_tcp_nodelay_error(monkeypatch, error): + sock = mock.Mock() + sock.setsockopt.side_effect = error + monkeypatch.setattr(pydevd_comm.socket_module, "TCP_NODELAY", mock.sentinel.tcp_nodelay, raising=False) + + start_client(monkeypatch, sock) + sock.setsockopt.assert_any_call(pydevd_comm.socket_module.IPPROTO_TCP, mock.sentinel.tcp_nodelay, 1) + + +def test_start_server_sets_tcp_nodelay(monkeypatch): + server, accepted = mock.Mock(), mock.Mock() + address = ("127.0.0.1", 5678) + server.configure_mock(**{"accept.return_value": (accepted, address), "getsockname.return_value": address}) + monkeypatch.setattr(pydevd_comm, "create_server_socket", mock.Mock(return_value=server)) + monkeypatch.setattr(pydevd_comm.socket_module, "TCP_NODELAY", mock.sentinel.tcp_nodelay, raising=False) + assert pydevd_comm.start_server(0) is accepted + accepted.setsockopt.assert_called_once_with(pydevd_comm.socket_module.IPPROTO_TCP, mock.sentinel.tcp_nodelay, 1) + + +@pytest.mark.parametrize("error", [AttributeError, OSError]) +def test_start_server_ignores_tcp_nodelay_error(monkeypatch, error): + server, accepted = mock.Mock(), mock.Mock() + address = ("127.0.0.1", 5678) + server.configure_mock(**{"accept.return_value": (accepted, address), "getsockname.return_value": address}) + accepted.setsockopt.side_effect = error + monkeypatch.setattr(pydevd_comm, "create_server_socket", mock.Mock(return_value=server)) + monkeypatch.setattr(pydevd_comm.socket_module, "TCP_NODELAY", mock.sentinel.tcp_nodelay, raising=False) + + assert pydevd_comm.start_server(0) is accepted + accepted.setsockopt.assert_called_once_with(pydevd_comm.socket_module.IPPROTO_TCP, mock.sentinel.tcp_nodelay, 1) + + +def test_startup_ignores_missing_tcp_nodelay(monkeypatch): + monkeypatch.delattr(pydevd_comm.socket_module, "TCP_NODELAY", raising=False) + start_client(monkeypatch, mock.Mock()) + + server, accepted = mock.Mock(), mock.Mock() + address = ("127.0.0.1", 5678) + server.configure_mock(**{"accept.return_value": (accepted, address), "getsockname.return_value": address}) + monkeypatch.setattr(pydevd_comm, "create_server_socket", mock.Mock(return_value=server)) + assert pydevd_comm.start_server(0) is accepted