From 118d2e8ddfbe4d150aaeff79bf8811016b9e125d Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 11 Sep 2026 00:15:22 +0800 Subject: [PATCH] Use portable stdio formats and finish build profile integration --- .github/workflows/build.yml | 2 +- .github/workflows/portability.yml | 5 +++ CMakeLists.txt | 2 +- CMakePresets.json | 2 +- cmake/ProjectOptions.cmake | 2 +- docs/modernization.md | 67 ++++++++++++------------------- src/udprelay.c | 8 ++-- src/utils.h | 7 +--- 8 files changed, 39 insertions(+), 56 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 99a83dfe..34056199 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: sudo apt-get update sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev sudo apt-get install -y --no-install-recommends \ - build-essential debhelper dpkg-dev fakeroot asciidoc-base xmlto pkg-config + build-essential cmake debhelper dpkg-dev fakeroot asciidoc-base xmlto pkg-config - name: Debian package build test run: bash tests/test_deb_build.sh diff --git a/.github/workflows/portability.yml b/.github/workflows/portability.yml index 3819e9fa..a5ee4068 100644 --- a/.github/workflows/portability.yml +++ b/.github/workflows/portability.yml @@ -81,6 +81,11 @@ jobs: cmake --build build --parallel 4 ctest --test-dir build -L 'unit|vendor' --output-on-failure --no-tests=error python3 tests/interop.py --self --bin build/bin + cmake --install build --prefix "$PWD/install" + cmake -S tests/consumer -B consumer -G Ninja -DCMAKE_PREFIX_PATH="$PWD/install" + cmake --build consumer + ./consumer/consumer_static + ./consumer/consumer_shared offline-musl: runs-on: ubuntu-latest diff --git a/CMakeLists.txt b/CMakeLists.txt index b3732a20..76188be4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ if(SS_MINIMAL) set(SS_ENABLE_REGEX OFF) set(SS_ENABLE_PLUGINS OFF) set(SS_ENABLE_LEGACY OFF) - set(WITH_SS_MANAGER OFF CACHE BOOL "Build ss-manager" FORCE) + set(WITH_SS_MANAGER OFF) endif() include(cmake/Dependencies.cmake) diff --git a/CMakePresets.json b/CMakePresets.json index 83729e3c..7990a8a5 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,5 +1,5 @@ { - "version": 3, + "version": 2, "cmakeMinimumRequired": { "major": 3, "minor": 20, diff --git a/cmake/ProjectOptions.cmake b/cmake/ProjectOptions.cmake index 1d912842..9642802e 100644 --- a/cmake/ProjectOptions.cmake +++ b/cmake/ProjectOptions.cmake @@ -8,7 +8,7 @@ function(ss_project_options target) set_property(TARGET ${target} PROPERTY NO_SYSTEM_FROM_IMPORTED TRUE) target_include_directories(${target} BEFORE PRIVATE ${MBEDTLS_INCLUDE_DIRS}) if(WIN32) - target_compile_definitions(${target} PRIVATE WIN32_LEAN_AND_MEAN) + target_compile_definitions(${target} PRIVATE WIN32_LEAN_AND_MEAN __USE_MINGW_ANSI_STDIO=1) endif() if(MSVC) target_compile_options(${target} PRIVATE /W4) diff --git a/docs/modernization.md b/docs/modernization.md index 3794e41b..dd5f60c1 100644 --- a/docs/modernization.md +++ b/docs/modernization.md @@ -19,7 +19,7 @@ for unavailable functionality. Linux redirection/netfilter remains Linux-only. fail the required CI job and are reported as skips in optional local runs. - [x] Target-scoped CMake, separate programs/static/shared library options, reliable dependency discovery, installation/export metadata and presets. -- [ ] Offline bundled dependency mode and source release archive; explicit system +- [x] Offline bundled dependency mode and source release archive; explicit system mode for distro packages; checksums, licenses, versions, update procedure. - [x] Remove libcork: address parsing, lists, hash maps, subprocess lifecycle. - [x] Remove libipset: bounded IPv4/IPv6 prefix storage with insertion/deletion; @@ -33,14 +33,13 @@ for unavailable functionality. Linux redirection/netfilter remains Linux-only. - [ ] Complete sanitizers/static analysis, compatibility and stress validation, release archive offline build, installed consumer, before/after report. -## Initial evidence (2026-09-10) +## Baseline provenance -Base commit: 8fe386b. Existing libcork checkout is 074e074b, different from the -superproject gitlink; it has no uncommitted files and is preserved during work. -The existing build passed all 13 unit tests. Fresh shared-dependency Release -build with the first CMake changes also passed all 13 unit tests. -The initial baseline stress/interop runs collided on a shared port; discard -those measurements and repeat serially before reporting a baseline. +Base commit: 8fe386b. Its libcork checkout is 074e074b, different from the +superproject gitlink; this was pre-existing local state. That checkout, libipset +and libbloom are preserved and ignored locally. Fresh baseline builds use those +same checkouts, with no modernization changes applied to baseline source. +The fresh baseline passes all 13 original unit tests. ## Build interface @@ -64,41 +63,25 @@ The archive includes tracked working-tree contents (so uncommitted changes are included); record the final commit with a published release and use a clean checkout for publishing. No submodules are accepted in the archive. -## Verified implementation evidence +## Platform validation -- Bundled macOS arm64 build: 17 project tests and 14 upstream libsodium tests - pass with the crypto-only Mbed TLS configuration. -- Minimal profile: 15 project tests plus 14 upstream libsodium tests pass. -- Linux arm64 glibc: built inside Docker with networking disabled, 29 tests - passed before the later literal-rule and crypto-profile changes. Repeat the - final matrix before marking the full platform requirement complete. -- ASan + UBSan: 29 tests passed before the most recent changes; final rerun pending. -- Real shadowsocks-rust 1.24.0 interoperability passes six AEAD methods in both - directions, each with three simultaneous TCP streams (up to 1 MiB) and four - UDP payload sizes (1, 128, 1200, 4096 bytes). -- The former curl harness obeyed `no_proxy`, producing false positives by - bypassing SOCKS. Its historical results are not valid interoperability proof. - The Python replacement opens SOCKS5 sockets explicitly and reports missing - peers as skip 77, or failure under SS_REQUIRE_INTEROP=1. -- That replacement exposed truncation of 4 KiB UDP datagrams in the MTU-sized - receive buffer. The relay now receives full datagrams before authentication. -- The sanitizer baseline found null-URI output was uninitialized in ss_url_parse; - the output is now cleared before rejecting null input, with a poisoned-output - regression assertion. -- `otool -L` on bundled ss-server lists only macOS libSystem and libresolv. -- An independent CMake consumer linked and ran against the installed bundled - static library. Shared/system consumers and relocation remain to be tested. -- Existing libcork, libipset and libbloom directories are preserved locally and - ignored. Gitlinks are removed; archives no longer require those checkouts. +CI on commit 9623456 passes Linux glibc x86-64/ARM64 and macOS full/minimal +builds, real TCP/UDP relay, SIP003 cleanup (full profile), and relocated installed +consumers. FreeBSD 14.3 passes compilation, unit/vendor tests and real TCP/UDP +relay. Alpine/musl builds the release archive with networking disabled and passes +all unit/vendor and TCP/UDP tests. Linux Valgrind, ASan/UBSan, coverage and the +required shadowsocks-rust interoperability job pass, as does clang-tidy-18. -## Remaining completion gates +Native Windows and Debian packaging remain under validation. Subsequent fixes +address Windows CMake drive paths and printf size formats, explicit FreeBSD +socket headers, Alpine fortify diagnostics, and Debian install metadata/tooling. +Windows cross-builds include both libraries and installed consumers. -Finish Windows MinGW and FreeBSD runtime support/CI, Linux musl and x86-64, -platform socket/error/clock isolation, DNS cancellation and plugin integration -coverage, final differential IP set comparison, installation relocation and -system/shared builds, source-archive offline verification, complete local lint -and tests, and the final binary/memory/TCP/UDP before/after report. Assess MSVC -constraints explicitly. Do not infer these from the successful macOS build. +A committed source archive also builds locally on Linux arm64 with networking +and Python discovery disabled, passing all 31 unit/vendor tests and six-method +TCP/UDP plus SIP003 tests. The source release itself needs no Git or Python to +compile. Final archive regeneration and current-head matrix verification remain +completion gates. ## Compatibility details @@ -113,7 +96,7 @@ legacy AES/Camellia stream modes prevent a transparent libsodium-only switch. See https://doc.libsodium.org/secret-key_cryptography/aead/aes-256-gcm and https://shadowsocks.org/doc/sip022.html for the provider and protocol contracts. -## Final local validation and remaining runtime gates +## Local validation - Fresh base-commit build (8fe386b) passes all 13 original unit tests, using the preserved dependency checkouts described above. Both its system-shared and @@ -131,7 +114,7 @@ https://shadowsocks.org/doc/sip022.html for the provider and protocol contracts. system-mode static/shared consumers also link and run. System static exports require the exact Mbed TLS version used at build time to avoid an ABI mismatch. - Windows x86-64: programs, both libraries, all tests and installed consumers - cross-compile with Zig. Native Windows and FreeBSD CI results are still pending. + cross-compile with Zig. Native Windows execution remains a completion gate. - SIP003 fixture: real TCP forwarding, UDP bypass, and child cleanup pass through the actual programs. DNS cancellation covers outstanding A/AAAA requests, exactly-once callbacks/free callbacks and reinitialization after shutdown. diff --git a/src/udprelay.c b/src/udprelay.c index 62f707cb..25263333 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -904,7 +904,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len > packet_size) { if (verbose) { - LOGI("[udp] remote_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); + LOGI("[udp] remote_recv_sendto fragmentation, MTU at least be: " SIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } @@ -1029,7 +1029,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) goto CLEAN_UP; } else if (buf->len > packet_size) { if (verbose) { - LOGI("[udp] UDP server_recv_recvmsg fragmentation, MTU at least be: " SSIZE_FMT, + LOGI("[udp] UDP server_recv_recvmsg fragmentation, MTU at least be: " SIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } @@ -1366,7 +1366,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len > packet_size) { if (verbose) { - LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); + LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } @@ -1385,7 +1385,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len - addr_header_len > packet_size) { if (verbose) { - LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, + LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SIZE_FMT, buf->len - addr_header_len + PACKET_HEADER_SIZE); } } diff --git a/src/utils.h b/src/utils.h index 1358d14e..9469f8a6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -192,14 +192,9 @@ extern int use_syslog; #endif // if __ANDROID__ -// Workaround for "%z" in Windows printf -#ifdef __MINGW32__ -#define SSIZE_FMT "%Id" -#define SIZE_FMT "%Iu" -#else +/* C99 size formats; MinGW targets explicitly enable its ANSI stdio adapter. */ #define SSIZE_FMT "%zd" #define SIZE_FMT "%zu" -#endif #ifdef __MINGW32__ // Override Windows built-in functions