Files
shadowsocks-libev/CLAUDE.md
Max Lv df7a6dc13f Add the C++ event layer over libuv
src/event/loop.hpp wraps uv_loop/poll/timer/signal/async handles that
live by value inside their owner and dispatch to an owner member
function chosen at compile time. A Poll owns its socket and carries
read and write interest on one handle, closing the descriptor in
libuv's close callback. CloseGroup collects the asynchronous closes of
an owner's handles and reports completion afterwards, which is how
pooled owners implement AsyncClosable. DeadlineList drives the idle
timeouts of many owners from one timer.

test_event_cpp covers readiness, closing a peer from inside a
callback, recycling a pooled owner only after its handles closed,
repeating timers, deadline ordering and cross-thread wakeups.
2026-10-14 22:51:38 +08:00

6.6 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

shadowsocks-c (formerly shadowsocks-libev) is a lightweight SOCKS5 proxy. Version 3.3.6, licensed under GPLv3. The sources are C11 and are being ported to C++20 module by module (see docs/cpp-core.md); the public src/shadowsocks.h stays a C header with a stable ABI.

Build Commands

CMake (sole build system)

cmake --preset bundled          # or: cmake -S . -B build -G Ninja
cmake --build --preset bundled
ctest --preset bundled

Bundled mode (the default, SS_DEPENDENCY_MODE=bundled) builds every dependency from the pinned archives in third_party/dist with no network access. SS_DEPENDENCY_MODE=system uses distro libraries instead. There are no git submodules.

Binaries land in <build>/bin/, libraries in <build>/lib/.

Build Dependencies

  • CMake >= 3.20, C11 and C++20 compilers (GCC >= 11, Clang >= 14, Apple Clang >= 15), Ninja for the presets
  • System mode only: Mbed TLS 2.x/3.x, libsodium >= 1.0.4, PCRE2 (8-bit), libuv, c-ares
  • Doxygen (documentation only)

CMake Options

  • -DSS_MINIMAL=ON: no regex, plugins, manager or legacy stream ciphers
  • -DWITH_STATIC=OFF: link third-party dependencies dynamically
  • -DSS_BUILD_EXECUTABLES / SS_BUILD_STATIC_LIBRARY / SS_BUILD_SHARED_LIBRARY: choose outputs
  • -DWITH_DOC_MAN=ON / -DWITH_DOC_HTML=ON: build documentation
  • -DENABLE_CONNMARKTOS=ON, -DENABLE_NFTABLES=ON: Linux netfilter features
  • -DENABLE_SANITIZERS=ON, -DENABLE_COVERAGE=ON, -DDISABLE_SSP=ON, -DBUILD_TESTING=OFF

Testing

Unit Tests (CTest)

ctest --test-dir build -LE memcheck --output-on-failure

