From 18d3ff101a686b32c31cf777462fdaf18551a973 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Tue, 13 Oct 2026 12:57:50 +0300 Subject: [PATCH] tests: run the half-close case on Windows again The previous commit lets a half-closed client be written to on Windows too, so the case left out there is back. This reverts commit 5d1cdf8. Co-Authored-By: Claude Opus 5.5 --- tests/cases/portmap.py | 71 +++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/tests/cases/portmap.py b/tests/cases/portmap.py index dcee7c1..d456192 100644 --- a/tests/cases/portmap.py +++ b/tests/cases/portmap.py @@ -1,7 +1,6 @@ """The port mappers: tcppm forwards a TCP port, udppm a UDP one.""" import socket -import sys import threading import time @@ -65,44 +64,38 @@ def run(t): t.stop_all() - # WSAPoll reports a hang-up once the peer has half-closed, not once - # both sides are shut down as poll() does elsewhere, and sockmap() takes - # it for a client it can no longer write to: not covered there yet. - if sys.platform == "win32": - t.skip("a half-closed client gets the whole answer (not on Windows)") - else: - # A client which shuts down its sending side still gets the whole answer, - # even when it reads slowly: the server has finished and closed by then, - # and the rest of the answer waits in the proxy's buffer and the kernel's. - listener = socket.socket() - listener.bind(("127.0.0.1", 0)) - listener.listen(1) - threading.Thread(target=halfclose_origin, args=(listener,), daemon=True).start() - halfclosed = t.free_port() - t.start("portmap_halfclose", f""" - log - auth none - tcppm {halfclosed} 127.0.0.1 {listener.getsockname()[1]} - """, ports=[halfclosed]) - s = socket.socket() - s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768) - s.settimeout(30) - got = 0 - try: - s.connect(("127.0.0.1", halfclosed)) - s.sendall(b"request") - s.shutdown(socket.SHUT_WR) - time.sleep(1) - while True: - d = s.recv(65536) - if not d: - break - got += len(d) - except OSError: - pass - s.close() - listener.close() - t.eq(HALFCLOSE_SIZE, got, "a half-closed client reading slowly gets the whole answer") + # A client which shuts down its sending side still gets the whole answer, + # even when it reads slowly: the server has finished and closed by then, + # and the rest of the answer waits in the proxy's buffer and the kernel's. + listener = socket.socket() + listener.bind(("127.0.0.1", 0)) + listener.listen(1) + threading.Thread(target=halfclose_origin, args=(listener,), daemon=True).start() + halfclosed = t.free_port() + t.start("portmap_halfclose", f""" + log + auth none + tcppm {halfclosed} 127.0.0.1 {listener.getsockname()[1]} + """, ports=[halfclosed]) + s = socket.socket() + s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768) + s.settimeout(30) + got = 0 + try: + s.connect(("127.0.0.1", halfclosed)) + s.sendall(b"request") + s.shutdown(socket.SHUT_WR) + time.sleep(1) + while True: + d = s.recv(65536) + if not d: + break + got += len(d) + except OSError: + pass + s.close() + listener.close() + t.eq(HALFCLOSE_SIZE, got, "a half-closed client reading slowly gets the whole answer") t.stop_all()