commit ff623565dead20667277cc140dde701f71de0e32
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-05-29T01:43:18Z |
| subject | Trying some Windows AF_UNIX support |
commit ff623565dead20667277cc140dde701f71de0e32
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-05-29T01:43:18Z
Trying some Windows AF_UNIX support
---
src/compat.h | 7 +++++++
src/stream_conn.c | 4 ----
src/stream_listener.c | 44 ++++++++++++++++++++++----------------------
src/stream_route.c | 12 ++++++------
src/tinyproxy.c | 2 +-
tests/test_unix_listeners.py | 34 +++++++++++++++++++---------------
6 files changed, 55 insertions(+), 48 deletions(-)
diff --git a/src/compat.h b/src/compat.h
index 573cd16..f69baee 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -9,6 +9,7 @@
#include <winsock2.h>
#include <ws2tcpip.h>
+#include <afunix.h>
#include <process.h>
#include <direct.h>
#include <errno.h>
@@ -26,6 +27,12 @@
#endif
+#ifdef _WIN32
+#define compat_unlink(path) _unlink(path)
+#else
+#define compat_unlink(path) unlink(path)
+#endif
+
static inline int socket_err_is_retriable(int err)
{
#ifdef _WIN32
diff --git a/src/stream_conn.c b/src/stream_conn.c
index 1f5b4c0..c78c03a 100644
--- a/src/stream_conn.c
+++ b/src/stream_conn.c
@@ -130,9 +130,6 @@ static int connect_upstream(struct bufferevent *bev, const struct endpoint *ep)
}
case ENDPOINT_UNIX:
-#ifdef _WIN32
- return -ENOTSUP;
-#else
{
struct sockaddr_un addr;
@@ -158,7 +155,6 @@ static int connect_upstream(struct bufferevent *bev, const struct endpoint *ep)
return 0;
}
-#endif
default:
return -ENOTSUP;
diff --git a/src/stream_listener.c b/src/stream_listener.c
index d1a6ed1..07e1c33 100644
--- a/src/stream_listener.c
+++ b/src/stream_listener.c
@@ -80,13 +80,6 @@ static int bind_tcp_stream_listener(struct stream_route_ctx *ctx)
return 0;
}
-#ifdef _WIN32
-static int bind_unix_stream_listener(struct stream_route_ctx *ctx)
-{
- (void)ctx;
- return -EAFNOSUPPORT;
-}
-#else
static int bind_unix_stream_listener(struct stream_route_ctx *ctx)
{
const struct endpoint *ep = &ctx->route->listen;
@@ -113,17 +106,14 @@ static int bind_unix_stream_listener(struct stream_route_ctx *ctx)
memcpy(sa.sun_path, path, strlen(path) + 1);
- /*
- * For listener sockets, stale socket files are common after crashes.
- * This is safe enough for our config-driven proxy: if the path exists
- * and is not ours, bind() would fail without this anyway.
- */
- if (unlink(path) < 0 && errno != ENOENT) {
+ if (compat_unlink(path) < 0 && errno != ENOENT) {
+ int err = errno;
+
LOG_ERROR("failed to remove existing unix stream socket",
"line", _LOGV(ctx->route->line_no),
"path", _LOGV(path),
- "err", _LOGV(strerror(errno)));
- return -errno;
+ "err", _LOGV(strerror(err)));
+ return -err;
}
listener = evconnlistener_new_bind(
@@ -135,21 +125,31 @@ static int bind_unix_stream_listener(struct stream_route_ctx *ctx)
(struct sockaddr *)&sa,
sizeof(sa)
);
+
if (listener == NULL) {
- int err = errno;
+ int sockerr = EVUTIL_SOCKET_ERROR();
+ int syserr = errno;
LOG_ERROR("failed to bind unix stream listener",
- "line", _LOGV(ctx->route->line_no),
- "path", _LOGV(path),
- "err", _LOGV(strerror(err)));
-
- return err ? -err : -EIO;
+ "line", _LOGV(ctx->route->line_no),
+ "path", _LOGV(path),
+ "sockerr", _LOGV(sockerr),
+ "sockerrstr", _LOGV(evutil_socket_error_to_string(sockerr)),
+ "errno", _LOGV(syserr),
+ "errnostr", _LOGV(strerror(syserr)));
+
+ if (sockerr != 0) {
+ return -sockerr;
+ }
+ if (syserr != 0) {
+ return -syserr;
+ }
+ return -EIO;
}
ctx->listener = listener;
return 0;
}
-#endif
int bind_stream_listener(struct stream_route_ctx *ctx)
{
diff --git a/src/stream_route.c b/src/stream_route.c
index c901d2a..f80ac48 100644
--- a/src/stream_route.c
+++ b/src/stream_route.c
@@ -4,6 +4,7 @@
#include "klog.h"
#include "stream_route.h"
+#include "compat.h"
#include "worker.h"
#include "route.h"
#include "stream_listener.h"
@@ -39,12 +40,10 @@ int start_stream_route(struct worker *w, const struct route *r,
return 0;
}
-#ifndef _WIN32
static void stop_unix_stream_route(struct stream_route_ctx *ctx)
{
const struct route *r;
const char *path;
- struct stat st;
if (ctx == NULL || ctx->route == NULL) {
return;
@@ -61,6 +60,9 @@ static void stop_unix_stream_route(struct stream_route_ctx *ctx)
return;
}
+#ifndef _WIN32
+ struct stat st;
+
if (lstat(path, &st) < 0) {
if (errno != ENOENT) {
LOG_WARN("failed to inspect unix stream listener socket",
@@ -77,15 +79,15 @@ static void stop_unix_stream_route(struct stream_route_ctx *ctx)
"path", _LOGV(path));
return;
}
+#endif
- if (unlink(path) < 0) {
+ if (compat_unlink(path) < 0 && errno != ENOENT) {
LOG_WARN("failed to remove unix stream listener socket",
"line", _LOGV(r->line_no),
"path", _LOGV(path),
"err", _LOGV(strerror(errno)));
}
}
-#endif
void stop_stream_route(struct stream_route_ctx *ctx)
{
@@ -97,9 +99,7 @@ void stop_stream_route(struct stream_route_ctx *ctx)
evconnlistener_free(ctx->listener);
}
-#ifndef _WIN32
stop_unix_stream_route(ctx);
-#endif
memset(ctx, 0, sizeof(*ctx));
}
diff --git a/src/tinyproxy.c b/src/tinyproxy.c
index 2dc6e3b..fcea91f 100644
--- a/src/tinyproxy.c
+++ b/src/tinyproxy.c
@@ -4,8 +4,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <signal.h>
+#include <unistd.h>
#include "klog.h"
#include "signals.h"
diff --git a/tests/test_unix_listeners.py b/tests/test_unix_listeners.py
index 35cf234..ccae43f 100644
--- a/tests/test_unix_listeners.py
+++ b/tests/test_unix_listeners.py
@@ -2,6 +2,7 @@ import asyncio
import os
import socket
import sys
+import tempfile
from .support import (
LISTEN_HOST,
@@ -10,17 +11,27 @@ from .support import (
run_tinyproxy_with_conf,
)
+def unix_sock_path(name):
+ from pathlib import Path
-UNIX_STREAM_SOCK = "/tmp/test-listen.sock"
-UNIX_BUILTIN_SOCK = "/tmp/test-listen-2.sock"
-UNIX_DGRAM_SOCK = "/tmp/test-listen-dgram.sock"
-UNIX_DGRAM_BUILTIN_SOCK = "/tmp/test-listen-3.sock"
+ if sys.platform == "win32":
+ d = Path("C:/tmp/tinyproxy-tests")
+ d.mkdir(parents=True, exist_ok=True)
+ return str(d / name).replace("\\", "/")
-UNIX_TO_UNIX_LISTEN_SOCK = "/tmp/test-ping.sock"
-UNIX_TO_UNIX_BACKEND_SOCK = "/tmp/test-pong.sock"
+ d = tempfile.mkdtemp(prefix="tinyproxy-")
+ return os.path.join(d, name)
-UNIX_DGRAM_TO_UNIX_DGRAM_LISTEN_SOCK = "/tmp/test-ping-dgram.sock"
-UNIX_DGRAM_TO_UNIX_DGRAM_BACKEND_SOCK = "/tmp/test-pong-dgram.sock"
+UNIX_STREAM_SOCK = unix_sock_path("test-listen.sock")
+UNIX_BUILTIN_SOCK = unix_sock_path("test-listen-2.sock")
+UNIX_DGRAM_SOCK = unix_sock_path("test-listen-dgram.sock")
+UNIX_DGRAM_BUILTIN_SOCK = unix_sock_path("test-listen-3.sock")
+
+UNIX_TO_UNIX_LISTEN_SOCK = unix_sock_path("test-ping.sock")
+UNIX_TO_UNIX_BACKEND_SOCK = unix_sock_path("test-pong.sock")
+
+UNIX_DGRAM_TO_UNIX_DGRAM_LISTEN_SOCK = unix_sock_path("test-ping-dgram.sock")
+UNIX_DGRAM_TO_UNIX_DGRAM_BACKEND_SOCK = unix_sock_path("test-pong-dgram.sock")
def unlink_if_exists(path: str) -> None:
try:
@@ -28,7 +39,6 @@ def unlink_if_exists(path: str) -> None:
except FileNotFoundError:
pass
-
async def echo_handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
try:
while True:
@@ -88,8 +98,6 @@ def unix_dgram_roundtrip(sock_path: str, payload: bytes) -> bytes:
async def test_unix_stream_to_tcp() -> None:
- if sys.platform.startswith("win"):
- raise SkipTest("Unix socks tests are skipped on Windows")
proxy_bin = os.environ.get("TINYPROXY_BIN")
if not proxy_bin:
raise SkipTest("TINYPROXY_BIN is not set")
@@ -138,8 +146,6 @@ async def test_unix_stream_to_tcp() -> None:
async def test_unix_stream_to_builtin_client_addr() -> None:
- if sys.platform.startswith("win"):
- raise SkipTest("Unix socks tests are skipped on Windows")
proxy_bin = os.environ.get("TINYPROXY_BIN")
if not proxy_bin:
raise SkipTest("TINYPROXY_BIN is not set")
@@ -238,8 +244,6 @@ async def test_unix_dgram_to_builtin_client_addr() -> None:
unlink_if_exists(UNIX_DGRAM_BUILTIN_SOCK)
async def test_unix_stream_to_unix_stream() -> None:
- if sys.platform.startswith("win"):
- raise SkipTest("Unix socks tests are skipped on Windows")
proxy_bin = os.environ.get("TINYPROXY_BIN")
if not proxy_bin:
raise SkipTest("TINYPROXY_BIN is not set")