C unit tests (tests/test_*.c) compile the specific src/*.c files they need (see ss_add_test in tests/CMakeLists.txt). C++ core tests are tests/test_core_*.cpp using tests/test_helpers.hpp. Labels: unit, vendor, integration, memcheck (Linux + valgrind).

Integration Tests

python3 tests/interop.py --self --bin build/bin          # TCP/UDP relay, all AEAD/2022 methods
python3 tests/test.py --bin build/bin/ -c tests/aes-gcm.json   # one cipher via curl/dig (needs network)
python3 tests/test_cli.py --bin-dir build/bin           # CLI contract: help/version/exit codes
python3 tests/stress_test.py --bin build/bin/ --size 10

Allocation audit

python3 tests/alloc_audit/measure_alloc.py --bin build/bin --shim build/lib/libss_alloc_audit.dylib

Reports heap allocations per relayed connection (C baseline numbers are in docs/cpp-core.md).

Code Formatting

Uses uncrustify with the config at .uncrustify.cfg. Key settings: 4-space indent, no tabs, 120-column width, K&R brace style (braces on same line).

Code Quality Tooling

  • clang-tidy: config in .clang-tidy. The build exports compile_commands.json automatically. Run locally:
    run-clang-tidy -quiet -p build '/(src/(core/|event/|relay/|crypto/|api/)?[^/]+\.(c|cpp)|tests/test_(core_[^/]+|event_cpp)\.cpp)$'
    
    On macOS with Homebrew LLVM, add -extra-arg="-isysroot$(xcrun --show-sdk-path)". CI (clang-tidy job in tests.yml) enforces a warning-count ratchet via MAX_WARNINGS — lower it when fixing findings; never raise it without justification.
  • No-heap lint: scripts/check_no_heap.py --self-test (also a ctest) rejects heap allocation in C++ sources under src/.
  • Sanitizers: cmake .. -DENABLE_SANITIZERS=ON builds with ASan + UBSan. CI runs ctest and the stress test under sanitizers on every PR.
  • Coverage: cmake .. -DENABLE_COVERAGE=ON, run tests, then make coverage (needs lcov). HTML report lands in build/coverage-html/. CI uploads it as the coverage-html artifact.

Architecture

Binaries (all in src/)

Each binary is compiled with a module define that controls conditional compilation:

Binary Define Purpose
ss-local MODULE_LOCAL SOCKS5 client proxy
ss-server MODULE_REMOTE Server-side proxy
ss-tunnel MODULE_TUNNEL Port forwarding tunnel (implies MODULE_LOCAL)
ss-redir MODULE_REDIR Transparent proxy via iptables (Linux only, implies MODULE_LOCAL)
ss-manager MODULE_MANAGER Multi-server manager daemon (Linux only by default)

A library libshadowsocks-c (legacy names libshadowsocks-libev.* are kept) is built from the ss-local sources with -DLIB_ONLY. Its public API is in src/shadowsocks.h.

Source Organization (src/)

Shared by all binaries:

  • utils.cpp - logging, system utilities, ss_malloc/ss_free
  • jconf.cpp / json.cpp - JSON config file parsing
  • netutils.cpp - network address utilities
  • cache.cpp - uthash-based connection cache (UDP relay, AEAD-2022 tables)
  • udprelay.cpp - UDP relay implementation (shared, but uses #ifdef MODULE_* for per-binary behavior)
  • ss_event.cpp / ss_event.h - event loop API over libuv
  • resolv.cpp - asynchronous DNS via c-ares

Crypto layer (behind a common crypto_t function-pointer interface):

  • crypto.cpp / crypto.h - crypto initialization, key derivation (HKDF), buffer_t management
  • stream.cpp - legacy stream ciphers
  • aead.cpp - AEAD ciphers (AES-GCM via Mbed TLS/libsodium, ChaCha20-Poly1305 via libsodium)
  • aead2022.cpp / aead2022_udp.cpp - Shadowsocks 2022 (SIP022), BLAKE3 from src/blake3
  • ppbloom.cpp - ping-pong bloom filter for salt replay detection (third_party/bloom)

ACL: acl.cpp / rule.cpp / ipset.cpp - IP prefix sets and PCRE2/literal domain rules.

Plugins: plugin.cpp / process.cpp - SIP003 plugin subprocess management.

C++ core: src/core/*.hpp - header-only ownership and allocation primitives (pools, handles, fixed buffers, arena, fixed hash map/LRU, intrusive list, bounded heap). See docs/cpp-core.md.

Event Loop

All binaries use the ss_event API (libuv backend: kqueue/epoll/IOCP). The connection lifecycle follows stages defined in src/common.h: STAGE_INIT -> STAGE_HANDSHAKE -> STAGE_RESOLVE -> STAGE_STREAM -> STAGE_STOP. Each binary defines its own listen_ctx_t, server_t, and remote_t structs (note: "server" in local.h means the local-side connection, "remote" means the ss-server side).

Compiler Flags

From cmake/ProjectOptions.cmake: -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fstack-protector-strong, plus _GNU_SOURCE on Linux. C is C11 with GNU extensions. C++ is C++20 without extensions and adds -Wextra -fno-exceptions -fno-rtti -fno-threadsafe-statics.

-Werror means all warnings are errors — new code must compile warning-free.