penguin/tinyproxy

An L4 proxy designed to act as a tiny transparent shim

commit f8d28ddf0cef36c6d9c974fd624d310dafa36126

author斟酌 鵬兄 <tgckpg@gmail.com>
date2026-05-26T12:54:12Z
subjectFixing windows build
commit f8d28ddf0cef36c6d9c974fd624d310dafa36126
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2026-05-26T12:54:12Z

    Fixing windows build
---
 .github/workflows/cmake-multi-platform.yml | 30 ++++++++++++++++++++++--------
 Makefile                                   | 23 ++++++++++++++++++-----
 compat_socket.h                            | 23 +++++++++++++++++++++++
 klog.c                                     | 21 +++++++++++++++++++--
 proxy_proto_v2.c                           |  3 +--
 tcp_route.c                                |  2 +-
 tests/test_proxy.py                        |  9 ++++++++-
 7 files changed, 92 insertions(+), 19 deletions(-)

diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml
index 32f2c9d..093dd4b 100644
--- a/.github/workflows/cmake-multi-platform.yml
+++ b/.github/workflows/cmake-multi-platform.yml
@@ -31,8 +31,14 @@ jobs:
 
       - name: Verify static binary
         run: |
+          apk add --no-cache pax-utils
           file bin/tinyproxy
-          ldd bin/tinyproxy && exit 1 || true
+          scanelf -n bin/tinyproxy
+
+          if scanelf -n bin/tinyproxy | grep -q 'lib'; then
+            echo "binary has dynamic library dependencies"
+            exit 1
+          fi
 
       - name: Test
         run: make test
@@ -60,8 +66,14 @@ jobs:
 
       - name: Verify static binary
         run: |
+          apk add --no-cache pax-utils
           file bin/tinyproxy
-          ldd bin/tinyproxy && exit 1 || true
+          scanelf -n bin/tinyproxy
+
+          if scanelf -n bin/tinyproxy | grep -q 'lib'; then
+            echo "binary has dynamic library dependencies"
+            exit 1
+          fi
 
       - name: Test
         run: make test
@@ -89,10 +101,6 @@ jobs:
     runs-on: windows-2022
     continue-on-error: true
 
-    defaults:
-      run:
-        shell: msys2 {0}
-
     steps:
       - uses: actions/checkout@v4
 
@@ -104,11 +112,17 @@ jobs:
           install: >-
             base-devel
             mingw-w64-ucrt-x86_64-gcc
+            mingw-w64-ucrt-x86_64-pkgconf
             mingw-w64-ucrt-x86_64-libevent
             mingw-w64-ucrt-x86_64-python
 
       - name: Build
-        run: make clean all STATIC=0
+        shell: msys2 {0}
+        run: |
+          make clean
+          make all
 
       - name: Test
-        run: make test
+        shell: msys2 {0}
+        run: |
+          make test
diff --git a/Makefile b/Makefile
index ed1d3b5..577e644 100644
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,11 @@ CC ?= cc
 AR ?= ar
 RANLIB ?= ranlib
 STRIP ?= strip
+PKG_CONFIG ?= pkg-config
 
 PROJECT_ROOT := $(CURDIR)
 BIN_DIR := $(CURDIR)/bin
+BUILD_DIR := $(PROJECT_ROOT)/build
 
 SRC := klog.c \
        proxy_proto_v2.c \
@@ -16,9 +18,15 @@ SRC := klog.c \
        file_conf.c \
        tinyproxy.c
 
-BIN := $(BIN_DIR)/tinyproxy
+EXEEXT :=
+WINDOWS_LDLIBS :=
 
-BUILD_DIR := $(PROJECT_ROOT)/build
+ifeq ($(OS),Windows_NT)
+EXEEXT := .exe
+WINDOWS_LDLIBS += -lws2_32
+endif
+
+BIN := $(BIN_DIR)/tinyproxy$(EXEEXT)
 
 LIBEVENT_SRC ?=
 LIBEVENT_PREFIX := $(BUILD_DIR)/libevent-install
@@ -32,6 +40,10 @@ ifeq ($(UNAME_S),Darwin)
 STATIC ?= 0
 LDFLAGS += -Wl,-dead_strip
 TEST_FLAGS := CONCURRENCY=1000 TOTAL=1000 FD_LIMIT=2560
+else ifeq ($(OS),Windows_NT)
+STATIC ?= 0
+LDFLAGS += -Wl,--gc-sections
+TEST_FLAGS :=
 else
 STATIC ?= 1
 LDFLAGS += -Wl,--gc-sections
@@ -46,9 +58,9 @@ PKG_CONFIG_STATIC :=
 endif
 
 ifeq ($(strip $(LIBEVENT_SRC)),)
