mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-28 10:44:43 +08:00
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:
1 parent
201e70c4bd
commit
bdc77408cb
61 files changed
+1695
-851
No files matched your search
+2
-2
@@ -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-*,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# shadowsocks-libev
|
||||
# shadowsocks-c
|
||||
|
||||
[](https://travis-ci.com/shadowsocks/shadowsocks-libev) [](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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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@
|
||||
Vendored
+2
-2
@@ -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
@@ -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/
|
||||
Vendored
+1
@@ -1 +1,2 @@
|
||||
usr/lib/*/libshadowsocks-libev.so.*
|
||||
usr/lib/*/libshadowsocks-c.so.*
|
||||
Vendored
+2
-2
@@ -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
@@ -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,
|
||||
@@ -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"; \
|
||||
|
||||
@@ -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
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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',
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Vendored
+11
-11
@@ -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()
|
||||
Vendored
+23
@@ -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()
|
||||
Vendored
+12
-6
@@ -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
|
||||
|
||||
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
-8
@@ -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))
|
||||
Vendored
+5
-5
@@ -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"
|
||||
}
|
||||
]
|
||||
Reference in new issue
Block a user