Rename to shadowsocks-c with libuv, async DNS and CI lint (#3051)

Rename the project to shadowsocks-c while retaining ss-* commands, the embedding ABI, and legacy library/package lookup compatibility.

Replace libev with bundled libuv for IOCP/kqueue event backends, expand asynchronous runtime DNS coverage, and add actionlint/Ruff with strict clang-tidy failure handling. Validate native platforms, static builds, packaging, interoperability, sanitizers, and canonical/legacy consumers.

All 22 hosted checks pass at reviewed head a8493250eb.
This commit is contained in:
Max Lv authored and GitHub committed 2026-09-11 14:18:37 +08:00
1 parent 201e70c4bd
commit bdc77408cb
61 files changed
+1695 -851

No files matched your search

+2 -2
View File
@@ -1,4 +1,4 @@
# clang-tidy configuration for shadowsocks-libev project sources (src/ only).
# clang-tidy configuration for shadowsocks-c project sources (src/ only).
# Bundled sources under third_party/ and src/blake3/ are third-party code and
# are excluded by the file regex used in CI:
# run-clang-tidy -p build '/src/[^/]+\.c$'
@@ -8,7 +8,7 @@
# Checks disabled below are either stylistic churn (macro-parentheses,
# reserved-identifier: the codebase uses _prefixed names and vendored
# uthash.h/generated config.h trip them ~600 times) or produce false
# positives with the libev callback style (casting-through-void,
# positives with the event callback style (casting-through-void,
# multi-level-implicit-pointer-conversion).
Checks: >
clang-analyzer-*,
+3 -3
View File
@@ -20,11 +20,11 @@ jobs:
if: runner.os == 'Linux'
run: |
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 libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install mbedtls@3 libsodium libev c-ares pcre2
run: brew install mbedtls@3 libsodium libuv c-ares pcre2
- name: Build
run: |
@@ -41,7 +41,7 @@ jobs:
- name: Install dependencies
run: |
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 libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev
sudo apt-get install -y --no-install-recommends \
build-essential cmake debhelper dpkg-dev fakeroot asciidoc-base xmlto pkg-config
+20 -3
View File
@@ -24,6 +24,8 @@ jobs:
ctest --test-dir build -L 'unit|vendor' --output-on-failure --no-tests=error
- name: Real TCP and UDP relay
run: python3 tests/interop.py --self --bin build/bin
- name: Asynchronous hostname ACL bypass
run: python3 tests/async_dns_interop.py --bin build/bin
- name: SIP003 transport and child cleanup
if: matrix.minimal == 'OFF'
run: python3 tests/interop.py --self --bin build/bin --plugin tests/sip003_fixture.py
@@ -35,6 +37,10 @@ jobs:
cmake --build consumer
./consumer/consumer_static
./consumer/consumer_shared
cmake -S tests/consumer -B consumer-legacy -DSS_PACKAGE_NAME=shadowsocks-libev -DCMAKE_PREFIX_PATH="$PWD/relocated"
cmake --build consumer-legacy
./consumer-legacy/consumer_static
./consumer-legacy/consumer_shared
windows:
runs-on: windows-latest
@@ -59,11 +65,14 @@ jobs:
ctest --test-dir build -L 'unit|vendor' --output-on-failure --no-tests=error
objdump -p build/bin/ss-server.exe | sed -n '/DLL Name/p'
python tests/interop.py --self --bin build/bin --isolate-windows-runtime
python tests/async_dns_interop.py --bin build/bin --isolate-windows-runtime
- name: Installed consumers
run: |
cmake --install build --prefix "$PWD/install"
cmake -S tests/consumer -B consumer -G Ninja -DCMAKE_PREFIX_PATH="$PWD/install"
cmake --build consumer
cmake -S tests/consumer -B consumer-legacy -G Ninja -DSS_PACKAGE_NAME=shadowsocks-libev -DCMAKE_PREFIX_PATH="$PWD/install"
cmake --build consumer-legacy
- name: Run installed consumers without toolchain DLLs
shell: pwsh
run: |
@@ -72,6 +81,10 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw "Static consumer failed: $LASTEXITCODE" }
& ./consumer/consumer_shared.exe
if ($LASTEXITCODE -ne 0) { throw "Shared consumer failed: $LASTEXITCODE" }
& ./consumer-legacy/consumer_static.exe
if ($LASTEXITCODE -ne 0) { throw "Legacy static consumer failed: $LASTEXITCODE" }
& ./consumer-legacy/consumer_shared.exe
if ($LASTEXITCODE -ne 0) { throw "Legacy shared consumer failed: $LASTEXITCODE" }
static-macos:
runs-on: macos-latest
@@ -95,6 +108,7 @@ jobs:
- name: Exercise installed static programs
run: |
python3 tests/interop.py --self --bin relocated-static/bin
python3 tests/async_dns_interop.py --bin relocated-static/bin
python3 tests/interop.py --self --bin relocated-static/bin --plugin tests/sip003_fixture.py
- uses: actions/upload-artifact@v4
with:
@@ -132,7 +146,9 @@ jobs:
- name: Reject third-party DLL imports, including delay imports
run: python tests/check_static_runtime.py relocated-static/bin/ss-*.exe consumer-static/consumer_static.exe
- name: Exercise installed programs without toolchain DLLs
run: python tests/interop.py --self --bin relocated-static/bin --isolate-windows-runtime
run: |
python tests/interop.py --self --bin relocated-static/bin --isolate-windows-runtime
python tests/async_dns_interop.py --bin relocated-static/bin --isolate-windows-runtime
- name: Run static consumer with only Windows system directories on PATH
shell: pwsh
run: |
@@ -171,6 +187,7 @@ 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
python3 tests/async_dns_interop.py --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
@@ -182,7 +199,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Source archive
run: python3 scripts/source_archive.py release/shadowsocks-libev.tar.gz
run: python3 scripts/source_archive.py release/shadowsocks-c.tar.gz
- name: Prepare compiler image
run: |
printf 'FROM alpine:3.24\nRUN apk add --no-cache build-base cmake python3 linux-headers\n' > /tmp/ss-toolchain.Dockerfile
@@ -191,7 +208,7 @@ jobs:
run: |
docker run --rm --network none -v "$PWD/release:/release:ro" ss-toolchain sh -ec '
mkdir /src
tar xzf /release/shadowsocks-libev.tar.gz -C /src --strip-components=1
tar xzf /release/shadowsocks-c.tar.gz -C /src --strip-components=1
cmake -S /src -B /build -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE
cmake --build /build --parallel 4
ctest --test-dir /build -L "unit|vendor" --output-on-failure --no-tests=error
+41 -9
View File
@@ -7,6 +7,26 @@ on:
branches: [master]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
cache: false
- uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install pinned linters
run: |
go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.12
python -m pip install ruff==0.15.6
- name: Lint GitHub Actions workflows
run: actionlint -shellcheck= -pyflakes=
- name: Lint Python scripts and tests
run: ruff check --select E9,F63,F7,F82 tests scripts
tests:
strategy:
fail-fast: false
@@ -20,11 +40,11 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev valgrind
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev valgrind
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install mbedtls@3 libsodium libev c-ares pcre2
run: brew install mbedtls@3 libsodium libuv c-ares pcre2
- name: Build test binaries
run: |
@@ -62,7 +82,7 @@ jobs:
- name: Install dependencies
run: |
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 libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev
- name: Build with ASan + UBSan
run: |
@@ -91,14 +111,16 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy-18 clang-tools-18 libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
sudo apt-get install -y clang-tidy-18 clang-tools-18 libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev
- name: Configure (compile_commands.json)
run: cmake -S . -B build
- name: Run clang-tidy on project sources
run: |
run-clang-tidy-18 -quiet -p build "$PWD/src/[^/]+\.c$" 2>/dev/null | tee tidy.log || true
set -o pipefail
tidy_status=0
run-clang-tidy-18 -quiet -p build "$PWD/src/[^/]+\.c$" 2>&1 | tee tidy.log || tidy_status=$?
grep 'warning:' tidy.log | sort -u > warnings.txt || true
count="$(wc -l < warnings.txt)"
echo "clang-tidy warnings: $count (max allowed: $MAX_WARNINGS)"
@@ -108,8 +130,8 @@ jobs:
cat warnings.txt
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
if ! grep -q . warnings.txt && grep -qE 'error:' tidy.log; then
echo "clang-tidy produced errors:"; grep -E 'error:' tidy.log | sort -u
if [ "$tidy_status" -ne 0 ] || grep -qE 'error:' tidy.log; then
echo "clang-tidy failed (exit status: $tidy_status). See tidy.log for diagnostics."
exit 1
fi
if [ "$count" -gt "$MAX_WARNINGS" ]; then
@@ -118,6 +140,16 @@ jobs:
exit 1
fi
- name: Upload clang-tidy diagnostics
if: always()
uses: actions/upload-artifact@v4
with:
name: clang-tidy-diagnostics
path: |
tidy.log
warnings.txt
if-no-files-found: ignore
coverage:
runs-on: ubuntu-latest
steps:
@@ -126,7 +158,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y lcov libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
sudo apt-get install -y lcov libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev
- name: Build with coverage instrumentation
run: |
@@ -160,7 +192,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Install dependencies and independent peer
run: brew install mbedtls@3 libsodium libev c-ares pcre2 shadowsocks-rust
run: brew install mbedtls@3 libsodium libuv c-ares pcre2 shadowsocks-rust
- name: Build
run: |
cmake -S . -B build -DSS_DEPENDENCY_MODE=system -DWITH_STATIC=OFF
+2 -1
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME shadowsocks-libev)
set(PROJECT_NAME shadowsocks-c)
set(RELEASE_DATE 2026-02-09)
set(PROJECT_VERSION "3.3.6")
set(PROJECT_DESC "a lightweight secured socks5 proxy")
@@ -98,6 +98,7 @@ endif()
include(${PROJECT_SOURCE_DIR}/cmake/configure.cmake)
configure_file(${PROJECT_SOURCE_DIR}/cmake/config.h.cmake ${PROJECT_BINARY_DIR}/src/config.h)
include(cmake/ProjectOptions.cmake)
ss_project_options(ss_ev)
include_directories(${PROJECT_BINARY_DIR}/src)
add_compile_definitions(HAVE_CONFIG_H)
+14 -7
View File
@@ -1,10 +1,10 @@
# shadowsocks-libev
# shadowsocks-c
[![Build Status](https://travis-ci.com/shadowsocks/shadowsocks-libev.svg?branch=master)](https://travis-ci.com/shadowsocks/shadowsocks-libev) [![Snap Status](https://snapcraft.io/shadowsocks-libev/badge.svg)](https://snapcraft.io/shadowsocks-libev)
## Intro
[Shadowsocks-libev](https://shadowsocks.org) is a lightweight secured SOCKS5
[shadowsocks-c](https://shadowsocks.org) is a lightweight secured SOCKS5
proxy for embedded devices and low-end boxes.
It is a port of [Shadowsocks](https://github.com/shadowsocks/shadowsocks)
@@ -15,12 +15,19 @@ Current version: 3.3.6 | [Changelog](debian/changelog)
## Features
Shadowsocks-libev is written in pure C and depends on [libev](http://software.schmorp.de/pkg/libev.html). It's designed
shadowsocks-c is written in pure C and depends on [libuv](https://libuv.org/). It's designed
to be a lightweight implementation of shadowsocks protocol, in order to keep the resource usage as low as possible.
For a full list of feature comparison between different versions of shadowsocks,
refer to the [Wiki page](https://github.com/shadowsocks/shadowsocks/wiki/Feature-Comparison-across-Different-Versions).
The project is now **shadowsocks-c**. Commands (`ss-local`, `ss-server`, etc.)
and the `shadowsocks.h` API remain compatible. New builds produce
`libshadowsocks-c` with CMake/pkg-config package `shadowsocks-c`; legacy library
filenames and package lookup names remain available as compatibility aliases.
Existing configuration paths, distro package names and service names are retained.
Repository links below still point to the current GitHub repository.
## Quick Start
Snap is the recommended way to install the latest binaries.
@@ -93,7 +100,7 @@ IPv4/IPv6 CIDRs, `full:example.com` for exact domains, and
case and respect label boundaries. Unsupported regex rules are rejected.
Distribution packages can use `-DSS_DEPENDENCY_MODE=system -DWITH_STATIC=OFF`
with libev, c-ares, libsodium, Mbed TLS 3.x, and PCRE2 development packages.
with libuv, c-ares, libsodium, Mbed TLS 3.x, and PCRE2 development packages.
Use `-DCMAKE_PREFIX_PATH=/opt/homebrew/opt/mbedtls@3` when needed on macOS.
| Option | Default | Purpose |
@@ -110,7 +117,7 @@ Use `-DCMAKE_PREFIX_PATH=/opt/homebrew/opt/mbedtls@3` when needed on macOS.
| `ENABLE_SANITIZERS` | `OFF` | AddressSanitizer and UndefinedBehaviorSanitizer |
| `ENABLE_CONNMARKTOS` / `ENABLE_NFTABLES` | `OFF` | Optional Linux firewall integrations |
CMake consumers can use `find_package(shadowsocks-libev CONFIG REQUIRED)` and
CMake consumers can use `find_package(shadowsocks-c CONFIG REQUIRED)` and
link `shadowsocks::static`, `shadowsocks::shared`, or `shadowsocks::shadowsocks`
(which prefers the shared library when installed). A pkg-config file is also
installed. Dependency provenance and update instructions are in
@@ -196,7 +203,7 @@ ctest --test-dir build -L 'unit|vendor' --output-on-failure
sudo cmake --install build
```
Distribution packagers can install `libpcre2-dev libev-dev libc-ares-dev
Distribution packagers can install `libpcre2-dev libuv1-dev libc-ares-dev
libmbedtls-dev libsodium-dev` and select `-DSS_DEPENDENCY_MODE=system
-DWITH_STATIC=OFF`. Documentation additionally needs asciidoc and xmlto.
@@ -275,7 +282,7 @@ cmake --build build-windows --parallel
Cross-compilation does not run Windows tests. The portability workflow runs
native UCRT64 tests and TCP/UDP relay checks on Windows. Bundled mode is required
because libev must use the project's Winsock handle adapter. MSVC remains a
with a bundled libuv IOCP backend. MSVC remains a
separate, unsupported milestone; configuration reports this explicitly.
The historical Autotools scripts in `docker/mingw` are superseded by this build.
+5 -6
View File
@@ -15,7 +15,7 @@ elseif(NOT SS_DEPENDENCY_MODE STREQUAL "system")
message(FATAL_ERROR "SS_DEPENDENCY_MODE must be bundled or system")
endif()
if(WIN32)
message(FATAL_ERROR "Windows requires bundled dependencies: libev must use this project's Winsock handle adapter")
message(FATAL_ERROR "Windows requires bundled dependencies: the bundled libuv configuration is the validated Windows build")
endif()
# Select one linkage mode consistently for programs, libraries, and tests.
@@ -30,10 +30,8 @@ endif()
find_package(MbedTLS REQUIRED)
find_package(Sodium REQUIRED)
find_package(Cares REQUIRED)
find_path(LIBEV_INCLUDE_DIR ev.h)
find_library(LIBEV_LIBRARY NAMES ev)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libev REQUIRED_VARS LIBEV_LIBRARY LIBEV_INCLUDE_DIR)
find_path(LIBUV_INCLUDE_DIR uv.h REQUIRED)
find_library(LIBUV_LIBRARY NAMES uv REQUIRED)
find_package(Threads REQUIRED)
if(WITH_STATIC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_ss_saved_suffixes})
@@ -51,7 +49,8 @@ ss_import_dependency(ss_cares "${CARES_LIBRARY}" "${CARES_INCLUDE_DIRS}")
if(SS_ENABLE_REGEX)
ss_import_dependency(ss_pcre2 "${PCRE2_LIBRARY}" "${PCRE2_INCLUDE_DIRS}")
endif()
ss_import_dependency(ss_ev "${LIBEV_LIBRARY}" "${LIBEV_INCLUDE_DIR}")
ss_import_dependency(ss_uv "${LIBUV_LIBRARY}" "${LIBUV_INCLUDE_DIR}")
include(${PROJECT_SOURCE_DIR}/cmake/EventLoop.cmake)
if(WIN32)
set_property(TARGET ss_cares APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32 iphlpapi)
set_property(TARGET ss_ev APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32)
+6
View File
@@ -0,0 +1,6 @@
add_library(ss_ev STATIC ${PROJECT_SOURCE_DIR}/src/ss_event.c)
target_include_directories(ss_ev PUBLIC ${PROJECT_SOURCE_DIR}/src)
target_link_libraries(ss_ev PUBLIC ss_uv Threads::Threads ${SS_MATH_LIBRARY} ${CMAKE_DL_LIBS})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(ss_ev PUBLIC rt)
endif()
+40 -30
View File
@@ -5,37 +5,41 @@ set(SS_PC_PRIVATE "")
set(private_links)
set(private_content "# Generated private linkage for the installed static library.\n")
if(SS_BUILD_STATIC_LIBRARY)
set(private_targets bloom blake3)
set(private_targets bloom blake3 ss_ev)
if(SS_DEPENDENCY_MODE STREQUAL "bundled")
list(APPEND private_targets ss_sodium ss_mbedcrypto ss_ev ss_cares)
list(APPEND private_targets ss_sodium ss_mbedcrypto ss_uv ss_cares)
if(SS_ENABLE_REGEX)
list(APPEND private_targets ss_pcre2)
endif()
else()
set(SS_SYSTEM_DEPENDENCIES
"list(APPEND CMAKE_MODULE_PATH \"\${CMAKE_CURRENT_LIST_DIR}/modules\")\n find_dependency(MbedTLS ${MBEDTLS_VERSION} EXACT)\n find_dependency(Sodium)\n find_dependency(Cares)\n find_library(SS_CONSUMER_EV NAMES ev REQUIRED)")
"list(APPEND CMAKE_MODULE_PATH \"\${CMAKE_CURRENT_LIST_DIR}/modules\")\n find_dependency(MbedTLS ${MBEDTLS_VERSION} EXACT)\n find_dependency(Sodium)\n find_dependency(Cares)\n find_library(SS_CONSUMER_UV NAMES uv REQUIRED)")
if(SS_ENABLE_REGEX)
string(APPEND SS_SYSTEM_DEPENDENCIES "\n find_dependency(PCRE2)")
list(APPEND private_links "\${PCRE2_LIBRARY}")
string(APPEND SS_PC_PRIVATE " -lpcre2-8")
endif()
list(APPEND private_links "\${SODIUM_LIBRARY}" "\${MBEDTLS_CRYPTO_LIBRARY}"
"\${CARES_LIBRARY}" "\${SS_CONSUMER_EV}")
string(APPEND SS_PC_PRIVATE " -lsodium -lmbedcrypto -lcares -lev")
"\${CARES_LIBRARY}" )
string(APPEND SS_PC_PRIVATE " -lsodium -lmbedcrypto -lcares")
install(FILES cmake/FindMbedTLS.cmake cmake/FindSodium.cmake
cmake/FindCares.cmake cmake/FindPCRE2.cmake cmake/mbedtls_version_check.c
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-libev/modules)
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-c/modules)
endif()
foreach(target IN LISTS private_targets)
install(FILES $<TARGET_FILE:${target}>
DESTINATION ${CMAKE_INSTALL_LIBDIR}/shadowsocks-libev)
list(APPEND private_links "\${_ss_libdir}/shadowsocks-libev/$<TARGET_FILE_NAME:${target}>")
string(APPEND SS_PC_PRIVATE " \${libdir}/shadowsocks-libev/$<TARGET_FILE_NAME:${target}>")
DESTINATION ${CMAKE_INSTALL_LIBDIR}/shadowsocks-c)
list(APPEND private_links "\${_ss_libdir}/shadowsocks-c/$<TARGET_FILE_NAME:${target}>")
string(APPEND SS_PC_PRIVATE " \${libdir}/shadowsocks-c/$<TARGET_FILE_NAME:${target}>")
endforeach()
if(SS_DEPENDENCY_MODE STREQUAL "system")
list(APPEND private_links "\${SS_CONSUMER_UV}")
string(APPEND SS_PC_PRIVATE " -luv")
endif()
list(APPEND private_links Threads::Threads ${SS_MATH_LIBRARY} ${CMAKE_DL_LIBS})
if(WIN32)
list(APPEND private_links ws2_32 iphlpapi bcrypt advapi32)
string(APPEND SS_PC_PRIVATE " -lws2_32 -liphlpapi -lbcrypt -ladvapi32")
list(APPEND private_links ws2_32 iphlpapi bcrypt advapi32 user32 userenv psapi dbghelp ole32 shell32)
string(APPEND SS_PC_PRIVATE " -lws2_32 -liphlpapi -lbcrypt -ladvapi32 -luser32 -luserenv -lpsapi -ldbghelp -lole32 -lshell32")
else()
string(APPEND SS_PC_PRIVATE " -lm -pthread")
if(APPLE)
@@ -43,36 +47,42 @@ if(SS_BUILD_STATIC_LIBRARY)
string(APPEND SS_PC_PRIVATE " -lresolv")
endif()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND private_links rt)
string(APPEND SS_PC_PRIVATE " -lrt")
endif()
# Resolve libdir relative to this installed config, supporting --prefix relocation.
file(RELATIVE_PATH libdir_from_config "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-libev" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
file(RELATIVE_PATH libdir_from_config "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-c" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
string(APPEND private_content "get_filename_component(_ss_libdir \"\${CMAKE_CURRENT_LIST_DIR}/${libdir_from_config}\" ABSOLUTE)\n")
string(APPEND private_content "set_property(TARGET shadowsocks::static PROPERTY INTERFACE_LINK_LIBRARIES \"${private_links}\")\n")
endif()
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-private.cmake" CONTENT "${private_content}")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-private.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-libev)
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-c)
set(SS_STATIC_FILENAME "${CMAKE_STATIC_LIBRARY_PREFIX}shadowsocks-libev${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(SS_SHARED_FILENAME "${CMAKE_SHARED_LIBRARY_PREFIX}shadowsocks-libev${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(SS_SHARED_IMPLIB "${CMAKE_IMPORT_LIBRARY_PREFIX}shadowsocks-libev${CMAKE_IMPORT_LIBRARY_SUFFIX}")
configure_package_config_file(cmake/shadowsocks-libev-config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev-config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-libev
set(SS_STATIC_FILENAME "${CMAKE_STATIC_LIBRARY_PREFIX}shadowsocks-c${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(SS_SHARED_FILENAME "${CMAKE_SHARED_LIBRARY_PREFIX}shadowsocks-c${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(SS_SHARED_IMPLIB "${CMAKE_IMPORT_LIBRARY_PREFIX}shadowsocks-c${CMAKE_IMPORT_LIBRARY_SUFFIX}")
configure_package_config_file(cmake/shadowsocks-c-config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-c-config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-c
PATH_VARS CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_BINDIR CMAKE_INSTALL_INCLUDEDIR)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev-config-version.cmake"
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-c-config-version.cmake"
VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-libev)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-c-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-c-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-c)
file(RELATIVE_PATH SS_PC_PREFIX_RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/pkgconfig" "${CMAKE_CURRENT_BINARY_DIR}")
configure_file(cmake/shadowsocks-libev.pc.cmake "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev.pc.in" @ONLY)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/shadowsocks-libev.pc"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev.pc.in")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/shadowsocks-libev.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
configure_file(cmake/shadowsocks-c.pc.cmake "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-c.pc.in" @ONLY)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/shadowsocks-c.pc"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-c.pc.in")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/shadowsocks-c.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif()
install(FILES COPYING LICENSE third_party/README.md third_party/manifest.json
DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-libev)
install(FILES third_party/bloom/LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-libev/bloom)
install(DIRECTORY src/blake3/ DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-libev/blake3
DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-c)
install(FILES third_party/bloom/LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-c/bloom)
install(DIRECTORY src/blake3/ DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-c/blake3
FILES_MATCHING PATTERN "LICENSE*")
include(${PROJECT_SOURCE_DIR}/cmake/LegacyPackage.cmake)
+50
View File
@@ -0,0 +1,50 @@
# Preserve installed library filenames for existing build scripts and binaries.
# Unix aliases are relative symlinks so the installation remains relocatable.
# Windows uses copies because creating symlinks may require elevated privileges.
function(ss_legacy_library target directory filename source)
# filename is supplied with its canonical project name replaced below.
string(REPLACE "shadowsocks-c" "shadowsocks-libev" legacy "${filename}")
if(WIN32)
install(FILES "${source}" DESTINATION "${directory}" RENAME "${legacy}")
else()
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${directory}\")
file(CREATE_LINK \"$<TARGET_FILE_NAME:${target}>\"
\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${directory}/${legacy}\" SYMBOLIC)")
endif()
endfunction()
foreach(kind STATIC SHARED)
if(SS_BUILD_${kind}_LIBRARY)
string(TOLOWER "${kind}" suffix)
set(target shadowsocks-c-${suffix})
if(WIN32 AND kind STREQUAL "SHARED")
ss_legacy_library(${target} "${CMAKE_INSTALL_BINDIR}"
"${CMAKE_SHARED_LIBRARY_PREFIX}shadowsocks-c${CMAKE_SHARED_LIBRARY_SUFFIX}" "$<TARGET_FILE:${target}>")
ss_legacy_library(${target} "${CMAKE_INSTALL_LIBDIR}"
"${CMAKE_IMPORT_LIBRARY_PREFIX}shadowsocks-c${CMAKE_IMPORT_LIBRARY_SUFFIX}" "$<TARGET_LINKER_FILE:${target}>")
elseif(kind STREQUAL "STATIC")
ss_legacy_library(${target} "${CMAKE_INSTALL_LIBDIR}"
"${CMAKE_STATIC_LIBRARY_PREFIX}shadowsocks-c${CMAKE_STATIC_LIBRARY_SUFFIX}" "$<TARGET_FILE:${target}>")
else()
ss_legacy_library(${target} "${CMAKE_INSTALL_LIBDIR}"
"${CMAKE_SHARED_LIBRARY_PREFIX}shadowsocks-c${CMAKE_SHARED_LIBRARY_SUFFIX}" "$<TARGET_FILE:${target}>")
if(APPLE)
set(legacy_soname "${CMAKE_SHARED_LIBRARY_PREFIX}shadowsocks-c.2${CMAKE_SHARED_LIBRARY_SUFFIX}")
else()
set(legacy_soname "${CMAKE_SHARED_LIBRARY_PREFIX}shadowsocks-c${CMAKE_SHARED_LIBRARY_SUFFIX}.2")
endif()
ss_legacy_library(${target} "${CMAKE_INSTALL_LIBDIR}" "${legacy_soname}" "$<TARGET_FILE:${target}>")
endif()
endif()
endforeach()
if(SS_BUILD_STATIC_LIBRARY OR SS_BUILD_SHARED_LIBRARY)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev-config.cmake"
"include(CMakeFindDependencyMacro)\nfind_dependency(shadowsocks-c \${shadowsocks-libev_FIND_VERSION} CONFIG PATHS \"\${CMAKE_CURRENT_LIST_DIR}/../shadowsocks-c\" NO_DEFAULT_PATH)\n")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-libev-config.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-libev)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/package/shadowsocks-c-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/shadowsocks-libev RENAME shadowsocks-libev-config-version.cmake)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/shadowsocks-c.pc"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig RENAME shadowsocks-libev.pc)
endif()
-2
View File
@@ -17,8 +17,6 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1
/* Define to 1 if you have the <ev.h> header file. */
#cmakedefine HAVE_EV_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#cmakedefine HAVE_FCNTL_H 1
-1
View File
@@ -26,7 +26,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
endif ()
check_include_files(dlfcn.h HAVE_DLFCN_H)
check_include_files(ev.h HAVE_EV_H)
check_include_files(fcntl.h HAVE_FCNTL_H)
check_function_exists(fork HAVE_FORK)
check_function_exists(getpwnam_r HAVE_GETPWNAM_R)
@@ -31,4 +31,4 @@ if(NOT TARGET shadowsocks::shadowsocks)
add_library(shadowsocks::shadowsocks ALIAS shadowsocks::static)
endif()
endif()
check_required_components(shadowsocks-libev)
check_required_components(shadowsocks-c)
@@ -9,5 +9,5 @@ URL: @PROJECT_URL@
Version: @PROJECT_VERSION@
Requires:
Cflags: -I${includedir}
Libs: -L${libdir} -lshadowsocks-libev
Libs: -L${libdir} -lshadowsocks-c
Libs.private: @SS_PC_PRIVATE@
+2 -2
View File
@@ -11,7 +11,7 @@ Build-Depends:
asciidoc-base | asciidoc,
debhelper (>= 10),
libc-ares-dev,
libev-dev,
libuv1-dev,
libmbedtls-dev,
libpcre2-dev,
libsodium-dev (>= 1.0.12),
@@ -53,7 +53,7 @@ Breaks: shadowsocks-libev (<< 2.4.0)
Depends:
libshadowsocks-libev2 (= ${binary:Version}),
libc-ares-dev,
libev-dev,
libuv1-dev,
libmbedtls-dev,
libpcre2-dev,
libsodium-dev,
+4 -1
View File
@@ -1,6 +1,9 @@
usr/include/
usr/lib/*/libshadowsocks-libev.so
usr/lib/*/libshadowsocks-libev.a
usr/lib/*/shadowsocks-libev/
usr/lib/*/shadowsocks-c/
usr/lib/*/cmake/shadowsocks-libev/
usr/lib/*/pkgconfig/
usr/lib/*/libshadowsocks-c.so
usr/lib/*/libshadowsocks-c.a
usr/lib/*/cmake/shadowsocks-c/
+1
View File
@@ -1 +1,2 @@
usr/lib/*/libshadowsocks-libev.so.*
usr/lib/*/libshadowsocks-c.so.*
+2 -2
View File
@@ -4,5 +4,5 @@ debian/config.json usr/share/shadowsocks-libev
debian/shadowsocks-libev-*.service lib/systemd/system
usr/bin/
usr/share/man/
usr/share/doc/shadowsocks-libev/
usr/share/licenses/shadowsocks-libev/
usr/share/doc/shadowsocks-c/
usr/share/licenses/shadowsocks-c/
+4 -1
View File
@@ -27,7 +27,7 @@ set(ASCIIDOC_XML_OPTS -b docbook -d manpage -f ${DOC_DIR}/asciidoc.conf -aversio
set(ASCIIDOC_HTML_OPTS -b html4 -d article -f ${DOC_DIR}/asciidoc.conf -aversion=${PROJECT_VERSION})
set(MAN_NAMES ss-local.1 ss-manager.1 ss-nat.1 ss-redir.1 ss-server.1 ss-tunnel.1 shadowsocks-libev.8)
set(MAN_NAMES ss-local.1 ss-manager.1 ss-nat.1 ss-redir.1 ss-server.1 ss-tunnel.1 shadowsocks-c.8)
set(MAN_FILES)
set(HTML_FILES)
@@ -86,3 +86,6 @@ endif ()
# This is required for custom command
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/man)
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/html)
# Retain the former manual lookup name.
file(WRITE "${PROJECT_BINARY_DIR}/man/shadowsocks-libev.8" ".so man8/shadowsocks-c.8\n")
@@ -1,9 +1,9 @@
shadowsocks-libev(8)
====================
shadowsocks-c(8)
================
NAME
----
shadowsocks-libev - a lightweight and secure socks5 proxy
shadowsocks-c - a lightweight and secure socks5 proxy
SYNOPSIS
--------
@@ -13,12 +13,12 @@ SYNOPSIS
DESCRIPTION
-----------
*Shadowsocks-libev* is a lightweight and secure socks5 proxy.
*shadowsocks-c* is a lightweight and secure socks5 proxy.
It is a port of the original shadowsocks created by clowwindy.
*Shadowsocks-libev* is written in pure C and takes advantage of *libev*
*shadowsocks-c* is written in pure C and takes advantage of *libev*
to achieve both high performance and low resource consumption.
*Shadowsocks-libev* consists of five components. One is `ss-server`(1)
*shadowsocks-c* consists of five components. One is `ss-server`(1)
that runs on a remote server to provide secured tunnel service.
`ss-local`(1) and `ss-redir`(1) are clients on your local machines to proxy
traffic(TCP/UDP or both).
@@ -56,7 +56,7 @@ Not available in manager mode.
-m <encrypt_method>::
Set the cipher.
+
*Shadowsocks-libev* accepts 22 different ciphers:
*shadowsocks-c* accepts 22 different ciphers:
+
2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm,
2022-blake3-chacha20-poly1305,
+1
View File
@@ -16,6 +16,7 @@ RUN --network=none cmake -S . -B /build \
&& 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 \
&& python3 tests/async_dns_interop.py --bin /build/bin \
&& cmake --install /build --strip \
&& for binary in /out/bin/ss-*; do \
file "$binary"; \
+2 -2
View File
@@ -29,9 +29,9 @@ Build the scratch runtime image using the same cached build stage:
```sh
docker build --platform linux/arm64 -f docker/static/Dockerfile \
--target runtime -t shadowsocks-libev:static-arm64 .
--target runtime -t shadowsocks-c:static-arm64 .
docker run --rm -p 8388:8388/tcp -p 8388:8388/udp \
shadowsocks-libev:static-arm64 \
shadowsocks-c:static-arm64 \
-s 0.0.0.0 -p 8388 -k example-password -m aes-256-gcm -u
```
+50 -3
View File
@@ -2,7 +2,7 @@
Status: complete for the agreed modernization scope. Native MSVC remains an
explicitly deferred milestone. Implementation branch: feature/self-contained-portable-c;
review: https://github.com/shadowsocks/shadowsocks-libev/pull/3050 (draft).
review: https://github.com/shadowsocks/shadowsocks-libev/pull/3050 (merged).
## Compatibility contract
@@ -59,11 +59,27 @@ SS_BUILD_EXECUTABLES, SS_BUILD_STATIC_LIBRARY and SS_BUILD_SHARED_LIBRARY contro
outputs independently. Docs and platform shell tools are explicit opt-ins.
Bundled mode is the default and the `bundled` / `minimal` presets exercise it.
Maintainers stage the intended source files, then run
`scripts/source_archive.py build-artifacts/shadowsocks-libev.tar.gz`.
`scripts/source_archive.py build-artifacts/shadowsocks-c.tar.gz`.
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.
## Lint and static analysis
The `tests` workflow runs actionlint 1.7.12 on GitHub Actions workflows and
Ruff 0.15.6 on Python scripts/tests (`E9,F63,F7,F82`: syntax errors, invalid
constructs and undefined names). Run the same checks locally:
```sh
actionlint -shellcheck= -pyflakes=
uvx --from ruff==0.15.6 ruff check --select E9,F63,F7,F82 tests scripts
```
Project C builds treat compiler warnings as errors. The separate clang-tidy-18
job analyzes project sources using the CMake compilation database and allows
zero warnings. Tool failures and compiler errors also fail the job; complete
diagnostics are uploaded even on failure. Vendored sources remain excluded.
## Platform validation
Implementation validation at commit cdb192a passes the full platform matrix:
@@ -132,7 +148,7 @@ MSVC is an explicitly deferred milestone, not a supported build today. MinGW-w64
supplies the POSIX compatibility headers/functions (`unistd.h`, `getopt`,
`ssize_t`, string helpers) used throughout the existing CLI. Native MSVC needs
those interfaces isolated, compiler-specific flags in the libsodium adapter,
libev/Win32 build verification and export/import validation. CMake now rejects
libuv/Win32 build verification and export/import validation. CMake now rejects
MSVC early with the supported UCRT64/Zig alternatives. Removing the event loop
or inventing replacement crypto implementations is outside this modernization.
@@ -163,3 +179,34 @@ mean no separately distributed project, crypto, event-loop or toolchain shared
libraries. The `static-linux` job builds the Clang/musl Dockerfile, which also
links libc statically and rejects ELF interpreters and `NEEDED` entries. All
three jobs publish the tested installations as workflow artifacts.
## Native event backends and asynchronous DNS
Libuv 1.52.1 replaces libev in bundled builds; system builds use the distro's
libuv. Windows uses libuv's IOCP-backed AFD socket polling and macOS uses kqueue.
The internal event API supports independent read/write watchers on one socket,
including stopping/freeing watchers during callbacks. Handles close separately
from application objects. Native tests exercise 256 descriptors and verify the
IOCP handle or kqueue descriptor on the corresponding platform.
c-ares drives asynchronous A/AAAA lookups for TCP/UDP destinations and client
hostname ACL bypass, with a dynamically sized DNS watcher list. Manager hostname
updates also use this resolver. Runtime calls to the numeric-address helper
cannot fall back to blocking DNS. Initial configuration/listener/proxy-address
resolution remains synchronous before serving traffic. Tests use a local delayed
DNS server to verify both address families, NXDOMAIN, cancellation, exactly-once
callbacks, and timer progress while requests wait. Hostname ACL integration uses
an unreachable proxy upstream so successful transfers prove direct resolution.
## Project name and compatibility
The project is named **shadowsocks-c**. New library outputs are
`libshadowsocks-c`, and CMake/pkg-config consumers use `shadowsocks-c`.
`shadowsocks.h`, its ABI version, and all `ss-*` commands remain stable.
Legacy library filenames are installed as relative symlinks on Unix and copies
on Windows; `find_package(shadowsocks-libev)` and the old pkg-config name resolve
to the new library. Private dependency archives and license files install under
`shadowsocks-c`. Source archives and the main manual use the new name.
Existing configuration paths, Debian package identifiers and service names
remain compatible. GitHub URLs retain the current repository location.
+1 -1
View File
@@ -2,7 +2,7 @@
# Backward-compatible maintainer entrypoint for the offline release archive.
set -euo pipefail
root=$(git rev-parse --show-toplevel)
name=shadowsocks-libev
name=shadowsocks-c
directory=$root
while getopts "n:o:" opt; do
case "$opt" in
+1 -1
View File
@@ -16,7 +16,7 @@ import tarfile
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("output", type=Path)
parser.add_argument("--prefix", default="shadowsocks-libev-3.3.6")
parser.add_argument("--prefix", default="shadowsocks-c-3.3.6")
args = parser.parse_args()
root = Path(__file__).resolve().parents[1]
if "/" in args.prefix or args.prefix in ("", ".", ".."):
+4 -2
View File
@@ -64,6 +64,7 @@ set(LIBSHADOWSOCKS_LIBEV_SOURCE
udprelay.c
cache.c
local.c
resolv.c
ssurl.c
${SS_CRYPTO_SOURCE}
${SS_PLUGIN_SOURCE}
@@ -148,14 +149,15 @@ endif()
foreach(kind STATIC SHARED)
if(SS_BUILD_${kind}_LIBRARY)
string(TOLOWER "${kind}" suffix)
set(target shadowsocks-libev-${suffix})
set(target shadowsocks-c-${suffix})
add_library(${target} ${kind} ${LIBSHADOWSOCKS_LIBEV_SOURCE})
add_library(shadowsocks-libev-${suffix} ALIAS ${target})
target_compile_definitions(${target} PRIVATE MODULE_LOCAL LIB_ONLY)
target_include_directories(${target} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_link_libraries(${target} PRIVATE ${SS_CORE_DEPS} ${SS_ACL_DEPS})
set_target_properties(${target} PROPERTIES OUTPUT_NAME shadowsocks-libev)
set_target_properties(${target} PROPERTIES OUTPUT_NAME shadowsocks-c)
if(kind STREQUAL "SHARED")
set_target_properties(${target} PROPERTIES VERSION 2.0.0 SOVERSION 2)
endif()
+223 -166
View File
@@ -52,6 +52,7 @@
#include "core.h"
#include "netutils.h"
#include "resolv.h"
#include "ssurl.h"
#include "utils.h"
#include "socks5.h"
@@ -89,7 +90,7 @@ int tcp_outgoing_rcvbuf = 0;
int vpn = 0;
uint64_t tx = 0;
uint64_t rx = 0;
ev_tstamp last = 0;
ss_tstamp last = 0;
char *stat_path = NULL;
#endif
@@ -104,15 +105,15 @@ static int no_delay = 0;
static int udp_fd = 0;
static int ret_val = 0;
static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher;
static struct ss_signal sigint_watcher;
static struct ss_signal sigterm_watcher;
#ifndef __MINGW32__
static struct ev_signal sigchld_watcher;
static struct ev_signal sigusr1_watcher;
static struct ss_signal sigchld_watcher;
static struct ss_signal sigusr1_watcher;
#else
#ifndef LIB_ONLY
static struct plugin_watcher_t {
ev_io io;
ss_io io;
SOCKET fd;
uint16_t port;
int valid;
@@ -126,14 +127,14 @@ static int nofile = 0;
#endif
#endif
static void server_recv_cb(EV_P_ ev_io *w, int revents);
static void server_send_cb(EV_P_ ev_io *w, int revents);
static void remote_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_send_cb(EV_P_ ev_io *w, int revents);
static void accept_cb(EV_P_ ev_io *w, int revents);
static void signal_cb(EV_P_ ev_signal *w, int revents);
static void server_recv_cb(SS_P_ ss_io *w, int revents);
static void server_send_cb(SS_P_ ss_io *w, int revents);
static void remote_recv_cb(SS_P_ ss_io *w, int revents);
static void remote_send_cb(SS_P_ ss_io *w, int revents);
static void accept_cb(SS_P_ ss_io *w, int revents);
static void signal_cb(SS_P_ ss_signal *w, int revents);
#if defined(__MINGW32__) && !defined(LIB_ONLY)
static void plugin_watcher_cb(EV_P_ ev_io *w, int revents);
static void plugin_watcher_cb(SS_P_ ss_io *w, int revents);
#endif
static int create_and_bind(const char *addr, const char *port);
@@ -142,9 +143,9 @@ static int launch_or_create(const char *addr, const char *port);
#endif
static remote_t *create_remote(listen_ctx_t *listener, struct sockaddr *addr, int direct);
static void free_remote(remote_t *remote);
static void close_and_free_remote(EV_P_ remote_t *remote);
static void close_and_free_remote(SS_P_ remote_t *remote);
static void free_server(server_t *server);
static void close_and_free_server(EV_P_ server_t *server);
static void close_and_free_server(SS_P_ server_t *server);
static remote_t *new_remote(int fd, int timeout);
static server_t *new_server(int fd);
@@ -263,7 +264,7 @@ launch_or_create(const char *addr, const char *port)
#endif
static void
free_connections(struct ev_loop *loop)
free_connections(struct ss_loop *loop)
{
struct ss_list_item *curr, *next;
ss_list_foreach_void(&connections, curr, next) {
@@ -275,16 +276,16 @@ free_connections(struct ev_loop *loop)
}
static void
delayed_connect_cb(EV_P_ ev_timer *watcher, int revents)
delayed_connect_cb(SS_P_ ss_timer *watcher, int revents)
{
server_t *server = ss_container_of(watcher, server_t,
delayed_connect_watcher);
server_recv_cb(EV_A_ & server->recv_ctx->io, revents);
server_recv_cb(SS_A_ & server->recv_ctx->io, revents);
}
static int
server_handshake_reply(EV_P_ ev_io *w, int udp_assc, struct socks5_response *response)
server_handshake_reply(SS_P_ ss_io *w, int udp_assc, struct socks5_response *response)
{
server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
server_t *server = server_recv_ctx->server;
@@ -299,8 +300,8 @@ server_handshake_reply(EV_P_ ev_io *w, int udp_assc, struct socks5_response *res
LOGE("getsockname: %s", strerror(ss_socket_error()));
response->rep = SOCKS5_REP_CONN_REFUSED;
send(server->fd, (char *)response, sizeof(struct socks5_response), 0);
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return -1;
}
} else
@@ -326,8 +327,8 @@ server_handshake_reply(EV_P_ ev_io *w, int udp_assc, struct socks5_response *res
if (s < reply_size) {
LOGE("failed to send fake reply");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return -1;
}
if (udp_assc) {
@@ -337,8 +338,34 @@ server_handshake_reply(EV_P_ ev_io *w, int udp_assc, struct socks5_response *res
return 0;
}
struct local_dns_query {
server_t *server;
struct ss_loop *loop;
};
static void local_dns_free(void *data) { ss_free(data); }
static void local_dns_done(struct sockaddr *address, void *data)
{
struct local_dns_query *query = data;
server_t *server = query->server;
if (!server) return;
server->dns_query = NULL;
server->dns_done = 1;
server->dns_success = address != NULL;
if (address)
memcpy(&server->dns_address, address, get_sockaddr_len(address));
ss_io_start(query->loop, &server->recv_ctx->io);
/* Resume the buffered handshake without reading additional socket data. */
server_recv_cb(query->loop, &server->recv_ctx->io, SS_TIMER);
}
static int local_dns_address(server_t *server, struct sockaddr_storage *address)
{
if (!server->dns_success) return -1;
*address = server->dns_address;
return 0;
}
static int
server_handshake(EV_P_ ev_io *w, buffer_t *buf)
server_handshake(SS_P_ ss_io *w, buffer_t *buf)
{
server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
server_t *server = server_recv_ctx->server;
@@ -361,14 +388,14 @@ server_handshake(EV_P_ ev_io *w, buffer_t *buf)
if (verbose) {
LOGI("udp assc request accepted");
}
return server_handshake_reply(EV_A_ w, 1, &response);
return server_handshake_reply(SS_A_ w, 1, &response);
} else if (request->cmd != SOCKS5_CMD_CONNECT) {
LOGE("unsupported command: %d", request->cmd);
response.rep = SOCKS5_REP_CMD_NOT_SUPPORTED;
char *send_buf = (char *)&response;
send(server->fd, send_buf, 4, 0);
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return -1;
}
@@ -439,12 +466,32 @@ server_handshake(EV_P_ ev_io *w, buffer_t *buf)
response.rep = SOCKS5_REP_ADDRTYPE_NOT_SUPPORTED;
char *send_buf = (char *)&response;
send(server->fd, send_buf, 4, 0);
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return -1;
}
if (server_handshake_reply(EV_A_ w, 0, &response) < 0)
if (acl && atyp == SOCKS5_ATYP_DOMAIN && !server->dns_done
#ifdef __ANDROID__
&& !vpn
#endif
&& acl_match_host(host) >= 0) {
uint16_t numeric_port;
if (parse_numeric_port(port, &numeric_port) != 0) {
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return -1;
}
struct local_dns_query *query = ss_malloc(sizeof(*query));
query->server = server;
query->loop = loop;
server->dns_query = query;
ss_io_stop(loop, &server->recv_ctx->io);
resolv_start(host, htons(numeric_port), local_dns_done, local_dns_free, query);
return -1;
}
if (server_handshake_reply(SS_A_ w, 0, &response) < 0)
return -1;
server->stage = STAGE_STREAM;
@@ -487,7 +534,7 @@ server_handshake(EV_P_ ev_io *w, buffer_t *buf)
&& !vpn
#endif
) { // resolve domain so we can bypass domain with geoip
if (get_sockaddr(host, port, &storage, 0, ipv6first))
if (local_dns_address(server, &storage))
goto not_bypass;
resolved = 1;
switch (((struct sockaddr *)&storage)->sa_family) {
@@ -541,7 +588,7 @@ server_handshake(EV_P_ ev_io *w, buffer_t *buf)
goto not_bypass;
else
#endif
err = get_sockaddr(host, port, &storage, 0, ipv6first);
err = local_dns_address(server, &storage);
else
err = get_sockaddr(ip, port, &storage, 0, ipv6first);
if (err != -1) {
@@ -558,7 +605,7 @@ not_bypass:
if (remote == NULL) {
LOGE("invalid remote addr");
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
return -1;
}
@@ -566,8 +613,8 @@ not_bypass:
int err = crypto->encrypt(abuf, server->e_ctx, SOCKET_BUF_SIZE);
if (err) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return -1;
}
}
@@ -583,14 +630,14 @@ not_bypass:
if (buf->len > 0) {
return 0;
} else {
ev_timer_start(EV_A_ & server->delayed_connect_watcher);
ss_timer_start(SS_A_ & server->delayed_connect_watcher);
}
return -1;
}
static void
server_stream(EV_P_ ev_io *w, buffer_t *buf)
server_stream(SS_P_ ss_io *w, buffer_t *buf)
{
server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
server_t *server = server_recv_ctx->server;
@@ -598,7 +645,7 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
if (remote == NULL) {
LOGE("invalid remote");
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
return;
}
@@ -611,8 +658,8 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
if (err) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
@@ -636,8 +683,8 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
if (!not_protect) {
if (protect_socket(remote->fd) == -1) {
ERROR("protect_socket");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -652,15 +699,15 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
if (r == -1 && ss_socket_error() != CONNECT_IN_PROGRESS) {
ERROR("connect");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
// wait on remote connected event
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
ss_timer_start(SS_A_ & remote->send_ctx->watcher);
} else {
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT)
int s = -1;
@@ -738,8 +785,8 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
if (ss_socket_error() == CONNECT_IN_PROGRESS) {
// in progress, wait until connected
remote->buf->idx = 0;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
} else {
if (ss_socket_error() == EOPNOTSUPP || ss_socket_error() == EPROTONOSUPPORT ||
@@ -750,17 +797,17 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
} else {
ERROR("fast_open_connect");
}
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else {
remote->buf->len -= s;
remote->buf->idx = s;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
ss_timer_start(SS_A_ & remote->send_ctx->watcher);
return;
}
}
@@ -770,20 +817,20 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
remote->buf->idx = 0;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
} else {
ERROR("server_recv_cb_send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else if (s < (int)(remote->buf->len)) {
remote->buf->len -= s;
remote->buf->idx = s;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
} else {
remote->buf->idx = 0;
@@ -793,7 +840,7 @@ server_stream(EV_P_ ev_io *w, buffer_t *buf)
}
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
server_recv_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
server_t *server = server_recv_ctx->server;
@@ -801,7 +848,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
buffer_t *buf;
ssize_t r;
ev_timer_stop(EV_A_ & server->delayed_connect_watcher);
ss_timer_stop(SS_A_ & server->delayed_connect_watcher);
if (remote == NULL) {
buf = server->buf;
@@ -809,13 +856,13 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
buf = remote->buf;
}
if (revents != EV_TIMER) {
if (revents != SS_TIMER) {
r = recv(server->fd, buf->data + buf->len, SOCKET_BUF_SIZE - buf->len, 0);
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -825,8 +872,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
} else {
if (verbose)
ERROR("server_recv_cb_recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -836,7 +883,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
while (1) {
// local socks5 server
if (server->stage == STAGE_STREAM) {
server_stream(EV_A_ w, buf);
server_stream(SS_A_ w, buf);
// all processed
return;
@@ -852,8 +899,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (buf->len < 1)
return;
if (buf->data[0] != SVERSION) {
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
if (buf->len < sizeof(struct method_select_request)) {
@@ -876,8 +923,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
char *send_buf = (char *)&response;
send(server->fd, send_buf, sizeof(response), 0);
if (response.method == METHOD_UNACCEPTABLE) {
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
@@ -892,7 +939,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
buf->len = 0;
return;
} else if (server->stage == STAGE_HANDSHAKE) {
int ret = server_handshake(EV_A_ w, buf);
int ret = server_handshake(SS_A_ w, buf);
if (ret)
return;
}
@@ -900,15 +947,15 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
static void
server_send_cb(EV_P_ ev_io *w, int revents)
server_send_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_send_ctx = (server_ctx_t *)w;
server_t *server = server_send_ctx->server;
remote_t *remote = server->remote;
if (server->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -917,8 +964,8 @@ server_send_cb(EV_P_ ev_io *w, int revents)
if (s == -1) {
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("server_send_cb_send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < (ssize_t)(server->buf->len)) {
@@ -930,8 +977,8 @@ server_send_cb(EV_P_ ev_io *w, int revents)
// all sent out, wait for reading
server->buf->len = 0;
server->buf->idx = 0;
ev_io_stop(EV_A_ & server_send_ctx->io);
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_stop(SS_A_ & server_send_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
return;
}
}
@@ -941,7 +988,7 @@ server_send_cb(EV_P_ ev_io *w, int revents)
void
stat_update_cb()
{
ev_tstamp now = ev_time();
ss_tstamp now = ss_time();
if (now - last > 0.5) {
send_traffic_stat(tx, rx);
last = now;
@@ -951,7 +998,7 @@ stat_update_cb()
#endif
static void
remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
remote_timeout_cb(SS_P_ ss_timer *watcher, int revents)
{
remote_ctx_t *remote_ctx
= ss_container_of(watcher, remote_ctx_t, watcher);
@@ -963,12 +1010,12 @@ remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
LOGI("TCP connection timeout");
}
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
static void
remote_recv_cb(EV_P_ ev_io *w, int revents)
remote_recv_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_recv_ctx->remote;
@@ -978,8 +1025,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -988,8 +1035,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
ERROR("remote_recv_cb_recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -1004,8 +1051,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
int err = crypto->decrypt(server->buf, server->d_ctx, SOCKET_BUF_SIZE);
if (err == CRYPTO_ERROR) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (err == CRYPTO_NEED_MORE) {
return; // Wait for more
@@ -1018,19 +1065,19 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
server->buf->idx = 0;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
} else {
ERROR("remote_recv_cb_send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else if (s < (int)(server->buf->len)) {
server->buf->len -= s;
server->buf->idx = s;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
}
// Disable TCP_NODELAY after the first response are sent
@@ -1043,7 +1090,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
}
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
remote_send_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_send_ctx->remote;
@@ -1068,8 +1115,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
} else {
ERROR("WSAGetOverlappedResult");
// not connected
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -1086,28 +1133,28 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
if (r == 0) {
remote_send_ctx->connected = 1;
ev_timer_stop(EV_A_ & remote_send_ctx->watcher);
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_timer_stop(SS_A_ & remote_send_ctx->watcher);
ss_io_start(SS_A_ & remote->recv_ctx->io);
// no need to send any data
if (remote->buf->len == 0) {
ev_io_stop(EV_A_ & remote_send_ctx->io);
ev_io_start(EV_A_ & server->recv_ctx->io);
ss_io_stop(SS_A_ & remote_send_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
return;
}
} else {
// not connected
ERROR("getpeername");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
if (remote->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -1117,8 +1164,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("remote_send_cb_send");
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < (ssize_t)(remote->buf->len)) {
@@ -1130,8 +1177,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
// all sent out, wait for reading
remote->buf->len = 0;
remote->buf->idx = 0;
ev_io_stop(EV_A_ & remote_send_ctx->io);
ev_io_start(EV_A_ & server->recv_ctx->io);
ss_io_stop(SS_A_ & remote_send_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
}
}
}
@@ -1156,9 +1203,9 @@ new_remote(int fd, int timeout)
remote->recv_ctx->remote = remote;
remote->send_ctx->remote = remote;
ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ);
ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE);
ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb,
ss_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, SS_READ);
ss_io_init(&remote->send_ctx->io, remote_send_cb, fd, SS_WRITE);
ss_timer_init(&remote->send_ctx->watcher, remote_timeout_cb,
min(MAX_CONNECT_TIMEOUT, timeout), 0);
return remote;
@@ -1180,12 +1227,12 @@ free_remote(remote_t *remote)
}
static void
close_and_free_remote(EV_P_ remote_t *remote)
close_and_free_remote(SS_P_ remote_t *remote)
{
if (remote != NULL) {
ev_timer_stop(EV_A_ & remote->send_ctx->watcher);
ev_io_stop(EV_A_ & remote->send_ctx->io);
ev_io_stop(EV_A_ & remote->recv_ctx->io);
ss_timer_stop(SS_A_ & remote->send_ctx->watcher);
ss_io_stop(SS_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & remote->recv_ctx->io);
ss_socket_close(remote->fd);
free_remote(remote);
}
@@ -1220,10 +1267,10 @@ new_server(int fd)
crypto->ctx_init(crypto->cipher, server->d_ctx, 0);
cipher_ctx_pair(server->e_ctx, server->d_ctx);
ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ);
ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE);
ss_io_init(&server->recv_ctx->io, server_recv_cb, fd, SS_READ);
ss_io_init(&server->send_ctx->io, server_send_cb, fd, SS_WRITE);
ev_timer_init(&server->delayed_connect_watcher,
ss_timer_init(&server->delayed_connect_watcher,
delayed_connect_cb, 0.05, 0);
ss_list_add(&connections, &server->entries);
@@ -1261,12 +1308,16 @@ free_server(server_t *server)
}
static void
close_and_free_server(EV_P_ server_t *server)
close_and_free_server(SS_P_ server_t *server)
{
if (server != NULL) {
ev_io_stop(EV_A_ & server->send_ctx->io);
ev_io_stop(EV_A_ & server->recv_ctx->io);
ev_timer_stop(EV_A_ & server->delayed_connect_watcher);
if (server->dns_query) {
server->dns_query->server = NULL;
server->dns_query = NULL;
}
ss_io_stop(SS_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & server->recv_ctx->io);
ss_timer_stop(SS_A_ & server->delayed_connect_watcher);
ss_socket_close(server->fd);
free_server(server);
}
@@ -1353,9 +1404,9 @@ create_remote(listen_ctx_t *listener,
}
static void
signal_cb(EV_P_ ev_signal *w, int revents)
signal_cb(SS_P_ ss_signal *w, int revents)
{
if (revents & EV_SIGNAL) {
if (revents & SS_SIGNAL) {
switch (w->signum) {
#ifndef __MINGW32__
case SIGCHLD:
@@ -1368,24 +1419,24 @@ signal_cb(EV_P_ ev_signal *w, int revents)
#endif
case SIGINT:
case SIGTERM:
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
ev_signal_stop(EV_DEFAULT, &sigusr1_watcher);
ss_signal_stop(SS_DEFAULT, &sigchld_watcher);
ss_signal_stop(SS_DEFAULT, &sigusr1_watcher);
#else
#ifndef LIB_ONLY
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
ss_io_stop(SS_DEFAULT, &plugin_watcher.io);
#endif
#endif
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
}
}
#if defined(__MINGW32__) && !defined(LIB_ONLY)
static void
plugin_watcher_cb(EV_P_ ev_io *w, int revents)
plugin_watcher_cb(SS_P_ ss_io *w, int revents)
{
char buf[1];
SOCKET fd = ss_accept(plugin_watcher.fd, NULL, NULL);
@@ -1396,16 +1447,16 @@ plugin_watcher_cb(EV_P_ ev_io *w, int revents)
closesocket(fd);
LOGE("plugin service exit unexpectedly");
ret_val = -1;
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
ss_io_stop(SS_DEFAULT, &plugin_watcher.io);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
#endif
void
accept_cb(EV_P_ ev_io *w, int revents)
accept_cb(SS_P_ ss_io *w, int revents)
{
listen_ctx_t *listener = (listen_ctx_t *)w;
int serverfd = ss_accept(listener->fd, NULL, NULL);
@@ -1423,7 +1474,7 @@ accept_cb(EV_P_ ev_io *w, int revents)
server_t *server = new_server(serverfd);
server->listener = listener;
ev_io_start(EV_A_ & server->recv_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
}
#ifndef LIB_ONLY
@@ -1896,8 +1947,8 @@ main(int argc, char **argv)
break;
}
plugin_watcher.fd = fd;
ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ);
ev_io_start(EV_DEFAULT, &plugin_watcher.io);
ss_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, SS_READ);
ss_io_start(SS_DEFAULT, &plugin_watcher.io);
plugin_watcher.valid = 1;
} while (0);
if (!plugin_watcher.valid) {
@@ -1972,13 +2023,13 @@ main(int argc, char **argv)
listen_ctx.mptcp = mptcp;
// Setup signal handler
ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ev_signal_start(EV_DEFAULT, &sigint_watcher);
ev_signal_start(EV_DEFAULT, &sigterm_watcher);
ss_signal_init(&sigint_watcher, signal_cb, SIGINT);
ss_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ss_signal_start(SS_DEFAULT, &sigint_watcher);
ss_signal_start(SS_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ev_signal_start(EV_DEFAULT, &sigchld_watcher);
ss_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ss_signal_start(SS_DEFAULT, &sigchld_watcher);
#endif
if (ss_is_ipv6addr(local_addr))
@@ -1986,7 +2037,8 @@ main(int argc, char **argv)
else
LOGI("listening at %s:%s", local_addr, local_port);
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
if (acl) resolv_init(loop, NULL, ipv6first);
if (mode != UDP_ONLY) {
// Setup socket
@@ -2006,8 +2058,8 @@ main(int argc, char **argv)
listen_ctx.fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
ss_io_init(&listen_ctx.io, accept_cb, listenfd, SS_READ);
ss_io_start(loop, &listen_ctx.io);
}
// Setup UDP
@@ -2049,7 +2101,7 @@ main(int argc, char **argv)
ss_list_init(&connections);
// Enter the loop
ev_run(loop, 0);
ss_run(loop, 0);
if (verbose) {
LOGI("closed gracefully");
@@ -2061,7 +2113,7 @@ main(int argc, char **argv)
}
if (mode != UDP_ONLY) {
ev_io_stop(loop, &listen_ctx.io);
ss_io_stop(loop, &listen_ctx.io);
free_connections(loop);
for (i = 0; i < listen_ctx.remote_num; i++)
@@ -2072,6 +2124,8 @@ main(int argc, char **argv)
if (mode != TCP_ONLY) {
free_udprelay();
}
if (acl) resolv_shutdown(loop);
ss_loop_destroy(loop);
#ifdef __MINGW32__
if (plugin_watcher.valid) {
@@ -2132,13 +2186,13 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
signal(SIGABRT, SIG_IGN);
#endif
ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ev_signal_start(EV_DEFAULT, &sigint_watcher);
ev_signal_start(EV_DEFAULT, &sigterm_watcher);
ss_signal_init(&sigint_watcher, signal_cb, SIGINT);
ss_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ss_signal_start(SS_DEFAULT, &sigint_watcher);
ss_signal_start(SS_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_init(&sigusr1_watcher, signal_cb, SIGUSR1);
ev_signal_start(EV_DEFAULT, &sigusr1_watcher);
ss_signal_init(&sigusr1_watcher, signal_cb, SIGUSR1);
ss_signal_start(SS_DEFAULT, &sigusr1_watcher);
#endif
// Setup keys
@@ -2149,12 +2203,13 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
struct sockaddr_storage storage;
memset(&storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(remote_host, remote_port_str, &storage, 0, ipv6first) == -1) {
if (get_sockaddr(remote_host, remote_port_str, &storage, 1, ipv6first) == -1) {
return -1;
}
// Setup proxy context
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
if (acl) resolv_init(loop, NULL, ipv6first);
struct sockaddr *remote_addr_tmp[MAX_REMOTE_NUM];
listen_ctx_t listen_ctx;
@@ -2188,8 +2243,8 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
listen_ctx.fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
ss_io_init(&listen_ctx.io, accept_cb, listenfd, SS_READ);
ss_io_start(loop, &listen_ctx.io);
}
// Setup UDP
@@ -2211,7 +2266,7 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
}
// Enter the loop
ev_run(loop, 0);
ss_run(loop, 0);
if (verbose) {
LOGI("closed gracefully");
@@ -2219,7 +2274,7 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
// Clean up
if (mode != UDP_ONLY) {
ev_io_stop(loop, &listen_ctx.io);
ss_io_stop(loop, &listen_ctx.io);
free_connections(loop);
ss_socket_close(listen_ctx.fd);
}
@@ -2227,6 +2282,8 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
if (mode != TCP_ONLY) {
free_udprelay();
}
if (acl) resolv_shutdown(loop);
ss_loop_destroy(loop);
#ifdef __MINGW32__
winsock_cleanup();
+9 -10
View File
@@ -25,11 +25,7 @@
#include "core.h"
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
#else
#include <ev.h>
#endif
#include "ss_event.h"
#ifdef __MINGW32__
#include "ss_windows.h"
@@ -41,7 +37,7 @@
#include "common.h"
typedef struct listen_ctx {
ev_io io;
ss_io io;
char *iface;
int remote_num;
int timeout;
@@ -51,7 +47,7 @@ typedef struct listen_ctx {
} listen_ctx_t;
typedef struct server_ctx {
ev_io io;
ss_io io;
int connected;
struct server *server;
} server_ctx_t;
@@ -59,6 +55,9 @@ typedef struct server_ctx {
typedef struct server {
int fd;
int stage;
struct local_dns_query *dns_query;
int dns_done, dns_success;
struct sockaddr_storage dns_address;
cipher_ctx_t *e_ctx;
cipher_ctx_t *d_ctx;
@@ -70,14 +69,14 @@ typedef struct server {
buffer_t *buf;
buffer_t *abuf;
ev_timer delayed_connect_watcher;
ss_timer delayed_connect_watcher;
struct ss_list_item entries;
} server_t;
typedef struct remote_ctx {
ev_io io;
ev_timer watcher;
ss_io io;
ss_timer watcher;
int connected;
struct remote *remote;
+16 -16
View File
@@ -952,7 +952,7 @@ update_stat(char *port, uint64_t traffic)
}
static void
manager_recv_cb(EV_P_ ev_io *w, int revents)
manager_recv_cb(SS_P_ ss_io *w, int revents)
{
struct manager_ctx *manager = (struct manager_ctx *)w;
socklen_t len;
@@ -1146,13 +1146,13 @@ ERROR_MSG:
}
static void
signal_cb(EV_P_ ev_signal *w, int revents)
signal_cb(SS_P_ ss_signal *w, int revents)
{
if (revents & EV_SIGNAL) {
if (revents & SS_SIGNAL) {
switch (w->signum) {
case SIGINT:
case SIGTERM:
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
}
}
@@ -1551,12 +1551,12 @@ main(int argc, char **argv)
signal(SIGCHLD, SIG_IGN);
signal(SIGABRT, SIG_IGN);
struct ev_signal sigint_watcher;
struct ev_signal sigterm_watcher;
ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ev_signal_start(EV_DEFAULT, &sigint_watcher);
ev_signal_start(EV_DEFAULT, &sigterm_watcher);
struct ss_signal sigint_watcher;
struct ss_signal sigterm_watcher;
ss_signal_init(&sigint_watcher, signal_cb, SIGINT);
ss_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ss_signal_start(SS_DEFAULT, &sigint_watcher);
ss_signal_start(SS_DEFAULT, &sigterm_watcher);
struct manager_ctx manager;
memset(&manager, 0, sizeof(struct manager_ctx));
@@ -1586,7 +1586,7 @@ main(int argc, char **argv)
#endif
// initialize ev loop
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
// Clean up all existed processes
DIR *dp;
@@ -1673,11 +1673,11 @@ main(int argc, char **argv)
}
manager.fd = sfd;
ev_io_init(&manager.io, manager_recv_cb, manager.fd, EV_READ);
ev_io_start(loop, &manager.io);
ss_io_init(&manager.io, manager_recv_cb, manager.fd, SS_READ);
ss_io_start(loop, &manager.io);
// start ev loop
ev_run(loop, 0);
ss_run(loop, 0);
if (verbose) {
LOGI("closed gracefully");
@@ -1692,8 +1692,8 @@ main(int argc, char **argv)
ss_free(server);
}
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
ss_free(working_dir);
free_addr(&ip_addr);
+2 -6
View File
@@ -27,18 +27,14 @@
#include "core.h"
#include "uthash.h"
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
#else
#include <ev.h>
#endif
#include "ss_event.h"
#include "jconf.h"
#include "common.h"
struct manager_ctx {
ev_io io;
ss_io io;
int fd;
int fast_open;
int no_delay;
+3 -1
View File
@@ -57,7 +57,7 @@ extern int verbose;
static const char valid_label_bytes[] =
"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
static int
int
parse_numeric_port(const char *port, uint16_t *port_out)
{
char *endptr;
@@ -178,6 +178,8 @@ get_sockaddr(char *host, char *port,
}
return 0;
} else {
/* Event-loop callers must use the asynchronous resolver for names. */
if (!block) return -1;
#ifdef __ANDROID__
extern int vpn;
if (vpn) {
+1
View File
@@ -85,6 +85,7 @@ static const char mptcp_enabled_values[] = { MPTCP_ENABLED, 0 };
/** byte size of ip6 address */
#define INET6_SIZE 16
int parse_numeric_port(const char *port, uint16_t *port_out);
size_t get_sockaddr_len(struct sockaddr *addr);
ssize_t get_sockaddr(char *host, char *port,
struct sockaddr_storage *storage, int block,
+114 -114
View File
@@ -73,19 +73,19 @@
#define IPV6_TRANSPARENT 75
#endif
static void accept_cb(EV_P_ ev_io *w, int revents);
static void server_recv_cb(EV_P_ ev_io *w, int revents);
static void server_send_cb(EV_P_ ev_io *w, int revents);
static void remote_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_send_cb(EV_P_ ev_io *w, int revents);
static void accept_cb(SS_P_ ss_io *w, int revents);
static void server_recv_cb(SS_P_ ss_io *w, int revents);
static void server_send_cb(SS_P_ ss_io *w, int revents);
static void remote_recv_cb(SS_P_ ss_io *w, int revents);
static void remote_send_cb(SS_P_ ss_io *w, int revents);
static remote_t *new_remote(int fd, int timeout);
static server_t *new_server(int fd);
static void free_remote(remote_t *remote);
static void close_and_free_remote(EV_P_ remote_t *remote);
static void close_and_free_remote(SS_P_ remote_t *remote);
static void free_server(server_t *server);
static void close_and_free_server(EV_P_ server_t *server);
static void close_and_free_server(SS_P_ server_t *server);
int verbose = 0;
int reuse_port = 0;
@@ -105,9 +105,9 @@ int fast_open = 0;
static int no_delay = 0;
static int ret_val = 0;
static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher;
static struct ev_signal sigchld_watcher;
static struct ss_signal sigint_watcher;
static struct ss_signal sigterm_watcher;
static struct ss_signal sigchld_watcher;
static int tcp_tproxy = 0; /* use tproxy instead of redirect (for tcp) */
@@ -227,21 +227,21 @@ create_and_bind(const char *addr, const char *port)
}
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
server_recv_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
server_t *server = server_recv_ctx->server;
remote_t *remote = server->remote;
ev_timer_stop(EV_A_ & server->delayed_connect_watcher);
ss_timer_stop(SS_A_ & server->delayed_connect_watcher);
ssize_t r = recv(server->fd, remote->buf->data + remote->buf->len,
SOCKET_BUF_SIZE - remote->buf->len, 0);
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -250,8 +250,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
ERROR("server recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -277,8 +277,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
if (!remote->send_ctx->connected) {
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
}
@@ -286,8 +286,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (err) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
@@ -297,20 +297,20 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
remote->buf->idx = 0;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
} else {
ERROR("send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else if (s < remote->buf->len) {
remote->buf->len -= s;
remote->buf->idx = s;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
} else {
remote->buf->idx = 0;
@@ -319,15 +319,15 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
static void
server_send_cb(EV_P_ ev_io *w, int revents)
server_send_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_send_ctx = (server_ctx_t *)w;
server_t *server = server_send_ctx->server;
remote_t *remote = server->remote;
if (server->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -336,8 +336,8 @@ server_send_cb(EV_P_ ev_io *w, int revents)
if (s == -1) {
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < server->buf->len) {
@@ -349,14 +349,14 @@ server_send_cb(EV_P_ ev_io *w, int revents)
// all sent out, wait for reading
server->buf->len = 0;
server->buf->idx = 0;
ev_io_stop(EV_A_ & server_send_ctx->io);
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_stop(SS_A_ & server_send_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
}
}
}
static void
delayed_connect_cb(EV_P_ ev_timer *watcher, int revents)
delayed_connect_cb(SS_P_ ss_timer *watcher, int revents)
{
server_t *server = ss_container_of(watcher, server_t,
delayed_connect_watcher);
@@ -369,18 +369,18 @@ delayed_connect_cb(EV_P_ ev_timer *watcher, int revents)
if (r == -1 && ss_socket_error() != CONNECT_IN_PROGRESS) {
ERROR("connect");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// listen to remote connected event
ev_io_start(EV_A_ & remote->send_ctx->io);
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
ss_io_start(SS_A_ & remote->send_ctx->io);
ss_timer_start(SS_A_ & remote->send_ctx->watcher);
}
}
static void
remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
remote_timeout_cb(SS_P_ ss_timer *watcher, int revents)
{
remote_ctx_t *remote_ctx
= ss_container_of(watcher, remote_ctx_t, watcher);
@@ -388,14 +388,14 @@ remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
remote_t *remote = remote_ctx->remote;
server_t *server = remote->server;
ev_timer_stop(EV_A_ watcher);
ss_timer_stop(SS_A_ watcher);
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
static void
remote_recv_cb(EV_P_ ev_io *w, int revents)
remote_recv_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_recv_ctx->remote;
@@ -405,8 +405,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -415,8 +415,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
ERROR("remote recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -426,8 +426,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
int err = crypto->decrypt(server->buf, server->d_ctx, SOCKET_BUF_SIZE);
if (err == CRYPTO_ERROR) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (err == CRYPTO_NEED_MORE) {
return; // Wait for more
@@ -439,19 +439,19 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
server->buf->idx = 0;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
} else {
ERROR("send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else if (s < server->buf->len) {
server->buf->len -= s;
server->buf->idx = s;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
}
// Disable TCP_NODELAY after the first response are sent
@@ -464,13 +464,13 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
}
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
remote_send_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_send_ctx->remote;
server_t *server = remote->server;
ev_timer_stop(EV_A_ & remote_send_ctx->watcher);
ss_timer_stop(SS_A_ & remote_send_ctx->watcher);
if (!remote_send_ctx->connected) {
int r = 0;
@@ -483,9 +483,9 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (r == 0) {
remote_send_ctx->connected = 1;
ev_io_stop(EV_A_ & remote_send_ctx->io);
ev_io_stop(EV_A_ & server->recv_ctx->io);
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_stop(SS_A_ & remote_send_ctx->io);
ss_io_stop(SS_A_ & server->recv_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
// send destaddr
buffer_t ss_addr_to_send;
@@ -520,8 +520,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (err) {
LOGE("invalid password or cipher");
bfree(abuf);
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
@@ -529,8 +529,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (err) {
LOGE("invalid password or cipher");
bfree(abuf);
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
@@ -539,16 +539,16 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
} else {
ERROR("getpeername");
// not connected
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
if (remote->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -575,8 +575,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (s == -1) {
if (ss_socket_error() == CONNECT_IN_PROGRESS) {
ev_io_start(EV_A_ & remote_send_ctx->io);
ev_timer_start(EV_A_ & remote_send_ctx->watcher);
ss_io_start(SS_A_ & remote_send_ctx->io);
ss_timer_start(SS_A_ & remote_send_ctx->watcher);
} else {
if (ss_socket_error() == EOPNOTSUPP || ss_socket_error() == EPROTONOSUPPORT ||
ss_socket_error() == ENOPROTOOPT) {
@@ -585,8 +585,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
} else {
ERROR("fast_open_connect");
}
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
}
@@ -599,22 +599,22 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("send");
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < remote->buf->len) {
// partly sent, move memory, wait for the next time to send
remote->buf->len -= s;
remote->buf->idx += s;
ev_io_start(EV_A_ & remote_send_ctx->io);
ss_io_start(SS_A_ & remote_send_ctx->io);
return;
} else {
// all sent out, wait for reading
remote->buf->len = 0;
remote->buf->idx = 0;
ev_io_stop(EV_A_ & remote_send_ctx->io);
ev_io_start(EV_A_ & server->recv_ctx->io);
ss_io_stop(SS_A_ & remote_send_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
}
}
}
@@ -637,9 +637,9 @@ new_remote(int fd, int timeout)
remote->send_ctx->remote = remote;
remote->send_ctx->connected = 0;
ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ);
ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE);
ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb,
ss_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, SS_READ);
ss_io_init(&remote->send_ctx->io, remote_send_cb, fd, SS_WRITE);
ss_timer_init(&remote->send_ctx->watcher, remote_timeout_cb,
min(MAX_CONNECT_TIMEOUT, timeout), 0);
return remote;
@@ -661,12 +661,12 @@ free_remote(remote_t *remote)
}
static void
close_and_free_remote(EV_P_ remote_t *remote)
close_and_free_remote(SS_P_ remote_t *remote)
{
if (remote != NULL) {
ev_timer_stop(EV_A_ & remote->send_ctx->watcher);
ev_io_stop(EV_A_ & remote->send_ctx->io);
ev_io_stop(EV_A_ & remote->recv_ctx->io);
ss_timer_stop(SS_A_ & remote->send_ctx->watcher);
ss_io_stop(SS_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & remote->recv_ctx->io);
ss_socket_close(remote->fd);
free_remote(remote);
}
@@ -696,10 +696,10 @@ new_server(int fd)
crypto->ctx_init(crypto->cipher, server->d_ctx, 0);
cipher_ctx_pair(server->e_ctx, server->d_ctx);
ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ);
ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE);
ss_io_init(&server->recv_ctx->io, server_recv_cb, fd, SS_READ);
ss_io_init(&server->send_ctx->io, server_send_cb, fd, SS_WRITE);
ev_timer_init(&server->delayed_connect_watcher, delayed_connect_cb, 0.05,
ss_timer_init(&server->delayed_connect_watcher, delayed_connect_cb, 0.05,
0);
return server;
@@ -729,19 +729,19 @@ free_server(server_t *server)
}
static void
close_and_free_server(EV_P_ server_t *server)
close_and_free_server(SS_P_ server_t *server)
{
if (server != NULL) {
ev_io_stop(EV_A_ & server->send_ctx->io);
ev_io_stop(EV_A_ & server->recv_ctx->io);
ev_timer_stop(EV_A_ & server->delayed_connect_watcher);
ss_io_stop(SS_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & server->recv_ctx->io);
ss_timer_stop(SS_A_ & server->delayed_connect_watcher);
ss_socket_close(server->fd);
free_server(server);
}
}
static void
accept_cb(EV_P_ ev_io *w, int revents)
accept_cb(SS_P_ ss_io *w, int revents)
{
listen_ctx_t *listener = (listen_ctx_t *)w;
struct sockaddr_storage destaddr;
@@ -850,27 +850,27 @@ accept_cb(EV_P_ ev_io *w, int revents)
if (fast_open) {
// save remote addr for fast open
remote->addr = remote_addr;
ev_timer_start(EV_A_ & server->delayed_connect_watcher);
ss_timer_start(SS_A_ & server->delayed_connect_watcher);
} else {
int r = connect(remotefd, remote_addr, get_sockaddr_len(remote_addr));
if (r == -1 && ss_socket_error() != CONNECT_IN_PROGRESS) {
ERROR("connect");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
// listen to remote connected event
ev_io_start(EV_A_ & remote->send_ctx->io);
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
ss_io_start(SS_A_ & remote->send_ctx->io);
ss_timer_start(SS_A_ & remote->send_ctx->watcher);
}
ev_io_start(EV_A_ & server->recv_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
}
static void
signal_cb(EV_P_ ev_signal *w, int revents)
signal_cb(SS_P_ ss_signal *w, int revents)
{
if (revents & EV_SIGNAL) {
if (revents & SS_SIGNAL) {
switch (w->signum) {
case SIGCHLD:
if (!is_plugin_running()) {
@@ -880,11 +880,11 @@ signal_cb(EV_P_ ev_signal *w, int revents)
return;
case SIGINT:
case SIGTERM:
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
ss_signal_stop(SS_DEFAULT, &sigchld_watcher);
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
}
}
@@ -1291,12 +1291,12 @@ main(int argc, char **argv)
signal(SIGPIPE, SIG_IGN);
signal(SIGABRT, SIG_IGN);
ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ev_signal_start(EV_DEFAULT, &sigint_watcher);
ev_signal_start(EV_DEFAULT, &sigterm_watcher);
ev_signal_start(EV_DEFAULT, &sigchld_watcher);
ss_signal_init(&sigint_watcher, signal_cb, SIGINT);
ss_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ss_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ss_signal_start(SS_DEFAULT, &sigint_watcher);
ss_signal_start(SS_DEFAULT, &sigterm_watcher);
ss_signal_start(SS_DEFAULT, &sigchld_watcher);
// Setup keys
LOGI("initializing ciphers... %s", method);
@@ -1331,7 +1331,7 @@ main(int argc, char **argv)
listen_ctx.timeout = timeout_secs;
listen_ctx.mptcp = mptcp;
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
listen_ctx_t *listen_ctx_current = &listen_ctx;
do {
@@ -1355,8 +1355,8 @@ main(int argc, char **argv)
listen_ctx_current->fd = listenfd;
ev_io_init(&listen_ctx_current->io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx_current->io);
ss_io_init(&listen_ctx_current->io, accept_cb, listenfd, SS_READ);
ss_io_start(loop, &listen_ctx_current->io);
}
// Setup UDP
@@ -1399,7 +1399,7 @@ main(int argc, char **argv)
LOGI("running from root user");
}
ev_run(loop, 0);
ss_run(loop, 0);
if (plugin != NULL) {
stop_plugin();
+6 -10
View File
@@ -22,17 +22,13 @@
#ifndef _REDIR_H
#define _REDIR_H
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
#else
#include <ev.h>
#endif
#include "ss_event.h"
#include "crypto.h"
#include "jconf.h"
typedef struct listen_ctx {
ev_io io;
ss_io io;
int remote_num;
int timeout;
int fd;
@@ -42,7 +38,7 @@ typedef struct listen_ctx {
} listen_ctx_t;
typedef struct server_ctx {
ev_io io;
ss_io io;
int connected;
struct server *server;
} server_ctx_t;
@@ -59,12 +55,12 @@ typedef struct server {
struct remote *remote;
struct sockaddr_storage destaddr;
ev_timer delayed_connect_watcher;
ss_timer delayed_connect_watcher;
} server_t;
typedef struct remote_ctx {
ev_io io;
ev_timer watcher;
ss_io io;
ss_timer watcher;
int connected;
struct remote *remote;
} remote_ctx_t;
+52 -62
View File
@@ -43,11 +43,7 @@
#endif
#include <ares.h>
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
#else
#include <ev.h>
#endif
#include "ss_event.h"
#include "core.h"
@@ -59,14 +55,17 @@
* Implement DNS resolution interface using libc-ares
*/
#define SS_NUM_IOS 6
#define SS_INVALID_FD -1
#define SS_TIMER_AFTER 1.0
struct resolv_io {
ss_io io;
struct resolv_io *next;
};
struct resolv_ctx {
struct ev_io ios[SS_NUM_IOS];
struct ev_timer timer;
ev_tstamp last_tick;
struct resolv_io *ios;
struct ss_timer timer;
ss_tstamp last_tick;
ares_channel channel;
struct ares_options options;
@@ -90,7 +89,7 @@ struct resolv_query {
extern int verbose;
static struct resolv_ctx default_ctx;
static struct ev_loop *default_loop;
static struct ss_loop *default_loop;
enum {
MODE_IPV4_FIRST = 0,
@@ -99,8 +98,8 @@ enum {
static int resolv_mode = MODE_IPV4_FIRST;
static void resolv_sock_cb(struct ev_loop *, struct ev_io *, int);
static void resolv_timer_cb(struct ev_loop *, struct ev_timer *, int);
static void resolv_sock_cb(struct ss_loop *, struct ss_io *, int);
static void resolv_timer_cb(struct ss_loop *, struct ss_timer *, int);
static void resolv_sock_state_cb(void *, ares_socket_t, int, int);
static void dns_query_v4_cb(void *, int, int, struct hostent *);
@@ -116,22 +115,22 @@ static struct sockaddr *choose_any(struct resolv_query *);
* DNS UDP socket activity callback
*/
static void
resolv_sock_cb(EV_P_ ev_io *w, int revents)
resolv_sock_cb(SS_P_ ss_io *w, int revents)
{
ares_socket_t rfd = ARES_SOCKET_BAD, wfd = ARES_SOCKET_BAD;
if (revents & EV_READ)
if (revents & SS_READ)
rfd = w->fd;
if (revents & EV_WRITE)
if (revents & SS_WRITE)
wfd = w->fd;
default_ctx.last_tick = ev_now(default_loop);
default_ctx.last_tick = ss_now(default_loop);
ares_process_fd(default_ctx.channel, rfd, wfd);
}
int
resolv_init(struct ev_loop *loop, char *nameservers, int ipv6first)
resolv_init(struct ss_loop *loop, char *nameservers, int ipv6first)
{
int status;
@@ -176,22 +175,23 @@ resolv_init(struct ev_loop *loop, char *nameservers, int ipv6first)
FATAL("failed to set nameservers");
}
for (int i = 0; i < SS_NUM_IOS; i++)
ev_io_init(&default_ctx.ios[i], resolv_sock_cb, SS_INVALID_FD, 0);
default_ctx.last_tick = ev_now(default_loop);
ev_init(&default_ctx.timer, resolv_timer_cb);
default_ctx.last_tick = ss_now(default_loop);
ss_timer_init(&default_ctx.timer, resolv_timer_cb, 0, 0);
resolv_timer_cb(default_loop, &default_ctx.timer, 0);
return 0;
}
void
resolv_shutdown(struct ev_loop *loop)
resolv_shutdown(struct ss_loop *loop)
{
ev_timer_stop(default_loop, &default_ctx.timer);
for (int i = 0; i < SS_NUM_IOS; i++)
ev_io_stop(default_loop, &default_ctx.ios[i]);
ss_timer_stop(default_loop, &default_ctx.timer);
while (default_ctx.ios) {
struct resolv_io *node = default_ctx.ios;
default_ctx.ios = node->next;
ss_io_stop(default_loop, &node->io);
ss_free(node);
}
ares_cancel(default_ctx.channel);
ares_destroy(default_ctx.channel);
@@ -431,23 +431,23 @@ all_requests_are_null(struct resolv_query *query)
* Timer callback
*/
static void
resolv_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
resolv_timer_cb(struct ss_loop *loop, struct ss_timer *w, int revents)
{
struct resolv_ctx *ctx = ss_container_of(w, struct resolv_ctx, timer);
struct resolv_ctx *ctx = &default_ctx;
ev_tstamp now = ev_now(default_loop);
ev_tstamp after = ctx->last_tick - now + SS_TIMER_AFTER;
ss_tstamp now = ss_now(default_loop);
ss_tstamp after = ctx->last_tick - now + SS_TIMER_AFTER;
if (after < 0.0) {
ctx->last_tick = now;
ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
ev_timer_set(w, SS_TIMER_AFTER, 0.0);
ss_timer_set(w, SS_TIMER_AFTER, 0.0);
} else {
ev_timer_set(w, after, 0.0);
ss_timer_set(w, after, 0.0);
}
ev_timer_start(loop, w);
ss_timer_start(loop, w);
}
/*
@@ -457,35 +457,25 @@ static void
resolv_sock_state_cb(void *data, ares_socket_t s, int read, int write)
{
struct resolv_ctx *ctx = (struct resolv_ctx *)data;
int events = (read ? EV_READ : 0) | (write ? EV_WRITE : 0);
int events = (read ? SS_READ : 0) | (write ? SS_WRITE : 0);
int i = 0, ffi = -1;
for (; i < SS_NUM_IOS; i++) {
if (ctx->ios[i].fd == s) {
break;
}
if (ffi < 0 && ctx->ios[i].fd == SS_INVALID_FD) {
// first free index
ffi = i;
struct resolv_io **entry = &ctx->ios;
while (*entry && (ares_socket_t)(unsigned int)(*entry)->io.fd != s)
entry = &(*entry)->next;
struct resolv_io *node = *entry;
if (node) ss_io_stop(default_loop, &node->io);
if (!events) {
if (node) {
*entry = node->next;
ss_free(node);
}
return;
}
if (i < SS_NUM_IOS) {
ev_io_stop(default_loop, &ctx->ios[i]);
} else if (ffi > -1) {
i = ffi;
} else {
LOGE("failed to find free I/O watcher slot for DNS query");
// last resort: stop io and re-use slot, will cause timeout
i = 0;
ev_io_stop(default_loop, &ctx->ios[i]);
}
if (events) {
ev_io_set(&ctx->ios[i], s, events);
ev_io_start(default_loop, &ctx->ios[i]);
} else {
ev_io_set(&ctx->ios[i], SS_INVALID_FD, 0);
}
if (!node) {
node = ss_malloc(sizeof(*node));
node->next = NULL;
*entry = node;
ss_io_init(&node->io, resolv_sock_cb, (int)s, events);
} else ss_io_set(&node->io, (int)s, events);
ss_io_start(default_loop, &node->io);
}
+3 -2
View File
@@ -35,12 +35,13 @@
#include <sys/socket.h>
#endif
struct ss_loop;
struct resolv_query;
int resolv_init(struct ev_loop *, char *, int);
int resolv_init(struct ss_loop *, char *, int);
void resolv_start(const char *hostname, uint16_t port,
void (*client_cb)(struct sockaddr *, void *),
void (*free_cb)(void *), void *data);
void resolv_shutdown(struct ev_loop *);
void resolv_shutdown(struct ss_loop *);
#endif
+166 -161
View File
@@ -98,23 +98,23 @@ enum datatypes {
#endif
static void signal_cb(EV_P_ ev_signal *w, int revents);
static void accept_cb(EV_P_ ev_io *w, int revents);
static void server_send_cb(EV_P_ ev_io *w, int revents);
static void server_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_send_cb(EV_P_ ev_io *w, int revents);
static void server_timeout_cb(EV_P_ ev_timer *watcher, int revents);
static void signal_cb(SS_P_ ss_signal *w, int revents);
static void accept_cb(SS_P_ ss_io *w, int revents);
static void server_send_cb(SS_P_ ss_io *w, int revents);
static void server_recv_cb(SS_P_ ss_io *w, int revents);
static void remote_recv_cb(SS_P_ ss_io *w, int revents);
static void remote_send_cb(SS_P_ ss_io *w, int revents);
static void server_timeout_cb(SS_P_ ss_timer *watcher, int revents);
static remote_t *new_remote(int fd);
static server_t *new_server(int fd, listen_ctx_t *listener);
static remote_t *connect_to_remote(EV_P_ struct addrinfo *res,
static remote_t *connect_to_remote(SS_P_ struct addrinfo *res,
server_t *server);
static void free_remote(remote_t *remote);
static void close_and_free_remote(EV_P_ remote_t *remote);
static void close_and_free_remote(SS_P_ remote_t *remote);
static void free_server(server_t *server);
static void close_and_free_server(EV_P_ server_t *server);
static void close_and_free_server(SS_P_ server_t *server);
static void resolv_cb(struct sockaddr *addr, void *data);
static void resolv_free_cb(void *data);
@@ -151,16 +151,16 @@ uint64_t tx = 0;
uint64_t rx = 0;
#ifndef __MINGW32__
ev_timer stat_update_watcher;
ss_timer stat_update_watcher;
#endif
static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher;
static struct ss_signal sigint_watcher;
static struct ss_signal sigterm_watcher;
#ifndef __MINGW32__
static struct ev_signal sigchld_watcher;
static struct ss_signal sigchld_watcher;
#else
static struct plugin_watcher_t {
ev_io io;
ss_io io;
SOCKET fd;
uint16_t port;
int valid;
@@ -170,8 +170,22 @@ static struct plugin_watcher_t {
static struct ss_list connections;
#ifndef __MINGW32__
static int setnonblocking(int fd);
static void stat_resolved(struct sockaddr *address, void *data)
{
if (!address) return;
int fd = ss_socket(address->sa_family, SOCK_DGRAM, 0);
if (fd == -1) return;
setnonblocking(fd);
const char *message = data;
size_t length = strlen(message) + 1;
if (sendto(fd, message, length, 0, address, get_sockaddr_len(address)) != (ssize_t)length)
ERROR("stat_sendto");
ss_socket_close(fd);
}
static void
stat_update_cb(EV_P_ ev_timer *watcher, int revents)
stat_update_cb(SS_P_ ss_timer *watcher, int revents)
{
struct sockaddr_un svaddr, claddr;
int sfd = -1;
@@ -189,6 +203,8 @@ stat_update_cb(EV_P_ ev_timer *watcher, int revents)
parse_addr(manager_addr, &ip_addr);
if (ip_addr.host == NULL || ip_addr.port == NULL) {
ss_free(ip_addr.host);
ss_free(ip_addr.port);
sfd = ss_socket(AF_UNIX, SOCK_DGRAM, 0);
if (sfd == -1) {
ERROR("stat_socket");
@@ -226,27 +242,15 @@ stat_update_cb(EV_P_ ev_timer *watcher, int revents)
unlink(claddr.sun_path);
} else {
struct sockaddr_storage storage;
memset(&storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(ip_addr.host, ip_addr.port, &storage, 0, ipv6first) == -1) {
ERROR("failed to parse the manager addr");
return;
}
sfd = ss_socket(storage.ss_family, SOCK_DGRAM, 0);
if (sfd == -1) {
ERROR("stat_socket");
return;
}
size_t addr_len = get_sockaddr_len((struct sockaddr *)&storage);
if (sendto(sfd, resp, strlen(resp) + 1, 0, (struct sockaddr *)&storage,
addr_len) != msgLen) {
ERROR("stat_sendto");
ss_socket_close(sfd);
return;
uint16_t port;
if (parse_numeric_port(ip_addr.port, &port) == 0) {
char *message = strdup(resp);
if (!message) FATAL("out of memory");
resolv_start(ip_addr.host, htons(port), stat_resolved, NULL, message);
}
ss_free(ip_addr.host);
ss_free(ip_addr.port);
return;
}
ss_socket_close(sfd);
@@ -255,7 +259,7 @@ stat_update_cb(EV_P_ ev_timer *watcher, int revents)
#endif
static void
free_connections(struct ev_loop *loop)
free_connections(struct ss_loop *loop)
{
struct ss_list_item *curr, *next;
ss_list_foreach_void(&connections, curr, next) {
@@ -290,7 +294,7 @@ get_peer_name(int fd)
}
static void
stop_server(EV_P_ server_t *server)
stop_server(SS_P_ server_t *server)
{
server->stage = STAGE_STOP;
}
@@ -669,7 +673,7 @@ create_and_bind(const char *host, const char *port, int mptcp)
}
static remote_t *
connect_to_remote(EV_P_ struct addrinfo *res,
connect_to_remote(SS_P_ struct addrinfo *res,
server_t *server)
{
int sockfd;
@@ -847,7 +851,7 @@ connect_to_remote(EV_P_ struct addrinfo *res,
if (r == -1 && ss_socket_error() != CONNECT_IN_PROGRESS) {
ERROR("connect");
close_and_free_remote(EV_A_ remote);
close_and_free_remote(SS_A_ remote);
return NULL;
}
}
@@ -947,7 +951,7 @@ setTosFromConnmark(remote_t *remote, server_t *server)
#endif
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
server_recv_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
server_t *server = server_recv_ctx->server;
@@ -960,15 +964,15 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
buf = remote->buf;
// Only timer the watcher if a valid connection is established
ev_timer_again(EV_A_ & server->recv_ctx->watcher);
ss_timer_again(SS_A_ & server->recv_ctx->watcher);
}
ssize_t r = recv(server->fd, buf->data, SOCKET_BUF_SIZE, 0);
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -977,8 +981,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
ERROR("server recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -995,7 +999,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (err == CRYPTO_ERROR) {
report_addr(server->fd, "authentication error");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
} else if (err == CRYPTO_NEED_MORE) {
if (server->stage != STAGE_STREAM) {
@@ -1011,18 +1015,18 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
remote->buf->idx = 0;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
} else {
ERROR("server_recv_send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
} else if (s < remote->buf->len) {
remote->buf->len -= s;
remote->buf->idx = s;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
}
return;
} else if (server->stage == STAGE_INIT) {
@@ -1041,7 +1045,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
int need_query = 0;
if (server->buf->len < 1) {
report_addr(server->fd, "missing address type");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
}
char atyp = server->buf->data[offset++];
@@ -1065,7 +1069,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
offset += in_addr_len;
} else {
report_addr(server->fd, "invalid length for ipv4 address");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
}
memcpy(&addr->sin_port, server->buf->data + offset, sizeof(uint16_t));
@@ -1078,7 +1082,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
// Domain name
if (server->buf->len < offset + 1) {
report_addr(server->fd, "missing host name length");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
}
uint8_t name_len = *(uint8_t *)(server->buf->data + offset);
@@ -1088,13 +1092,13 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
offset += name_len + 1;
} else {
report_addr(server->fd, "invalid host name length");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
}
if (acl && outbound_block_match_host(host) == 1) {
if (verbose)
LOGI("outbound blocked %s", host);
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
return;
}
struct ss_ip ip;
@@ -1121,7 +1125,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
} else {
if (!validate_hostname(host, name_len)) {
report_addr(server->fd, "invalid host name");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
}
need_query = 1;
@@ -1139,7 +1143,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
} else {
LOGE("invalid header with addr type %d", atyp);
report_addr(server->fd, "invalid length for ipv6 address");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
}
memcpy(&addr->sin6_port, server->buf->data + offset, sizeof(uint16_t));
@@ -1152,7 +1156,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (offset == 1) {
report_addr(server->fd, "invalid address type");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
}
@@ -1162,7 +1166,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (server->buf->len < offset) {
report_addr(server->fd, "invalid request length");
stop_server(EV_A_ server);
stop_server(SS_A_ server);
return;
} else {
server->buf->len -= offset;
@@ -1177,11 +1181,11 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
if (!need_query) {
remote_t *remote = connect_to_remote(EV_A_ & info, server);
remote_t *remote = connect_to_remote(SS_A_ & info, server);
if (remote == NULL) {
LOGE("connect error");
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
return;
} else {
server->remote = remote;
@@ -1199,11 +1203,11 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
// waiting on remote connected event
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
}
} else {
ev_io_stop(EV_A_ & server_recv_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
query_t *query = ss_malloc(sizeof(query_t));
memset(query, 0, sizeof(query_t));
@@ -1222,7 +1226,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
static void
server_send_cb(EV_P_ ev_io *w, int revents)
server_send_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_send_ctx = (server_ctx_t *)w;
server_t *server = server_send_ctx->server;
@@ -1230,14 +1234,14 @@ server_send_cb(EV_P_ ev_io *w, int revents)
if (remote == NULL) {
LOGE("invalid server");
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
return;
}
if (server->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -1246,8 +1250,8 @@ server_send_cb(EV_P_ ev_io *w, int revents)
if (s == -1) {
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("server_send_send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < server->buf->len) {
@@ -1259,14 +1263,14 @@ server_send_cb(EV_P_ ev_io *w, int revents)
// all sent out, wait for reading
server->buf->len = 0;
server->buf->idx = 0;
ev_io_stop(EV_A_ & server_send_ctx->io);
ss_io_stop(SS_A_ & server_send_ctx->io);
if (remote != NULL) {
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
return;
} else {
LOGE("invalid remote");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -1274,7 +1278,7 @@ server_send_cb(EV_P_ ev_io *w, int revents)
}
static void
server_timeout_cb(EV_P_ ev_timer *watcher, int revents)
server_timeout_cb(SS_P_ ss_timer *watcher, int revents)
{
server_ctx_t *server_ctx
= ss_container_of(watcher, server_ctx_t, watcher);
@@ -1285,8 +1289,8 @@ server_timeout_cb(EV_P_ ev_timer *watcher, int revents)
LOGI("TCP connection timeout");
}
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
static void
@@ -1310,11 +1314,11 @@ resolv_cb(struct sockaddr *addr, void *data)
if (server == NULL)
return;
struct ev_loop *loop = server->listen_ctx->loop;
struct ss_loop *loop = server->listen_ctx->loop;
if (addr == NULL) {
LOGE("unable to resolve %s", query->hostname);
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
} else {
if (verbose) {
LOGI("successfully resolved %s", query->hostname);
@@ -1334,10 +1338,10 @@ resolv_cb(struct sockaddr *addr, void *data)
info.ai_addrlen = sizeof(struct sockaddr_in6);
}
remote_t *remote = connect_to_remote(EV_A_ & info, server);
remote_t *remote = connect_to_remote(SS_A_ & info, server);
if (remote == NULL) {
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
} else {
server->remote = remote;
remote->server = server;
@@ -1354,13 +1358,13 @@ resolv_cb(struct sockaddr *addr, void *data)
}
// listen to remote connected event
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
}
}
}
static void
remote_recv_cb(EV_P_ ev_io *w, int revents)
remote_recv_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_recv_ctx->remote;
@@ -1368,18 +1372,18 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (server == NULL) {
LOGE("invalid server");
close_and_free_remote(EV_A_ remote);
close_and_free_remote(SS_A_ remote);
return;
}
ev_timer_again(EV_A_ & server->recv_ctx->watcher);
ss_timer_again(SS_A_ & server->recv_ctx->watcher);
ssize_t r = recv(remote->fd, server->buf->data, SOCKET_BUF_SIZE, 0);
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -1388,8 +1392,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
ERROR("remote recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -1406,8 +1410,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (err) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
@@ -1420,19 +1424,19 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
server->buf->idx = 0;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
} else {
ERROR("remote_recv_send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else if (s < server->buf->len) {
server->buf->len -= s;
server->buf->idx = s;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
}
// Disable TCP_NODELAY after the first response are sent
@@ -1445,7 +1449,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
}
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
remote_send_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_send_ctx->remote;
@@ -1453,7 +1457,7 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (server == NULL) {
LOGE("invalid server");
close_and_free_remote(EV_A_ remote);
close_and_free_remote(SS_A_ remote);
return;
}
@@ -1476,8 +1480,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
} else {
ERROR("WSAGetOverlappedResult");
// not connected
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -1500,24 +1504,24 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (remote->buf->len == 0) {
server->stage = STAGE_STREAM;
ev_io_stop(EV_A_ & remote_send_ctx->io);
ev_io_start(EV_A_ & server->recv_ctx->io);
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_stop(SS_A_ & remote_send_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
return;
}
} else {
ERROR("getpeername");
// not connected
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
if (remote->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -1527,8 +1531,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("remote_send_send");
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < remote->buf->len) {
@@ -1540,17 +1544,17 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
// all sent out, wait for reading
remote->buf->len = 0;
remote->buf->idx = 0;
ev_io_stop(EV_A_ & remote_send_ctx->io);
ss_io_stop(SS_A_ & remote_send_ctx->io);
if (server != NULL) {
ev_io_start(EV_A_ & server->recv_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
if (server->stage != STAGE_STREAM) {
server->stage = STAGE_STREAM;
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
}
} else {
LOGE("invalid server");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
}
@@ -1581,8 +1585,8 @@ new_remote(int fd)
remote->send_ctx->connected = 0;
remote->server = NULL;
ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ);
ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE);
ss_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, SS_READ);
ss_io_init(&remote->send_ctx->io, remote_send_cb, fd, SS_WRITE);
return remote;
}
@@ -1603,11 +1607,11 @@ free_remote(remote_t *remote)
}
static void
close_and_free_remote(EV_P_ remote_t *remote)
close_and_free_remote(SS_P_ remote_t *remote)
{
if (remote != NULL) {
ev_io_stop(EV_A_ & remote->send_ctx->io);
ev_io_stop(EV_A_ & remote->recv_ctx->io);
ss_io_stop(SS_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & remote->recv_ctx->io);
ss_socket_close(remote->fd);
free_remote(remote);
if (verbose) {
@@ -1654,9 +1658,9 @@ new_server(int fd, listen_ctx_t *listener)
cipher_ctx_pair(server->e_ctx, server->d_ctx);
int timeout = max(MIN_TCP_IDLE_TIMEOUT, server->listen_ctx->timeout);
ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ);
ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE);
ev_timer_init(&server->recv_ctx->watcher, server_timeout_cb,
ss_io_init(&server->recv_ctx->io, server_recv_cb, fd, SS_READ);
ss_io_init(&server->send_ctx->io, server_send_cb, fd, SS_WRITE);
ss_timer_init(&server->recv_ctx->watcher, server_timeout_cb,
timeout, timeout);
ss_list_add(&connections, &server->entries);
@@ -1702,16 +1706,16 @@ free_server(server_t *server)
}
static void
close_and_free_server(EV_P_ server_t *server)
close_and_free_server(SS_P_ server_t *server)
{
if (server != NULL) {
if (server->query != NULL) {
server->query->server = NULL;
server->query = NULL;
}
ev_io_stop(EV_A_ & server->send_ctx->io);
ev_io_stop(EV_A_ & server->recv_ctx->io);
ev_timer_stop(EV_A_ & server->recv_ctx->watcher);
ss_io_stop(SS_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & server->recv_ctx->io);
ss_timer_stop(SS_A_ & server->recv_ctx->watcher);
ss_socket_close(server->fd);
free_server(server);
if (verbose) {
@@ -1722,9 +1726,9 @@ close_and_free_server(EV_P_ server_t *server)
}
static void
signal_cb(EV_P_ ev_signal *w, int revents)
signal_cb(SS_P_ ss_signal *w, int revents)
{
if (revents & EV_SIGNAL) {
if (revents & SS_SIGNAL) {
switch (w->signum) {
#ifndef __MINGW32__
case SIGCHLD:
@@ -1736,21 +1740,21 @@ signal_cb(EV_P_ ev_signal *w, int revents)
#endif
case SIGINT:
case SIGTERM:
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
ss_signal_stop(SS_DEFAULT, &sigchld_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
ss_io_stop(SS_DEFAULT, &plugin_watcher.io);
#endif
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
}
}
#ifdef __MINGW32__
static void
plugin_watcher_cb(EV_P_ ev_io *w, int revents)
plugin_watcher_cb(SS_P_ ss_io *w, int revents)
{
char buf[1];
SOCKET fd = ss_accept(plugin_watcher.fd, NULL, NULL);
@@ -1761,16 +1765,16 @@ plugin_watcher_cb(EV_P_ ev_io *w, int revents)
closesocket(fd);
LOGE("plugin service exit unexpectedly");
ret_val = -1;
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
ss_io_stop(SS_DEFAULT, &plugin_watcher.io);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
#endif
static void
accept_cb(EV_P_ ev_io *w, int revents)
accept_cb(SS_P_ ss_io *w, int revents)
{
listen_ctx_t *listener = (listen_ctx_t *)w;
int serverfd = ss_accept(listener->fd, NULL, NULL);
@@ -1800,8 +1804,8 @@ accept_cb(EV_P_ ev_io *w, int revents)
setnonblocking(serverfd);
server_t *server = new_server(serverfd, listener);
ev_io_start(EV_A_ & server->recv_ctx->io);
ev_timer_start(EV_A_ & server->recv_ctx->watcher);
ss_io_start(SS_A_ & server->recv_ctx->io);
ss_timer_start(SS_A_ & server->recv_ctx->watcher);
}
int
@@ -2232,13 +2236,13 @@ main(int argc, char **argv)
signal(SIGABRT, SIG_IGN);
#endif
ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ev_signal_start(EV_DEFAULT, &sigint_watcher);
ev_signal_start(EV_DEFAULT, &sigterm_watcher);
ss_signal_init(&sigint_watcher, signal_cb, SIGINT);
ss_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ss_signal_start(SS_DEFAULT, &sigint_watcher);
ss_signal_start(SS_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ev_signal_start(EV_DEFAULT, &sigchld_watcher);
ss_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ss_signal_start(SS_DEFAULT, &sigchld_watcher);
#endif
// setup keys
@@ -2248,7 +2252,7 @@ main(int argc, char **argv)
FATAL("failed to initialize ciphers");
// initialize ev loop
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
// setup dns
resolv_init(loop, nameservers, ipv6first);
@@ -2278,8 +2282,8 @@ main(int argc, char **argv)
break;
}
plugin_watcher.fd = fd;
ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ);
ev_io_start(EV_DEFAULT, &plugin_watcher.io);
ss_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, SS_READ);
ss_io_start(SS_DEFAULT, &plugin_watcher.io);
plugin_watcher.valid = 1;
} while (0);
if (!plugin_watcher.valid) {
@@ -2354,8 +2358,8 @@ main(int argc, char **argv)
listen_ctx->iface = iface;
listen_ctx->loop = loop;
ev_io_init(&listen_ctx->io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx->io);
ss_io_init(&listen_ctx->io, accept_cb, listenfd, SS_READ);
ss_io_start(loop, &listen_ctx->io);
num_listen_ctx++;
@@ -2394,8 +2398,8 @@ main(int argc, char **argv)
#ifndef __MINGW32__
if (manager_addr != NULL) {
ev_timer_init(&stat_update_watcher, stat_update_cb, UPDATE_INTERVAL, UPDATE_INTERVAL);
ev_timer_start(EV_DEFAULT, &stat_update_watcher);
ss_timer_init(&stat_update_watcher, stat_update_cb, UPDATE_INTERVAL, UPDATE_INTERVAL);
ss_timer_start(SS_DEFAULT, &stat_update_watcher);
}
#endif
@@ -2414,7 +2418,7 @@ main(int argc, char **argv)
ss_list_init(&connections);
// start ev loop
ev_run(loop, 0);
ss_run(loop, 0);
if (verbose) {
LOGI("closed gracefully");
@@ -2422,7 +2426,7 @@ main(int argc, char **argv)
#ifndef __MINGW32__
if (manager_addr != NULL) {
ev_timer_stop(EV_DEFAULT, &stat_update_watcher);
ss_timer_stop(SS_DEFAULT, &stat_update_watcher);
}
#endif
@@ -2437,7 +2441,7 @@ main(int argc, char **argv)
for (int i = 0; i < server_num; i++) {
listen_ctx_t *listen_ctx = &listen_ctx_list[i];
if (mode != UDP_ONLY) {
ev_io_stop(loop, &listen_ctx->io);
ss_io_stop(loop, &listen_ctx->io);
ss_socket_close(listen_ctx->fd);
}
if (plugin != NULL)
@@ -2451,6 +2455,7 @@ main(int argc, char **argv)
if (mode != TCP_ONLY) {
free_udprelay();
}
ss_loop_destroy(loop);
#ifdef __MINGW32__
if (plugin_watcher.valid) {
+6 -10
View File
@@ -26,11 +26,7 @@
#include <time.h>
#include "core.h"
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
#else
#include <ev.h>
#endif
#include "ss_event.h"
#ifdef __MINGW32__
#include "ss_windows.h"
@@ -43,16 +39,16 @@
#include "common.h"
typedef struct listen_ctx {
ev_io io;
ss_io io;
int fd;
int timeout;
char *iface;
struct ev_loop *loop;
struct ss_loop *loop;
} listen_ctx_t;
typedef struct server_ctx {
ev_io io;
ev_timer watcher;
ss_io io;
ss_timer watcher;
int connected;
struct server *server;
} server_ctx_t;
@@ -101,7 +97,7 @@ typedef struct query {
} query_t;
typedef struct remote_ctx {
ev_io io;
ss_io io;
int connected;
struct remote *remote;
} remote_ctx_t;
+266
View File
@@ -0,0 +1,266 @@
#include "ss_event.h"
#include <uv.h>
#include "uthash.h"
#include <assert.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
struct poll_state {
uv_poll_t handle;
struct ss_loop *loop;
ss_io *watchers;
int fd, events;
UT_hash_handle hh;
};
struct timer_state {
uv_timer_t handle;
struct ss_loop *loop;
ss_timer *watcher;
};
struct signal_state {
uv_signal_t handle;
struct ss_loop *loop;
ss_signal *watcher;
};
struct ss_loop {
uv_loop_t native;
struct poll_state *polls;
uint64_t generation;
};
static struct ss_loop *default_loop;
static void checked(int status)
{
if (status < 0) {
fprintf(stderr, "event loop: %s\n", uv_strerror(status));
abort();
}
}
static void *allocate(size_t size)
{
void *p = calloc(1, size);
if (!p) abort();
return p;
}
static void closed(uv_handle_t *handle) { free(handle); }
uv_loop_t *ss_native_loop(struct ss_loop *loop) { return &loop->native; }
const char *ss_backend_name(void)
{
#ifdef _WIN32
return "iocp";
#elif defined(__APPLE__) || defined(__FreeBSD__)
return "kqueue";
#elif defined(__linux__)
return "epoll";
#else
return "libuv";
#endif
}
struct ss_loop *ss_loop_new(unsigned flags)
{
(void)flags;
struct ss_loop *loop = allocate(sizeof(*loop));
if (uv_loop_init(&loop->native)) { free(loop); return NULL; }
return loop;
}
struct ss_loop *ss_default_loop(void)
{
if (!default_loop) {
default_loop = ss_loop_new(0);
if (!default_loop) abort();
}
return default_loop;
}
static void close_walk(uv_handle_t *handle, void *arg)
{
(void)arg;
if (!uv_is_closing(handle)) uv_close(handle, closed);
}
void ss_loop_destroy(struct ss_loop *loop)
{
HASH_CLEAR(hh, loop->polls);
uv_walk(&loop->native, close_walk, NULL);
uv_run(&loop->native, UV_RUN_DEFAULT);
checked(uv_loop_close(&loop->native));
if (loop == default_loop) default_loop = NULL;
free(loop);
}
int ss_run(struct ss_loop *loop, int flags)
{
return uv_run(&loop->native, flags & SS_RUN_NOWAIT ? UV_RUN_NOWAIT : UV_RUN_DEFAULT);
}
void ss_unloop(struct ss_loop *loop, int how)
{
(void)how;
uv_stop(&loop->native);
}
double ss_now(struct ss_loop *loop) { return uv_now(&loop->native) / 1000.0; }
double ss_time(void)
{
uv_timeval64_t now;
checked(uv_gettimeofday(&now));
return (double)now.tv_sec + now.tv_usec / 1000000.0;
}
struct pending { ss_io *watcher; uint64_t generation; };
static void polled(uv_poll_t *handle, int status, int events)
{
struct poll_state *state = (struct poll_state *)handle;
int ready = (events & UV_READABLE ? SS_READ : 0) |
(events & UV_WRITABLE ? SS_WRITE : 0);
if (status < 0) ready = SS_READ | SS_WRITE | SS_ERROR;
size_t count = 0;
for (ss_io *w = state->watchers; w; w = w->next) count++;
struct pending local[8];
struct pending *pending = count > 8 ? allocate(count * sizeof(*pending)) : local;
size_t n = 0;
for (ss_io *w = state->watchers; w; w = w->next)
pending[n++] = (struct pending){w, w->generation};
/* A callback can stop/free itself or another watcher, or reuse its memory.
* Revalidate both membership and generation before dereferencing it. */
for (size_t i = 0; i < count; i++) {
for (ss_io *w = state->watchers; w; w = w->next) {
if (w == pending[i].watcher && w->generation == pending[i].generation) {
int deliver = ready & (w->events | SS_ERROR);
if (deliver) w->cb(state->loop, w, deliver);
break;
}
}
}
if (pending != local) free(pending);
}
static void update_poll(struct poll_state *state)
{
int events = 0;
for (ss_io *w = state->watchers; w; w = w->next) events |= w->events;
if (events == state->events) return;
state->events = events;
checked(uv_poll_start(&state->handle,
(events & SS_READ ? UV_READABLE : 0) | (events & SS_WRITE ? UV_WRITABLE : 0), polled));
}
void ss_io_init(ss_io *w, void (*cb)(struct ss_loop *, ss_io *, int), int fd, int events)
{
*w = (ss_io){.fd = fd, .events = events, .cb = cb};
}
void ss_io_set(ss_io *w, int fd, int events)
{
assert(!w->backend);
w->fd = fd; w->events = events;
}
void ss_io_start(struct ss_loop *loop, ss_io *w)
{
if (w->backend) return;
struct poll_state *state;
HASH_FIND_INT(loop->polls, &w->fd, state);
if (!state) {
state = allocate(sizeof(*state));
state->fd = w->fd; state->loop = loop;
#ifdef _WIN32
checked(uv_poll_init_socket(&loop->native, &state->handle, (SOCKET)(unsigned int)w->fd));
#else
checked(uv_poll_init(&loop->native, &state->handle, w->fd));
#endif
// NOLINTNEXTLINE(clang-analyzer-core.DivideZero): uthash expands a nonempty table, so ceil(num_items / num_buckets) is positive.
HASH_ADD_INT(loop->polls, fd, state);
}
w->backend = state;
w->generation = ++loop->generation;
w->next = state->watchers;
state->watchers = w;
update_poll(state);
}
void ss_io_stop(struct ss_loop *loop, ss_io *w)
{
struct poll_state *state = w->backend;
if (!state) return;
assert(state->loop == loop);
ss_io **item = &state->watchers;
while (*item != w) item = &(*item)->next;
*item = w->next;
w->backend = NULL; w->next = NULL;
if (!state->watchers) {
checked(uv_poll_stop(&state->handle));
HASH_DEL(loop->polls, state);
uv_close((uv_handle_t *)&state->handle, closed);
} else update_poll(state);
}
static uint64_t milliseconds(double seconds)
{
return seconds > 0 ? (uint64_t)ceil(seconds * 1000.0) : 0;
}
static void timed(uv_timer_t *handle)
{
struct timer_state *state = (struct timer_state *)handle;
ss_timer *w = state->watcher;
struct ss_loop *loop = state->loop;
if (!w->repeat) ss_timer_stop(loop, w);
w->cb(loop, w, SS_TIMER);
}
void ss_timer_init(ss_timer *w, void (*cb)(struct ss_loop *, ss_timer *, int), double after, double repeat)
{
*w = (ss_timer){.after = after, .repeat = repeat, .cb = cb};
}
void ss_timer_set(ss_timer *w, double after, double repeat)
{
w->after = after; w->repeat = repeat;
}
void ss_timer_start(struct ss_loop *loop, ss_timer *w)
{
if (w->backend) return;
struct timer_state *state = allocate(sizeof(*state));
state->loop = loop; state->watcher = w;
checked(uv_timer_init(&loop->native, &state->handle));
w->backend = state;
uv_update_time(&loop->native);
checked(uv_timer_start(&state->handle, timed, milliseconds(w->after), milliseconds(w->repeat)));
}
void ss_timer_stop(struct ss_loop *loop, ss_timer *w)
{
(void)loop;
struct timer_state *state = w->backend;
if (!state) return;
w->backend = NULL;
checked(uv_timer_stop(&state->handle));
uv_close((uv_handle_t *)&state->handle, closed);
}
void ss_timer_again(struct ss_loop *loop, ss_timer *w)
{
ss_timer_stop(loop, w);
if (w->repeat > 0) {
w->after = w->repeat;
ss_timer_start(loop, w);
}
}
static void signaled(uv_signal_t *handle, int signum)
{
(void)signum;
struct signal_state *state = (struct signal_state *)handle;
ss_signal *w = state->watcher;
w->cb(state->loop, w, SS_SIGNAL);
}
void ss_signal_init(ss_signal *w, void (*cb)(struct ss_loop *, ss_signal *, int), int signum)
{
*w = (ss_signal){.signum = signum, .cb = cb};
}
void ss_signal_start(struct ss_loop *loop, ss_signal *w)
{
if (w->backend) return;
#ifdef _WIN32
/* Windows has no SIGTERM delivery; process termination is an OS operation. */
if (w->signum == SIGTERM) return;
#endif
struct signal_state *state = allocate(sizeof(*state));
state->loop = loop; state->watcher = w;
checked(uv_signal_init(&loop->native, &state->handle));
checked(uv_signal_start(&state->handle, signaled, w->signum));
w->backend = state;
}
void ss_signal_stop(struct ss_loop *loop, ss_signal *w)
{
(void)loop;
struct signal_state *state = w->backend;
if (!state) return;
w->backend = NULL;
checked(uv_signal_stop(&state->handle));
uv_close((uv_handle_t *)&state->handle, closed);
}
+58
View File
@@ -0,0 +1,58 @@
/* Project event API backed by bundled/system libuv. Watchers may be freed
* immediately after stop; libuv handle storage has a separate lifetime. */
#ifndef SS_EVENT_H
#define SS_EVENT_H
#include <stdint.h>
/* Keep platform headers private: Linux TCP headers differ from libc headers. */
struct uv_loop_s;
struct ss_loop;
typedef double ss_tstamp;
#define SS_READ 1
#define SS_WRITE 2
#define SS_TIMER 4
#define SS_SIGNAL 8
#define SS_ERROR 16
#define SS_RUN_NOWAIT 1
#define SS_UNLOOP_ALL 2
#define SS_P_ struct ss_loop *loop,
#define SS_A_ loop,
#define SS_DEFAULT ss_default_loop()
typedef struct ss_io {
void *backend;
struct ss_io *next;
uint64_t generation;
int fd, events;
void (*cb)(struct ss_loop *, struct ss_io *, int);
} ss_io;
typedef struct ss_timer {
void *backend;
double after, repeat;
void (*cb)(struct ss_loop *, struct ss_timer *, int);
} ss_timer;
typedef struct ss_signal {
void *backend;
int signum;
void (*cb)(struct ss_loop *, struct ss_signal *, int);
} ss_signal;
struct ss_loop *ss_default_loop(void);
struct ss_loop *ss_loop_new(unsigned flags);
void ss_loop_destroy(struct ss_loop *loop);
struct uv_loop_s *ss_native_loop(struct ss_loop *loop);
const char *ss_backend_name(void);
int ss_run(struct ss_loop *loop, int flags);
void ss_unloop(struct ss_loop *loop, int how);
double ss_now(struct ss_loop *loop);
double ss_time(void);
void ss_io_init(ss_io *, void (*)(struct ss_loop *, ss_io *, int), int, int);
void ss_io_set(ss_io *, int, int);
void ss_io_start(struct ss_loop *, ss_io *);
void ss_io_stop(struct ss_loop *, ss_io *);
void ss_timer_init(ss_timer *, void (*)(struct ss_loop *, ss_timer *, int), double, double);
void ss_timer_set(ss_timer *, double, double);
void ss_timer_start(struct ss_loop *, ss_timer *);
void ss_timer_stop(struct ss_loop *, ss_timer *);
void ss_timer_again(struct ss_loop *, ss_timer *);
void ss_signal_init(ss_signal *, void (*)(struct ss_loop *, ss_signal *, int), int);
void ss_signal_start(struct ss_loop *, ss_signal *);
void ss_signal_stop(struct ss_loop *, ss_signal *);
#endif
+115 -115
View File
@@ -63,19 +63,19 @@
#define EWOULDBLOCK EAGAIN
#endif
static void accept_cb(EV_P_ ev_io *w, int revents);
static void server_recv_cb(EV_P_ ev_io *w, int revents);
static void server_send_cb(EV_P_ ev_io *w, int revents);
static void remote_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_send_cb(EV_P_ ev_io *w, int revents);
static void accept_cb(SS_P_ ss_io *w, int revents);
static void server_recv_cb(SS_P_ ss_io *w, int revents);
static void server_send_cb(SS_P_ ss_io *w, int revents);
static void remote_recv_cb(SS_P_ ss_io *w, int revents);
static void remote_send_cb(SS_P_ ss_io *w, int revents);
static remote_t *new_remote(int fd, int timeout);
static server_t *new_server(int fd);
static void free_remote(remote_t *remote);
static void close_and_free_remote(EV_P_ remote_t *remote);
static void close_and_free_remote(SS_P_ remote_t *remote);
static void free_server(server_t *server);
static void close_and_free_server(EV_P_ server_t *server);
static void close_and_free_server(SS_P_ server_t *server);
static int
validate_tunnel_addr(const ss_addr_t *addr)
@@ -121,13 +121,13 @@ static int no_delay = 0;
int fast_open = 0;
static int ret_val = 0;
static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher;
static struct ss_signal sigint_watcher;
static struct ss_signal sigterm_watcher;
#ifndef __MINGW32__
static struct ev_signal sigchld_watcher;
static struct ss_signal sigchld_watcher;
#else
static struct plugin_watcher_t {
ev_io io;
ss_io io;
SOCKET fd;
uint16_t port;
int valid;
@@ -215,14 +215,14 @@ create_and_bind(const char *addr, const char *port)
}
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
server_recv_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
server_t *server = server_recv_ctx->server;
remote_t *remote = server->remote;
if (remote == NULL) {
close_and_free_server(EV_A_ server);
close_and_free_server(SS_A_ server);
return;
}
@@ -230,8 +230,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -240,8 +240,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
ERROR("server recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -252,8 +252,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (err) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
@@ -263,34 +263,34 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
remote->buf->idx = 0;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
} else {
ERROR("send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else if (s < remote->buf->len) {
remote->buf->len -= s;
remote->buf->idx = s;
ev_io_stop(EV_A_ & server_recv_ctx->io);
ev_io_start(EV_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & server_recv_ctx->io);
ss_io_start(SS_A_ & remote->send_ctx->io);
return;
}
}
static void
server_send_cb(EV_P_ ev_io *w, int revents)
server_send_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_send_ctx = (server_ctx_t *)w;
server_t *server = server_send_ctx->server;
remote_t *remote = server->remote;
if (server->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -299,8 +299,8 @@ server_send_cb(EV_P_ ev_io *w, int revents)
if (s == -1) {
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < server->buf->len) {
@@ -312,12 +312,12 @@ server_send_cb(EV_P_ ev_io *w, int revents)
// all sent out, wait for reading
server->buf->len = 0;
server->buf->idx = 0;
ev_io_stop(EV_A_ & server_send_ctx->io);
ss_io_stop(SS_A_ & server_send_ctx->io);
if (remote != NULL) {
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
} else {
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -325,7 +325,7 @@ server_send_cb(EV_P_ ev_io *w, int revents)
}
static void
remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
remote_timeout_cb(SS_P_ ss_timer *watcher, int revents)
{
remote_ctx_t *remote_ctx
= ss_container_of(watcher, remote_ctx_t, watcher);
@@ -337,14 +337,14 @@ remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
LOGI("TCP connection timeout");
}
ev_timer_stop(EV_A_ watcher);
ss_timer_stop(SS_A_ watcher);
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
static void
remote_recv_cb(EV_P_ ev_io *w, int revents)
remote_recv_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_recv_ctx->remote;
@@ -354,8 +354,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (r == 0) {
// connection closed
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (r == -1) {
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
@@ -364,8 +364,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
ERROR("remote recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
@@ -375,8 +375,8 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
int err = crypto->decrypt(server->buf, server->d_ctx, SOCKET_BUF_SIZE);
if (err == CRYPTO_ERROR) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else if (err == CRYPTO_NEED_MORE) {
return; // Wait for more
@@ -388,19 +388,19 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK) {
// no data, wait for send
server->buf->idx = 0;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
} else {
ERROR("send");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
} else if (s < server->buf->len) {
server->buf->len -= s;
server->buf->idx = s;
ev_io_stop(EV_A_ & remote_recv_ctx->io);
ev_io_start(EV_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & remote_recv_ctx->io);
ss_io_start(SS_A_ & server->send_ctx->io);
}
// Disable TCP_NODELAY after the first response are sent
@@ -413,13 +413,13 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
}
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
remote_send_cb(SS_P_ ss_io *w, int revents)
{
remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
remote_t *remote = remote_send_ctx->remote;
server_t *server = remote->server;
ev_timer_stop(EV_A_ & remote_send_ctx->watcher);
ss_timer_stop(SS_A_ & remote_send_ctx->watcher);
if (!remote_send_ctx->connected) {
int r = 0;
@@ -435,8 +435,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (remote->buf->len != 0) {
LOGE("unexpected pending tunnel data");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
buffer_t *abuf = remote->buf;
@@ -477,8 +477,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (host_len > UINT8_MAX) {
LOGE("tunnel host name is too long");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
abuf->data[abuf->len++] = 3;
@@ -490,8 +490,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
uint16_t port_num;
if (ss_parse_uint16_port(sa->port, &port_num) == -1) {
LOGE("invalid tunnel port");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
uint16_t port = htons(port_num);
@@ -502,25 +502,25 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (err) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
ev_io_start(EV_A_ & remote->recv_ctx->io);
ss_io_start(SS_A_ & remote->recv_ctx->io);
} else {
ERROR("getpeername");
// not connected
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
if (remote->buf->len == 0) {
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
} else {
// has data to send
@@ -599,8 +599,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (s == -1) {
if (ss_socket_error() == CONNECT_IN_PROGRESS) {
ev_io_start(EV_A_ & remote_send_ctx->io);
ev_timer_start(EV_A_ & remote_send_ctx->watcher);
ss_io_start(SS_A_ & remote_send_ctx->io);
ss_timer_start(SS_A_ & remote_send_ctx->watcher);
} else {
fast_open = 0;
if (ss_socket_error() == EOPNOTSUPP || ss_socket_error() == EPROTONOSUPPORT ||
@@ -609,8 +609,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
} else {
ERROR("fast_open_connect");
}
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
}
@@ -623,8 +623,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
if (ss_socket_error() != EAGAIN && ss_socket_error() != EWOULDBLOCK) {
ERROR("send");
// close and free
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
}
return;
} else if (s < remote->buf->len) {
@@ -636,8 +636,8 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
// all sent out, wait for reading
remote->buf->len = 0;
remote->buf->idx = 0;
ev_io_stop(EV_A_ & remote_send_ctx->io);
ev_io_start(EV_A_ & server->recv_ctx->io);
ss_io_stop(SS_A_ & remote_send_ctx->io);
ss_io_start(SS_A_ & server->recv_ctx->io);
}
}
}
@@ -660,9 +660,9 @@ new_remote(int fd, int timeout)
remote->send_ctx->remote = remote;
remote->send_ctx->connected = 0;
ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ);
ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE);
ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb,
ss_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, SS_READ);
ss_io_init(&remote->send_ctx->io, remote_send_cb, fd, SS_WRITE);
ss_timer_init(&remote->send_ctx->watcher, remote_timeout_cb,
min(MAX_CONNECT_TIMEOUT, timeout), 0);
return remote;
@@ -684,12 +684,12 @@ free_remote(remote_t *remote)
}
static void
close_and_free_remote(EV_P_ remote_t *remote)
close_and_free_remote(SS_P_ remote_t *remote)
{
if (remote != NULL) {
ev_timer_stop(EV_A_ & remote->send_ctx->watcher);
ev_io_stop(EV_A_ & remote->send_ctx->io);
ev_io_stop(EV_A_ & remote->recv_ctx->io);
ss_timer_stop(SS_A_ & remote->send_ctx->watcher);
ss_io_stop(SS_A_ & remote->send_ctx->io);
ss_io_stop(SS_A_ & remote->recv_ctx->io);
ss_socket_close(remote->fd);
free_remote(remote);
}
@@ -719,8 +719,8 @@ new_server(int fd)
crypto->ctx_init(crypto->cipher, server->d_ctx, 0);
cipher_ctx_pair(server->e_ctx, server->d_ctx);
ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ);
ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE);
ss_io_init(&server->recv_ctx->io, server_recv_cb, fd, SS_READ);
ss_io_init(&server->send_ctx->io, server_send_cb, fd, SS_WRITE);
return server;
}
@@ -750,18 +750,18 @@ free_server(server_t *server)
}
static void
close_and_free_server(EV_P_ server_t *server)
close_and_free_server(SS_P_ server_t *server)
{
if (server != NULL) {
ev_io_stop(EV_A_ & server->send_ctx->io);
ev_io_stop(EV_A_ & server->recv_ctx->io);
ss_io_stop(SS_A_ & server->send_ctx->io);
ss_io_stop(SS_A_ & server->recv_ctx->io);
ss_socket_close(server->fd);
free_server(server);
}
}
static void
accept_cb(EV_P_ ev_io *w, int revents)
accept_cb(SS_P_ ss_io *w, int revents)
{
struct listen_ctx *listener = (struct listen_ctx *)w;
int serverfd = ss_accept(listener->fd, NULL, NULL);
@@ -864,21 +864,21 @@ accept_cb(EV_P_ ev_io *w, int revents)
if (r == -1 && ss_socket_error() != CONNECT_IN_PROGRESS) {
ERROR("connect");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
close_and_free_remote(SS_A_ remote);
close_and_free_server(SS_A_ server);
return;
}
}
// listen to remote connected event
ev_io_start(EV_A_ & remote->send_ctx->io);
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
ss_io_start(SS_A_ & remote->send_ctx->io);
ss_timer_start(SS_A_ & remote->send_ctx->watcher);
}
static void
signal_cb(EV_P_ ev_signal *w, int revents)
signal_cb(SS_P_ ss_signal *w, int revents)
{
if (revents & EV_SIGNAL) {
if (revents & SS_SIGNAL) {
switch (w->signum) {
#ifndef __MINGW32__
case SIGCHLD:
@@ -890,21 +890,21 @@ signal_cb(EV_P_ ev_signal *w, int revents)
#endif
case SIGINT:
case SIGTERM:
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
ss_signal_stop(SS_DEFAULT, &sigchld_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
ss_io_stop(SS_DEFAULT, &plugin_watcher.io);
#endif
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
}
}
#ifdef __MINGW32__
static void
plugin_watcher_cb(EV_P_ ev_io *w, int revents)
plugin_watcher_cb(SS_P_ ss_io *w, int revents)
{
char buf[1];
SOCKET fd = ss_accept(plugin_watcher.fd, NULL, NULL);
@@ -915,10 +915,10 @@ plugin_watcher_cb(EV_P_ ev_io *w, int revents)
closesocket(fd);
LOGE("plugin service exit unexpectedly");
ret_val = -1;
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
ev_unloop(EV_A_ EVUNLOOP_ALL);
ss_signal_stop(SS_DEFAULT, &sigint_watcher);
ss_signal_stop(SS_DEFAULT, &sigterm_watcher);
ss_io_stop(SS_DEFAULT, &plugin_watcher.io);
ss_unloop(SS_A_ SS_UNLOOP_ALL);
}
#endif
@@ -1352,8 +1352,8 @@ main(int argc, char **argv)
break;
}
plugin_watcher.fd = fd;
ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ);
ev_io_start(EV_DEFAULT, &plugin_watcher.io);
ss_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, SS_READ);
ss_io_start(SS_DEFAULT, &plugin_watcher.io);
plugin_watcher.valid = 1;
} while (0);
if (!plugin_watcher.valid) {
@@ -1393,13 +1393,13 @@ main(int argc, char **argv)
signal(SIGABRT, SIG_IGN);
#endif
ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ev_signal_start(EV_DEFAULT, &sigint_watcher);
ev_signal_start(EV_DEFAULT, &sigterm_watcher);
ss_signal_init(&sigint_watcher, signal_cb, SIGINT);
ss_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
ss_signal_start(SS_DEFAULT, &sigint_watcher);
ss_signal_start(SS_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ev_signal_start(EV_DEFAULT, &sigchld_watcher);
ss_signal_init(&sigchld_watcher, signal_cb, SIGCHLD);
ss_signal_start(SS_DEFAULT, &sigchld_watcher);
#endif
// Setup keys
@@ -1438,7 +1438,7 @@ main(int argc, char **argv)
LOGI("listening at %s:%s", local_addr, local_port);
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
if (mode != UDP_ONLY) {
// Setup socket
@@ -1454,8 +1454,8 @@ main(int argc, char **argv)
listen_ctx.fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
ss_io_init(&listen_ctx.io, accept_cb, listenfd, SS_READ);
ss_io_start(loop, &listen_ctx.io);
}
// Setup UDP
@@ -1490,7 +1490,7 @@ main(int argc, char **argv)
}
#endif
ev_run(loop, 0);
ss_run(loop, 0);
if (plugin != NULL) {
stop_plugin();
+5 -9
View File
@@ -23,11 +23,7 @@
#ifndef _TUNNEL_H
#define _TUNNEL_H
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
#else
#include <ev.h>
#endif
#include "ss_event.h"
#ifdef __MINGW32__
#include "ss_windows.h"
@@ -39,7 +35,7 @@
#include "common.h"
typedef struct listen_ctx {
ev_io io;
ss_io io;
ss_addr_t tunnel_addr;
char *iface;
int remote_num;
@@ -50,7 +46,7 @@ typedef struct listen_ctx {
} listen_ctx_t;
typedef struct server_ctx {
ev_io io;
ss_io io;
int connected;
struct server *server;
} server_ctx_t;
@@ -68,8 +64,8 @@ typedef struct server {
} server_t;
typedef struct remote_ctx {
ev_io io;
ev_timer watcher;
ss_io io;
ss_timer watcher;
int connected;
struct remote *remote;
} remote_ctx_t;
+31 -31
View File
@@ -74,16 +74,16 @@
#define EWOULDBLOCK EAGAIN
#endif
static void server_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents);
static void server_recv_cb(SS_P_ ss_io *w, int revents);
static void remote_recv_cb(SS_P_ ss_io *w, int revents);
static void remote_timeout_cb(SS_P_ ss_timer *watcher, int revents);
static char *hash_key(const int af, const struct sockaddr_storage *addr);
#ifdef MODULE_REMOTE
static void resolv_free_cb(void *data);
static void resolv_cb(struct sockaddr *addr, void *data);
#endif
static void close_and_free_remote(EV_P_ remote_ctx_t *ctx);
static void close_and_free_remote(SS_P_ remote_ctx_t *ctx);
static remote_ctx_t *new_remote(int fd, server_ctx_t *server_ctx);
#ifdef __ANDROID__
@@ -587,8 +587,8 @@ new_remote(int fd, server_ctx_t *server_ctx)
ctx->server_ctx = server_ctx;
ctx->af = AF_UNSPEC;
ev_io_init(&ctx->io, remote_recv_cb, fd, EV_READ);
ev_timer_init(&ctx->watcher, remote_timeout_cb, server_ctx->timeout,
ss_io_init(&ctx->io, remote_recv_cb, fd, SS_READ);
ss_timer_init(&ctx->watcher, remote_timeout_cb, server_ctx->timeout,
server_ctx->timeout);
return ctx;
@@ -602,7 +602,7 @@ new_server_ctx(int fd)
ctx->fd = fd;
ev_io_init(&ctx->io, server_recv_cb, fd, EV_READ);
ss_io_init(&ctx->io, server_recv_cb, fd, SS_READ);
return ctx;
}
@@ -621,7 +621,7 @@ new_query_ctx(char *buf, size_t len)
}
void
close_and_free_query(EV_P_ struct query_ctx *ctx)
close_and_free_query(SS_P_ struct query_ctx *ctx)
{
if (ctx != NULL) {
if (ctx->buf != NULL) {
@@ -635,11 +635,11 @@ close_and_free_query(EV_P_ struct query_ctx *ctx)
#endif
void
close_and_free_remote(EV_P_ remote_ctx_t *ctx)
close_and_free_remote(SS_P_ remote_ctx_t *ctx)
{
if (ctx != NULL) {
ev_timer_stop(EV_A_ & ctx->watcher);
ev_io_stop(EV_A_ & ctx->io);
ss_timer_stop(SS_A_ & ctx->watcher);
ss_io_stop(SS_A_ & ctx->io);
ss_socket_close(ctx->fd);
if (ctx->udp_session != NULL
&& ctx->server_ctx != NULL
@@ -651,7 +651,7 @@ close_and_free_remote(EV_P_ remote_ctx_t *ctx)
}
static void
remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
remote_timeout_cb(SS_P_ ss_timer *watcher, int revents)
{
remote_ctx_t *remote_ctx
= ss_container_of(watcher, remote_ctx_t, watcher);
@@ -680,7 +680,7 @@ static void
resolv_cb(struct sockaddr *addr, void *data)
{
struct query_ctx *query_ctx = (struct query_ctx *)data;
struct ev_loop *loop = query_ctx->server_ctx->loop;
struct ss_loop *loop = query_ctx->server_ctx->loop;
if (addr == NULL) {
LOGE("[udp] unable to resolve");
@@ -747,15 +747,15 @@ resolv_cb(struct sockaddr *addr, void *data)
if (s == -1) {
ERROR("[udp] sendto_remote");
if (!cache_hit) {
close_and_free_remote(EV_A_ remote_ctx);
close_and_free_remote(SS_A_ remote_ctx);
}
} else {
if (!cache_hit) {
// Add to conn cache
char *key = hash_key(AF_UNSPEC, &remote_ctx->src_addr);
cache_insert(query_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx);
ev_io_start(EV_A_ & remote_ctx->io);
ev_timer_start(EV_A_ & remote_ctx->watcher);
ss_io_start(SS_A_ & remote_ctx->io);
ss_timer_start(SS_A_ & remote_ctx->watcher);
}
}
}
@@ -788,7 +788,7 @@ void convert_ipv4_mapped_ipv6(struct sockaddr_storage* addr) {
}
static void
remote_recv_cb(EV_P_ ev_io *w, int revents)
remote_recv_cb(SS_P_ ss_io *w, int revents)
{
ssize_t r;
remote_ctx_t *remote_ctx = (remote_ctx_t *)w;
@@ -797,7 +797,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
// server has been closed
if (server_ctx == NULL) {
LOGE("[udp] invalid server");
close_and_free_remote(EV_A_ remote_ctx);
close_and_free_remote(SS_A_ remote_ctx);
return;
}
@@ -984,7 +984,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
// handle the UDP packet successfully,
// triger the timer
ev_timer_again(EV_A_ & remote_ctx->watcher);
ss_timer_again(SS_A_ & remote_ctx->watcher);
CLEAN_UP:
@@ -993,7 +993,7 @@ CLEAN_UP:
}
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
server_recv_cb(SS_P_ ss_io *w, int revents)
{
server_ctx_t *server_ctx = (server_ctx_t *)w;
struct sockaddr_storage src_addr;
@@ -1250,7 +1250,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
// reset the timer
if (remote_ctx != NULL) {
ev_timer_again(EV_A_ & remote_ctx->watcher);
ss_timer_again(SS_A_ & remote_ctx->watcher);
}
if (remote_ctx == NULL) {
@@ -1345,8 +1345,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
cache_insert(conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx);
// Start remote io
ev_io_start(EV_A_ & remote_ctx->io);
ev_timer_start(EV_A_ & remote_ctx->watcher);
ss_io_start(SS_A_ & remote_ctx->io);
ss_timer_start(SS_A_ & remote_ctx->watcher);
}
if (offset > 0) {
@@ -1451,7 +1451,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
if (s == -1) {
ERROR("[udp] sendto_remote");
if (!cache_hit) {
close_and_free_remote(EV_A_ remote_ctx);
close_and_free_remote(SS_A_ remote_ctx);
}
} else {
if (!cache_hit) {
@@ -1460,8 +1460,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr);
cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx);
ev_io_start(EV_A_ & remote_ctx->io);
ev_timer_start(EV_A_ & remote_ctx->watcher);
ss_io_start(SS_A_ & remote_ctx->io);
ss_timer_start(SS_A_ & remote_ctx->watcher);
}
}
} else {
@@ -1500,7 +1500,7 @@ free_cb(void *key, void *element)
LOGI("[udp] one connection freed");
}
close_and_free_remote(EV_DEFAULT, remote_ctx);
close_and_free_remote(SS_DEFAULT, remote_ctx);
}
int
@@ -1515,7 +1515,7 @@ init_udprelay(const char *server_host, const char *server_port,
{
s_port = server_port;
// Initialize ev loop
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
// Initialize MTU
if (mtu > 0) {
@@ -1556,7 +1556,7 @@ init_udprelay(const char *server_host, const char *server_port,
#endif
#endif
ev_io_start(loop, &server_ctx->io);
ss_io_start(loop, &server_ctx->io);
server_ctx_list[server_num++] = server_ctx;
@@ -1566,10 +1566,10 @@ init_udprelay(const char *server_host, const char *server_port,
void
free_udprelay()
{
struct ev_loop *loop = EV_DEFAULT;
struct ss_loop *loop = SS_DEFAULT;
while (server_num > 0) {
server_ctx_t *server_ctx = server_ctx_list[--server_num];
ev_io_stop(loop, &server_ctx->io);
ss_io_stop(loop, &server_ctx->io);
ss_socket_close(server_ctx->fd);
cache_delete(server_ctx->conn_cache, 0);
#ifdef MODULE_LOCAL
+5 -9
View File
@@ -25,11 +25,7 @@
#include <time.h>
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
#else
#include <ev.h>
#endif
#include "ss_event.h"
#include "crypto.h"
#include "jconf.h"
@@ -49,7 +45,7 @@
#define MAX_ADDR_HEADER_SIZE (1 + 256 + 2) // 1-byte atyp + 256-byte hostname + 2-byte port
typedef struct server_ctx {
ev_io io;
ss_io io;
int fd;
crypto_t *crypto;
int timeout;
@@ -63,7 +59,7 @@ typedef struct server_ctx {
#endif
#endif
#ifdef MODULE_REMOTE
struct ev_loop *loop;
struct ss_loop *loop;
#endif
} server_ctx_t;
@@ -79,8 +75,8 @@ typedef struct query_ctx {
#endif
typedef struct remote_ctx {
ev_io io;
ev_timer watcher;
ss_io io;
ss_timer watcher;
int af;
int fd;
struct sockaddr_storage src_addr;
+1 -1
View File
@@ -321,7 +321,7 @@ void
usage()
{
printf("\n");
printf("shadowsocks-libev %s\n\n", VERSION);
printf("shadowsocks-c %s\n\n", VERSION);
printf(
" maintained by Max Lv <max.c.lv@gmail.com> and Linus Yang <laokongzi@gmail.com>\n\n");
printf(" usage:\n\n");
+7
View File
@@ -199,3 +199,10 @@ endif()
ss_add_test(test_acl_literal
"test_acl_literal.c;${PROJECT_SOURCE_DIR}/src/acl.c;${PROJECT_SOURCE_DIR}/src/ipset.c;${PROJECT_SOURCE_DIR}/src/rule.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"${TEST_LITERAL_LIBS}")
ss_add_test(test_event "test_event.c" "ss_ev")
set_tests_properties(test_event PROPERTIES TIMEOUT 30)
ss_add_test(test_resolv_async
"test_resolv_async.c;${PROJECT_SOURCE_DIR}/src/resolv.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"ss_ev;ss_cares;ss_sodium")
set_tests_properties(test_resolv_async PROPERTIES TIMEOUT 30)
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""Exercise client hostname ACL bypass with an unreachable proxy upstream."""
import argparse
import concurrent.futures
import os
from pathlib import Path
import tempfile
import threading
from interop import TCPOrigin, TCPHandler, free_port, peers, tcp_case
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--bin', required=True, type=Path)
parser.add_argument('--isolate-windows-runtime', action='store_true')
args = parser.parse_args()
environment = None
if args.isolate_windows_runtime:
environment = os.environ.copy()
root = os.environ['SYSTEMROOT']
environment['PATH'] = root + '\\System32;' + root
local = args.bin.resolve() / ('ss-local.exe' if os.name == 'nt' else 'ss-local')
with tempfile.TemporaryDirectory() as temp, TCPOrigin(('127.0.0.1', 0), TCPHandler) as origin:
threading.Thread(target=origin.serve_forever, daemon=True).start()
try:
for policy in ('[bypass_all]\n', '[proxy_all]\n[bypass_list]\nfull:localhost\n'):
acl = Path(temp) / 'acl'
acl.write_text(policy)
port, upstream = free_port(), free_port()
command = [str(local), '-s', '127.0.0.1', '-p', str(upstream), '-l', str(port),
'-k', 'dns-integration', '-m', 'aes-128-gcm', '--acl', str(acl)]
with peers([command], [port], environment):
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as pool:
futures = [pool.submit(tcp_case, port, origin.server_address[1], size)
for size in (1, 65536, 1048576)]
for future in futures: future.result(timeout=15)
print('PASS hostname ACL bypass: ' + policy.splitlines()[0], flush=True)
finally:
origin.shutdown()
if __name__ == '__main__':
main()
+1 -1
View File
@@ -8,7 +8,7 @@ from pathlib import Path
WINDOWS_SYSTEM_DLLS = {
'advapi32.dll', 'bcrypt.dll', 'crypt32.dll', 'dnsapi.dll', 'iphlpapi.dll',
'kernel32.dll', 'msvcrt.dll', 'ntdll.dll', 'ole32.dll', 'psapi.dll',
'dbghelp.dll', 'kernel32.dll', 'msvcrt.dll', 'ntdll.dll', 'ole32.dll', 'psapi.dll',
'rpcrt4.dll', 'secur32.dll', 'shell32.dll', 'ucrtbase.dll', 'user32.dll',
'userenv.dll', 'winmm.dll', 'ws2_32.dll',
}
+14 -1
View File
@@ -1,8 +1,21 @@
cmake_minimum_required(VERSION 3.20)
project(shadowsocks_consumer LANGUAGES C)
find_package(shadowsocks-libev CONFIG REQUIRED)
set(SS_PACKAGE_NAME shadowsocks-c CACHE STRING "Installed package to test")
find_package(${SS_PACKAGE_NAME} CONFIG REQUIRED)
foreach(kind shared static)
if(TARGET shadowsocks::${kind})
if(SS_PACKAGE_NAME STREQUAL "shadowsocks-libev")
# Exercise legacy filenames as well as legacy package discovery.
foreach(property IMPORTED_LOCATION IMPORTED_IMPLIB)
get_target_property(location shadowsocks::${kind} ${property})
if(location)
get_filename_component(directory "${location}" DIRECTORY)
get_filename_component(filename "${location}" NAME)
string(REPLACE "shadowsocks-c" "shadowsocks-libev" filename "${filename}")
set_property(TARGET shadowsocks::${kind} PROPERTY ${property} "${directory}/${filename}")
endif()
endforeach()
endif()
add_executable(consumer_${kind} main.c)
target_link_libraries(consumer_${kind} PRIVATE shadowsocks::${kind})
endif()
+3 -3
View File
@@ -172,10 +172,10 @@ done
# Shared library should be findable by ldconfig
sudo ldconfig
if ldconfig -p | grep -q libshadowsocks-libev; then
check_pass "libshadowsocks-libev found by ldconfig"
if ldconfig -p | grep -q libshadowsocks-c; then
check_pass "libshadowsocks-c found by ldconfig"
else
check_fail "libshadowsocks-libev not found by ldconfig"
check_fail "libshadowsocks-c not found by ldconfig"
fi
# Header should be in the include path
+84
View File
@@ -0,0 +1,84 @@
#include "test_helpers.h"
#include <string.h>
#include "ss_event.h"
#include <uv.h>
#ifdef __APPLE__
#include <sys/event.h>
#endif
int verbose = 0;
struct receiver { ss_io io; int count; };
static void receive(struct ss_loop *loop, ss_io *io, int events)
{
struct receiver *r = (struct receiver *)io;
char byte;
assert(events & SS_READ);
assert(recv(io->fd, &byte, 1, 0) == 1 && byte == 'x');
r->count++;
ss_io_stop(loop, io);
}
struct shared { ss_io io; ss_io *other; int *calls; };
static void destroy_peer(struct ss_loop *loop, ss_io *io, int events)
{
(void)events;
struct shared *s = (struct shared *)io;
(*s->calls)++;
ss_io_stop(loop, s->other);
free(s->other);
ss_io_stop(loop, io);
free(s);
}
static void must_not_run(struct ss_loop *loop, ss_io *io, int events)
{
(void)loop; (void)io; (void)events;
assert(!"stopped watcher was invoked");
}
int main(void)
{
test_network_init();
struct ss_loop *loop = ss_loop_new(0);
assert(loop);
#ifdef _WIN32
assert(strcmp(ss_backend_name(), "iocp") == 0);
assert(ss_native_loop(loop)->iocp != NULL);
#elif defined(__APPLE__)
assert(strcmp(ss_backend_name(), "kqueue") == 0);
struct timespec zero = {0};
assert(kevent(uv_backend_fd(ss_native_loop(loop)), NULL, 0, NULL, 0, &zero) == 0);
#endif
/* Exceed Winsock select's default 64 descriptors. */
struct receiver receivers[256] = {0};
ss_socket_t sender = socket(AF_INET, SOCK_DGRAM, 0);
for (unsigned i = 0; i < 256; i++) {
int fd = (int)socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in address = {0};
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
assert(bind(fd, (struct sockaddr *)&address, sizeof(address)) == 0);
socklen_t length = sizeof(address);
assert(getsockname(fd, (struct sockaddr *)&address, &length) == 0);
ss_io_init(&receivers[i].io, receive, fd, SS_READ);
ss_io_start(loop, &receivers[i].io);
assert(sendto(sender, "x", 1, 0, (struct sockaddr *)&address, length) == 1);
}
ss_run(loop, 0);
for (unsigned i = 0; i < 256; i++) {
assert(receivers[i].count == 1);
ss_socket_close(receivers[i].io.fd);
}
/* Both directions share one poll handle; freeing a pending peer is safe. */
int calls = 0;
ss_io *other = calloc(1, sizeof(*other));
struct shared *owner = calloc(1, sizeof(*owner));
assert(other && owner);
ss_io_init(other, must_not_run, (int)sender, SS_WRITE);
ss_io_init(&owner->io, destroy_peer, (int)sender, SS_WRITE);
owner->other = other; owner->calls = &calls;
ss_io_start(loop, other);
ss_io_start(loop, &owner->io);
ss_run(loop, 0);
assert(calls == 1);
ss_socket_close(sender);
assert(ss_run(loop, SS_RUN_NOWAIT) == 0);
ss_loop_destroy(loop);
return 0;
}
+1
View File
@@ -113,6 +113,7 @@ test_get_sockaddr_rejects_invalid_ip_literal_ports(void)
struct sockaddr_in *addr4 = (struct sockaddr_in *)&storage;
memset(&storage, 0, sizeof(storage));
assert(get_sockaddr("localhost", "8388", &storage, 0, 0) == -1);
assert(get_sockaddr("127.0.0.1", "8388", &storage, 0, 0) == 0);
assert(addr4->sin_family == AF_INET);
assert(ntohs(addr4->sin_port) == 8388);
+5 -5
View File
@@ -1,6 +1,6 @@
/* Exercise real c-ares cancellation with outstanding A and AAAA requests. */
#include "test_helpers.h"
#include <ev.h>
#include "ss_event.h"
#include "resolv.h"
int verbose = 0;
@@ -32,7 +32,7 @@ int main(void)
assert(getsockname(sink, (struct sockaddr *)&address, &size) == 0);
char nameserver[64];
snprintf(nameserver, sizeof(nameserver), "127.0.0.1:%u", ntohs(address.sin_port));
struct ev_loop *loop = ev_loop_new(0);
struct ss_loop *loop = ss_loop_new(0);
assert(loop != NULL);
for (unsigned round = 0; round < 3; round++) {
struct result results[64] = {{0}};
@@ -42,15 +42,15 @@ int main(void)
snprintf(hostname, sizeof(hostname), "pending-%u.invalid", i);
resolv_start(hostname, htons(443), resolved, released, &results[i]);
}
ev_run(loop, EVRUN_NOWAIT);
ss_run(loop, SS_RUN_NOWAIT);
resolv_shutdown(loop);
for (unsigned i = 0; i < 64; i++) {
assert(results[i].called == 1);
assert(results[i].freed == 1);
}
assert(ev_run(loop, EVRUN_NOWAIT) == 0);
assert(ss_run(loop, SS_RUN_NOWAIT) == 0);
}
ev_loop_destroy(loop);
ss_loop_destroy(loop);
ss_socket_close(sink);
return 0;
}
+140
View File
@@ -0,0 +1,140 @@
/* Local delayed DNS server proves A/AAAA/NXDOMAIN completion without blocking. */
#include "test_helpers.h"
#include <string.h>
#include "ss_event.h"
#include "resolv.h"
int verbose = 0;
struct packet {
struct packet *next;
struct sockaddr_storage peer;
socklen_t peer_len;
unsigned char bytes[512];
size_t length;
};
static struct packet *packets;
static ss_io dns_io;
static ss_timer reply_timer, ticker, deadline;
static unsigned ticks, completed;
static int family;
struct result { unsigned called, freed; int missing; };
static void reply(struct ss_loop *loop, ss_timer *timer, int events)
{
(void)loop; (void)timer; (void)events;
while (packets) {
struct packet *p = packets;
packets = p->next;
assert(sendto(dns_io.fd, (const char *)p->bytes, (int)p->length, 0,
(struct sockaddr *)&p->peer, p->peer_len) == (int)p->length);
free(p);
}
}
static void question(struct ss_loop *loop, ss_io *io, int events)
{
(void)events;
struct packet *p = calloc(1, sizeof(*p));
assert(p);
p->peer_len = sizeof(p->peer);
int count = (int)recvfrom(io->fd, (char *)p->bytes, sizeof(p->bytes), 0,
(struct sockaddr *)&p->peer, &p->peer_len);
assert(count > 16 && p->bytes[4] == 0 && p->bytes[5] == 1);
size_t end = 12;
while (end < (size_t)count && p->bytes[end]) end += p->bytes[end] + 1;
end += 5; /* terminating zero, QTYPE, QCLASS */
assert(end <= (size_t)count && end + 28 <= sizeof(p->bytes));
unsigned type = p->bytes[end - 3];
int missing = p->bytes[13] == 'm';
p->bytes[2] = 0x81; p->bytes[3] = missing ? 0x83 : 0x80;
p->bytes[6] = 0; p->bytes[7] = missing ? 0 : 1;
memset(p->bytes + 8, 0, 4);
p->length = end;
if (!missing) {
unsigned char answer[] = {0xc0,0x0c,0,0,0,1,0,0,0,1,0,0};
assert(type == 1 || type == 28);
answer[3] = (unsigned char)type;
answer[11] = type == 1 ? 4 : 16;
memcpy(p->bytes + end, answer, sizeof(answer));
p->length += sizeof(answer);
memset(p->bytes + p->length, 0, 16);
if (type == 1) { p->bytes[p->length] = 127; p->bytes[p->length+3] = 1; }
else p->bytes[p->length+15] = 1;
p->length += answer[11];
}
p->next = packets; packets = p;
ss_timer_start(loop, &reply_timer);
}
static void tick(struct ss_loop *loop, ss_timer *timer, int events)
{
(void)loop; (void)timer; (void)events; ticks++;
}
static void timed_out(struct ss_loop *loop, ss_timer *timer, int events)
{
(void)loop; (void)timer; (void)events;
assert(!"asynchronous DNS did not complete");
}
static struct ss_loop *test_loop;
static void resolved(struct sockaddr *address, void *data)
{
struct result *r = data;
assert(!r->called && !r->freed && ticks > 2);
r->called++;
if (r->missing) assert(address == NULL);
else {
assert(address && address->sa_family == family);
if (family == AF_INET) assert(((struct sockaddr_in *)address)->sin_port == htons(443));
else assert(((struct sockaddr_in6 *)address)->sin6_port == htons(443));
}
if (++completed == 33) ss_unloop(test_loop, SS_UNLOOP_ALL);
}
static void released(void *data)
{
struct result *r = data;
assert(r->called == 1 && !r->freed);
r->freed++;
}
int main(void)
{
test_network_init();
test_loop = ss_loop_new(0);
int fd = (int)socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in address = {0};
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
assert(bind(fd, (struct sockaddr *)&address, sizeof(address)) == 0);
socklen_t length = sizeof(address);
assert(getsockname(fd, (struct sockaddr *)&address, &length) == 0);
char nameserver[64];
snprintf(nameserver, sizeof(nameserver), "127.0.0.1:%u", ntohs(address.sin_port));
ss_io_init(&dns_io, question, fd, SS_READ);
ss_timer_init(&reply_timer, reply, .05, 0);
ss_timer_init(&ticker, tick, .001, .001);
ss_timer_init(&deadline, timed_out, 10, 0);
for (int ipv6 = 0; ipv6 < 2; ipv6++) {
struct result results[33] = {{0}};
results[32].missing = 1;
family = ipv6 ? AF_INET6 : AF_INET;
ticks = completed = 0;
assert(resolv_init(test_loop, nameserver, ipv6) == 0);
ss_io_start(test_loop, &dns_io);
ss_timer_start(test_loop, &ticker);
ss_timer_start(test_loop, &deadline);
for (unsigned i = 0; i < 33; i++) {
char host[64];
snprintf(host, sizeof(host), "%s-%u.invalid", i == 32 ? "missing" : "resolved", i);
resolv_start(host, htons(443), resolved, released, &results[i]);
}
assert(completed == 0);
ss_run(test_loop, 0);
assert(completed == 33);
for (unsigned i = 0; i < 33; i++) assert(results[i].called == 1 && results[i].freed == 1);
resolv_shutdown(test_loop);
ss_io_stop(test_loop, &dns_io);
ss_timer_stop(test_loop, &ticker);
ss_timer_stop(test_loop, &deadline);
ss_timer_stop(test_loop, &reply_timer);
assert(!packets);
assert(ss_run(test_loop, SS_RUN_NOWAIT) == 0);
}
ss_socket_close(fd);
ss_loop_destroy(test_loop);
return 0;
}
+11 -11
View File
@@ -63,20 +63,20 @@ set(PCRE2_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/pcre2" PARENT_SCOPE)
endif()
add_library(ss_ev STATIC "${ev_SOURCE}/ev.c")
target_compile_definitions(ss_ev PRIVATE EV_STANDALONE=1)
target_include_directories(ss_ev PUBLIC "${ev_SOURCE}")
if(WIN32)
target_link_libraries(ss_ev PUBLIC ws2_32)
target_compile_options(ss_ev PRIVATE -include "${CMAKE_CURRENT_SOURCE_DIR}/libev_windows.h")
endif()
set(LIBUV_BUILD_SHARED OFF CACHE BOOL "" FORCE)
set(LIBUV_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(LIBUV_BUILD_BENCH OFF CACHE BOOL "" FORCE)
include(LibuvWindows.cmake)
add_subdirectory("${uv_SOURCE}" uv EXCLUDE_FROM_ALL)
add_library(ss_uv ALIAS uv_a)
include(${PROJECT_SOURCE_DIR}/cmake/EventLoop.cmake)
include(Sodium.cmake)
foreach(name sodium ev mbedtls)
install(FILES "${${name}_SOURCE}/LICENSE" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-libev/${name}")
foreach(name sodium uv mbedtls)
install(FILES "${${name}_SOURCE}/LICENSE" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-c/${name}")
endforeach()
install(FILES "${cares_SOURCE}/LICENSE.md" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-libev/cares")
install(FILES "${cares_SOURCE}/LICENSE.md" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-c/cares")
if(SS_ENABLE_REGEX)
install(FILES "${pcre2_SOURCE}/LICENCE.md" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-libev/pcre2")
install(FILES "${pcre2_SOURCE}/LICENCE.md" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/shadowsocks-c/pcre2")
endif()
+23
View File
@@ -0,0 +1,23 @@
# libuv 1.52.1 passes const char ** to a converter that writes char **.
# GCC 14+ rejects this. Keep the archive untouched and use a mutable temporary
# in the extracted source, assigning it to the const public field afterwards.
if(WIN32)
set(uv_util "${uv_SOURCE}/src/win/util.c")
file(READ "${uv_util}" uv_util_content)
set(uv_old [=[ uv__convert_utf16_to_utf8(cpu_brand,
cpu_brand_size / sizeof(WCHAR),
&(cpu_info->model));]=])
set(uv_new [=[ char* model = NULL;
uv__convert_utf16_to_utf8(cpu_brand,
cpu_brand_size / sizeof(WCHAR),
&model);
cpu_info->model = model;]=])
string(FIND "${uv_util_content}" "${uv_old}" uv_old_offset)
string(FIND "${uv_util_content}" "${uv_new}" uv_new_offset)
if(NOT uv_old_offset EQUAL -1)
string(REPLACE "${uv_old}" "${uv_new}" uv_util_content "${uv_util_content}")
file(WRITE "${uv_util}" "${uv_util_content}")
elseif(uv_new_offset EQUAL -1)
message(FATAL_ERROR "Bundled libuv changed; review the Windows CPU-info compatibility fix")
endif()
endif()
+12 -6
View File
@@ -10,22 +10,28 @@ signature verification.
- libsodium 1.0.22: ISC; see LICENSE in the archive.
- c-ares 1.34.8: MIT; see LICENSE.md in the archive.
- PCRE2 10.48: BSD-3-Clause; see LICENCE.md in the archive, including third-party notices.
- libev 4.33: BSD-2-Clause OR GPL-2.0-or-later; see LICENSE and source notices.
- libuv 1.52.1: MIT; see LICENSE in the archive, including third-party notices.
- bloom: copied unchanged from the former shadowsocks/libbloom submodule,
commit 437e1add5a2b9a87797d8c648df7cf5f3ee155a8. BSD-2-Clause;
license and MurmurHash2 source notices retained alongside the sources.
- BLAKE3 remains in src/blake3; its existing license files remain there.
- uthash remains in src/uthash.h with its upstream copyright/license notice.
Mbed TLS, c-ares and PCRE2 use their upstream CMake builds. The local libsodium
Mbed TLS, c-ares, libuv and PCRE2 use their upstream CMake builds. The local libsodium
CMake adapter compiles the portable C backends listed in upstream Makefile.am;
it is maintained by this project, not upstream. Upstream known-answer tests
are built and run under the `vendor` CTest label. SIMD acceleration needs its
own compiler probes and validation before enabling additional backends.
On Windows, `libev_windows.h` selects raw Winsock handles rather than CRT file
descriptors, consistently for application I/O and libev's wakeup sockets.
Windows therefore requires bundled mode; an arbitrary system libev build does
not necessarily use the same descriptor convention.
On Windows, `LibuvWindows.cmake` applies a checked, idempotent fix to extracted
libuv 1.52.1 CPU-info code: a mutable string temporary replaces an incompatible
`const char **` output argument rejected by GCC 14+. The archive is unchanged.
Libuv replaces libev. Its Windows socket polling uses AFD readiness requests
completed through IOCP; macOS uses kqueue. The internal `ss_event` layer combines
read/write watchers for each descriptor and owns libuv handle lifetime separately
from connection objects. c-ares stays integrated into that loop for asynchronous
A/AAAA resolution, custom DNS servers and cancellation. Native platform tests
exercise the backend, concurrent watchers, delayed DNS completion and shutdown.
To update an archive: select a supported upstream release, download its release
archive from the upstream source, verify published signatures/checksums where
Binary file not shown.
Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
/* libev's int watcher descriptors carry Winsock handles in this application.
* Keep the same conversion for its wakeup socket pair and application I/O.
* The default CRT descriptor conversion is incompatible with raw sockets.
*/
#include <winsock2.h>
#define EV_FD_TO_WIN32_HANDLE(fd) ((SOCKET)(unsigned int)(fd))
#define EV_WIN32_HANDLE_TO_FD(handle) ((int)(handle))
#define EV_WIN32_CLOSE_FD(fd) closesocket(EV_FD_TO_WIN32_HANDLE(fd))
+5 -5
View File
@@ -28,10 +28,10 @@
"sha256": "adbdd8f16149e81ac6078a03aca6fc03b592b89ef7b5ed83841c086191be3349"
},
{
"name": "ev",
"version": "4.33",
"url": "https://dist.schmorp.de/libev/libev-4.33.tar.gz",
"archive": "libev-4.33.tar.gz",
"sha256": "507eb7b8d1015fbec5b935f34ebed15bf346bed04a11ab82b8eee848c4205aea"
"name": "uv",
"version": "1.52.1",
"url": "https://dist.libuv.org/dist/v1.52.1/libuv-v1.52.1.tar.gz",
"archive": "libuv-v1.52.1.tar.gz",
"sha256": "66d511b9e6e334c0e62279eb234fbfb2b3110b1479c09b95b44c7afca8cff9e7"
}
]