-LIBEVENT_CPPFLAGS := $(shell pkg-config --cflags libevent_core)
+LIBEVENT_CPPFLAGS := $(shell $(PKG_CONFIG) --cflags libevent_core 2>/dev/null)
 LIBEVENT_LDFLAGS  :=
-LIBEVENT_LDLIBS   := $(shell pkg-config $(PKG_CONFIG_STATIC) --libs libevent_core)
+LIBEVENT_LDLIBS   := $(shell $(PKG_CONFIG) $(PKG_CONFIG_STATIC) --libs libevent_core 2>/dev/null)
 LIBEVENT_DEPS     :=
 else
 LIBEVENT_CPPFLAGS := -I$(LIBEVENT_PREFIX)/include
@@ -60,6 +72,7 @@ endif
 CPPFLAGS += $(LIBEVENT_CPPFLAGS)
 LDFLAGS  += $(LIBEVENT_LDFLAGS)
 LDLIBS   += $(LIBEVENT_LDLIBS)
+LDLIBS   += $(WINDOWS_LDLIBS)
 
 all: $(BIN)
 
@@ -105,4 +118,4 @@ clean-libevent:
 distclean: clean clean-libevent
 	rm -rf $(BUILD_DIR)
 
-.PHONY: all clean clean-libevent distclean test strip
+.PHONY: all clean clean-libevent distclean test strip
\ No newline at end of file
diff --git a/compat_socket.h b/compat_socket.h
new file mode 100644
index 0000000..d261224
--- /dev/null
+++ b/compat_socket.h
@@ -0,0 +1,23 @@
+#ifndef COMPAT_SOCKET_H
+#define COMPAT_SOCKET_H
+
+#ifdef _WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#endif
+
+#endif
diff --git a/klog.c b/klog.c
index cde9f21..28b6b55 100644
--- a/klog.c
+++ b/klog.c
@@ -2,9 +2,24 @@
 
 #include <stdarg.h>
 #include <stdio.h>
-#include <time.h>
+#include <string.h>
 #include <unistd.h>
 
+#ifdef _WIN32
+#include <time.h>
+#else
+#include <time.h>
+#endif
+
+static int localtime_compat(const time_t *t, struct tm *out)
+{
+#ifdef _WIN32
+	return localtime_s(out, t);
+#else
+	return localtime_r(t, out) == NULL ? -1 : 0;
+#endif
+}
+
 static void print_quoted_value(const char *s)
 {
 	if (s == NULL) {
@@ -77,7 +92,9 @@ void log_at(char sev, const char *file, int line, const char *msg, ...)
 	char tbuf[32];
 
 	clock_gettime(CLOCK_REALTIME, &ts);
-	localtime_r(&ts.tv_sec, &tm);
+	if (localtime_compat(&ts.tv_sec, &tm) != 0) {
+		memset(&tm, 0, sizeof(tm));
+	}
 
 	strftime(tbuf, sizeof(tbuf), "%m%d %H:%M:%S", &tm);
 
diff --git a/proxy_proto_v2.c b/proxy_proto_v2.c
index 168afe5..5318de1 100644
--- a/proxy_proto_v2.c
+++ b/proxy_proto_v2.c
@@ -3,9 +3,8 @@
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 
+#include "compat_socket.h"
 #include "proxy_proto_v2.h"
 
 static void put_u16(unsigned char *p, uint16_t v)
diff --git a/tcp_route.c b/tcp_route.c
index 18c273e..42c5164 100644
--- a/tcp_route.c
+++ b/tcp_route.c
@@ -4,7 +4,6 @@
 #include <event2/listener.h>
 #include <event2/util.h>
 
-#include <arpa/inet.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -12,6 +11,7 @@
 
 #include "klog.h"
 #include "file_conf.h"
+#include "compat_socket.h"
 #include "proxy_proto_v2.h"
 #include "route.h"
 #include "tcp_route.h"
diff --git a/tests/test_proxy.py b/tests/test_proxy.py
index 148c660..8c52af3 100755
--- a/tests/test_proxy.py
+++ b/tests/test_proxy.py
@@ -2,18 +2,25 @@
 
 import asyncio
 import os
-import resource
 import signal
 import subprocess
 import sys
 import time
 import tempfile
 
+try:
+	import resource
+except ImportError:
+	resource = None
+
 LISTEN_HOST = "127.0.0.1"
 PROXY_PORT = 31232
 BACKEND_PORT = 41232
 
 def raise_fd_limit(wanted: int) -> None:
+	if resource is None:
+		return
+
 	soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
 
 	if soft >= wanted: