commit c06b61a44ad84fd2fe61f49558d72c836c480fec
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-05-26T16:32:41Z |
| subject | Fixed windows compat |
commit c06b61a44ad84fd2fe61f49558d72c836c480fec
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-05-26T16:32:41Z
Fixed windows compat
---
compat_socket.h | 9 +++++++
proxy_proto_v2.c | 18 ++++++++-----
tests/support.py | 8 ------
tests/test_udp_proxy_v2.py | 65 ++++++++++++++++++++++++++++++----------------
udp_route.c | 10 +++----
5 files changed, 67 insertions(+), 43 deletions(-)
diff --git a/compat_socket.h b/compat_socket.h
index d261224..b981691 100644
--- a/compat_socket.h
+++ b/compat_socket.h
@@ -20,4 +20,13 @@
#endif
+static inline int socket_err_is_retriable(int err)
+{
+#ifdef _WIN32
+ return err == WSAEWOULDBLOCK || err == WSAEINTR;
+#else
+ return err == EAGAIN || err == EWOULDBLOCK || err == EINTR;
+#endif
+}
+
#endif
diff --git a/proxy_proto_v2.c b/proxy_proto_v2.c
index 5318de1..3a60c99 100644
--- a/proxy_proto_v2.c
+++ b/proxy_proto_v2.c
@@ -24,13 +24,17 @@ int proxy_v2_build(
size_t *out_len
) {
unsigned char fam_proto;
- uint16_t addr_len;
+ size_t addr_len;
unsigned char *p;
if (buf == NULL || src == NULL || dst == NULL || out_len == NULL) {
return -EINVAL;
}
+ if (src_len < 0 || dst_len < 0) {
+ return -EINVAL;
+ }
+
if (src->sa_family != dst->sa_family) {
return -EAFNOSUPPORT;
}
@@ -45,8 +49,8 @@ int proxy_v2_build(
switch (src->sa_family) {
case AF_INET:
- if (src_len < sizeof(struct sockaddr_in) ||
- dst_len < sizeof(struct sockaddr_in)) {
+ if ((size_t)src_len < sizeof(struct sockaddr_in) ||
+ (size_t)dst_len < sizeof(struct sockaddr_in)) {
return -EINVAL;
}
@@ -59,7 +63,7 @@ int proxy_v2_build(
memcpy(buf, PROXY_V2_SIG, 12);
buf[12] = PP2_VERSION_CMD_PROXY;
buf[13] = PP2_FAM_INET | fam_proto;
- put_u16(buf + 14, addr_len);
+ put_u16(buf + 14, (uint16_t)addr_len);
p = buf + 16;
@@ -82,8 +86,8 @@ int proxy_v2_build(
return 0;
case AF_INET6:
- if (src_len < sizeof(struct sockaddr_in6) ||
- dst_len < sizeof(struct sockaddr_in6)) {
+ if ((size_t)src_len < sizeof(struct sockaddr_in6) ||
+ (size_t)dst_len < sizeof(struct sockaddr_in6)) {
return -EINVAL;
}
@@ -96,7 +100,7 @@ int proxy_v2_build(
memcpy(buf, PROXY_V2_SIG, 12);
buf[12] = PP2_VERSION_CMD_PROXY;
buf[13] = PP2_FAM_INET6 | fam_proto;
- put_u16(buf + 14, addr_len);
+ put_u16(buf + 14, (uint16_t)addr_len);
p = buf + 16;
diff --git a/tests/support.py b/tests/support.py
index 6e031df..8a1bd37 100644
--- a/tests/support.py
+++ b/tests/support.py
@@ -48,7 +48,6 @@ class UDPClientProtocol(asyncio.DatagramProtocol):
class UDPProxyV2EchoServerProtocol(asyncio.DatagramProtocol):
def __init__(self) -> None:
self.transport: asyncio.DatagramTransport | None = None
- self.seen: asyncio.Future[None] | None = None
self.error: Exception | None = None
self.last_src: tuple[str, int] | None = None
self.last_dst: tuple[str, int] | None = None
@@ -56,8 +55,6 @@ class UDPProxyV2EchoServerProtocol(asyncio.DatagramProtocol):
def connection_made(self, transport: asyncio.BaseTransport) -> None:
self.transport = transport # type: ignore[assignment]
- loop = asyncio.get_running_loop()
- self.seen = loop.create_future()
def datagram_received(self, data: bytes, addr) -> None:
self.last_raw = data
@@ -66,16 +63,11 @@ class UDPProxyV2EchoServerProtocol(asyncio.DatagramProtocol):
src, dst, payload = parse_proxy_v2_udp4_packet(data)
except Exception as exc:
self.error = exc
- if self.seen is not None and not self.seen.done():
- self.seen.set_exception(exc)
return
self.last_src = src
self.last_dst = dst
- if self.seen is not None and not self.seen.done():
- self.seen.set_result(None)
-
if self.transport is not None:
self.transport.sendto(payload, addr)
diff --git a/tests/test_udp_proxy_v2.py b/tests/test_udp_proxy_v2.py
index 7c26a67..fd81ac2 100644
--- a/tests/test_udp_proxy_v2.py
+++ b/tests/test_udp_proxy_v2.py
@@ -2,7 +2,6 @@ import asyncio
import os
from .support import (
- BACKEND_PORT,
LISTEN_HOST,
PROXY_PORT,
SkipTest,
@@ -11,6 +10,9 @@ from .support import (
udp_proxy_roundtrip,
)
+UDP_PROXY_V2_BACKEND_PORT = 41234
+
+
async def test_tinyproxy_sends_proxy_v2_for_udp() -> None:
proxy_bin = os.environ.get("TINYPROXY_BIN")
if not proxy_bin:
@@ -18,11 +20,14 @@ async def test_tinyproxy_sends_proxy_v2_for_udp() -> None:
conf_text = (
f"{LISTEN_HOST}:{PROXY_PORT} "
- f"{LISTEN_HOST}:{BACKEND_PORT} "
+ f"{LISTEN_HOST}:{UDP_PROXY_V2_BACKEND_PORT} "
f"udp proxy_v2\n"
)
- async with run_udp_proxy_v2_echo_backend(LISTEN_HOST, BACKEND_PORT) as backend:
+ async with run_udp_proxy_v2_echo_backend(
+ LISTEN_HOST,
+ UDP_PROXY_V2_BACKEND_PORT,
+ ) as backend:
async with run_tinyproxy_with_conf(
proxy_bin=proxy_bin,
conf_text=conf_text,
@@ -32,32 +37,46 @@ async def test_tinyproxy_sends_proxy_v2_for_udp() -> None:
):
payload = b"hello udp proxy v2\n"
- echo_task = asyncio.create_task(udp_proxy_roundtrip(payload, timeout=3.0))
-
try:
- got = await echo_task
- except TimeoutError:
- if backend.error is not None:
- raw = backend.last_raw.hex(" ") if backend.last_raw else "<none>"
- raise AssertionError(
- f"backend failed to parse UDP PROXY v2: {backend.error}; raw={raw}"
- ) from backend.error
-
+ got = await udp_proxy_roundtrip(payload, timeout=3.0)
+ except TimeoutError as exc:
raw = backend.last_raw.hex(" ") if backend.last_raw else "<none>"
raise AssertionError(
- f"timed out waiting for UDP proxy v2 echo; backend raw={raw}"
- )
+ "timed out waiting for UDP proxy-v2 echo; "
+ f"backend_error={backend.error!r}; "
+ f"backend_last_src={backend.last_src!r}; "
+ f"backend_last_dst={backend.last_dst!r}; "
+ f"backend_raw={raw}"
+ ) from exc
+
+ raw = backend.last_raw.hex(" ") if backend.last_raw else "<none>"
- assert got == payload, f"udp proxy v2 roundtrip mismatch: {got!r}"
+ assert backend.error is None, (
+ f"backend failed to parse PROXY v2: {backend.error!r}; raw={raw}"
+ )
+ assert got == payload, (
+ f"udp proxy-v2 roundtrip mismatch: got={got!r} expected={payload!r}; "
+ f"backend_raw={raw}"
+ )
+ assert backend.last_src is not None, (
+ f"backend did not record PROXY v2 source; raw={raw}"
+ )
+ assert backend.last_dst is not None, (
+ f"backend did not record PROXY v2 destination; raw={raw}"
+ )
- assert backend.error is None, f"backend failed to parse PROXY v2: {backend.error}"
- assert backend.last_src is not None, "backend did not record PROXY v2 source"
- assert backend.last_dst is not None, "backend did not record PROXY v2 destination"
+ assert backend.last_src[0] == LISTEN_HOST, (
+ f"bad proxy-v2 src addr: got={backend.last_src!r}; raw={raw}"
+ )
+ assert backend.last_dst[0] == LISTEN_HOST, (
+ f"bad proxy-v2 dst addr: got={backend.last_dst!r}; raw={raw}"
+ )
+ assert backend.last_dst[1] == PROXY_PORT, (
+ f"bad proxy-v2 dst port: got={backend.last_dst!r}; "
+ f"expected_port={PROXY_PORT}; raw={raw}"
+ )
- assert backend.last_src[0] == LISTEN_HOST
- assert backend.last_dst[0] == LISTEN_HOST
- assert backend.last_dst[1] == PROXY_PORT
TESTS = [
("test_tinyproxy_sends_proxy_v2_for_udp", test_tinyproxy_sends_proxy_v2_for_udp),
-]
+]
\ No newline at end of file
diff --git a/udp_route.c b/udp_route.c
index f44bf5a..4a4fc6e 100644
--- a/udp_route.c
+++ b/udp_route.c
@@ -134,11 +134,11 @@ static void upstream_read_cb(evutil_socket_t fd, short events, void *arg)
if (n < 0) {
int err = EVUTIL_SOCKET_ERROR();
- if (err == EAGAIN || err == EWOULDBLOCK) {
+ if (socket_err_is_retriable(err)) {
return;
}
- LOG_ERROR("udp upstream recv failed",
+ LOG_ERROR("udp recvfrom failed",
"err", _LOGV(evutil_socket_error_to_string(err))
);
return;
@@ -343,11 +343,11 @@ static void listen_read_cb(evutil_socket_t fd, short events, void *arg)
if (n < 0) {
int err = EVUTIL_SOCKET_ERROR();
- if (err == EAGAIN || err == EWOULDBLOCK) {
+ if (socket_err_is_retriable(err)) {
return;
}
- LOG_ERROR("udp recvfrom failed",
+ LOG_ERROR("udp upstream recv failed",
"err", _LOGV(evutil_socket_error_to_string(err))
);
return;
@@ -370,7 +370,7 @@ static void listen_read_cb(evutil_socket_t fd, short events, void *arg)
int rc = send_udp_payload_to_upstream(c, buf, (size_t)n);
if (rc < 0) {
LOG_ERROR("udp send to upstream failed",
- "err", _LOGV(strerror(-rc))
+ "err", _LOGV(evutil_socket_error_to_string(-rc))
);
return;
}