From 349d895fd28adaf7135cde760168792ab4ecf463 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Wed, 14 Oct 2026 13:12:24 +0800 Subject: [PATCH] Compile the crypto, config, DNS, ACL and plugin modules as C++ Rename netutils, jconf, stream, aead, aead2022, aead2022_udp, crypto, acl, plugin, plugin_disabled and resolv from .c to .cpp without changing their contents, and update source lists, snippet references, test comments and debian/copyright. The Doxygen source list and scripts/check_cli_docs.py now accept either extension for each module, so the remaining programs can move one at a time. The new .cpp files are added to the no-heap ratchet baseline. --- CLAUDE.md | 18 ++++++------- debian/copyright | 2 +- doc/CMakeLists.txt | 7 ++++- scripts/check_cli_docs.py | 12 +++++++-- scripts/no_heap_baseline.txt | 8 ++++++ scripts/ss-setup.sh | 2 +- src/CMakeLists.txt | 24 ++++++++--------- src/{acl.c => acl.cpp} | 0 src/{aead.c => aead.cpp} | 0 src/{aead2022.c => aead2022.cpp} | 0 src/{aead2022_udp.c => aead2022_udp.cpp} | 0 src/aead_internal.h | 6 ++--- src/{crypto.c => crypto.cpp} | 0 src/{jconf.c => jconf.cpp} | 0 src/{netutils.c => netutils.cpp} | 0 src/{plugin.c => plugin.cpp} | 0 ...{plugin_disabled.c => plugin_disabled.cpp} | 0 src/{resolv.c => resolv.cpp} | 0 src/{stream.c => stream.cpp} | 0 src/utils.c | 4 +-- tests/CMakeLists.txt | 26 +++++++++---------- tests/test_aead2022.c | 2 +- tests/test_buffer.c | 2 +- tests/test_crypto.c | 4 +-- 24 files changed, 69 insertions(+), 48 deletions(-) rename src/{acl.c => acl.cpp} (100%) rename src/{aead.c => aead.cpp} (100%) rename src/{aead2022.c => aead2022.cpp} (100%) rename src/{aead2022_udp.c => aead2022_udp.cpp} (100%) rename src/{crypto.c => crypto.cpp} (100%) rename src/{jconf.c => jconf.cpp} (100%) rename src/{netutils.c => netutils.cpp} (100%) rename src/{plugin.c => plugin.cpp} (100%) rename src/{plugin_disabled.c => plugin_disabled.cpp} (100%) rename src/{resolv.c => resolv.cpp} (100%) rename src/{stream.c => stream.cpp} (100%) diff --git a/CLAUDE.md b/CLAUDE.md index 8347cb7a..17225d41 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -103,23 +103,23 @@ A library `libshadowsocks-c` (legacy names `libshadowsocks-libev.*` are kept) is **Shared by all binaries:** - `utils.c` - logging, system utilities, `ss_malloc`/`ss_free` -- `jconf.c` / `json.cpp` - JSON config file parsing -- `netutils.c` - network address utilities +- `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.c` - UDP relay implementation (shared, but uses `#ifdef MODULE_*` for per-binary behavior) - `ss_event.c` / `ss_event.h` - event loop API over libuv -- `resolv.c` - asynchronous DNS via c-ares +- `resolv.cpp` - asynchronous DNS via c-ares **Crypto layer** (behind a common `crypto_t` function-pointer interface): -- `crypto.c` / `crypto.h` - crypto initialization, key derivation (HKDF), `buffer_t` management -- `stream.c` - legacy stream ciphers -- `aead.c` - AEAD ciphers (AES-GCM via Mbed TLS/libsodium, ChaCha20-Poly1305 via libsodium) -- `aead2022.c` / `aead2022_udp.c` - Shadowsocks 2022 (SIP022), BLAKE3 from `src/blake3` +- `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.c` / `rule.cpp` / `ipset.cpp` - IP prefix sets and PCRE2/literal domain rules. +**ACL:** `acl.cpp` / `rule.cpp` / `ipset.cpp` - IP prefix sets and PCRE2/literal domain rules. -**Plugins:** `plugin.c` / `process.cpp` - SIP003 plugin subprocess management. +**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`. diff --git a/debian/copyright b/debian/copyright index 148d692f..7074f1a4 100644 --- a/debian/copyright +++ b/debian/copyright @@ -49,7 +49,7 @@ Files: src/json.cpp src/json.h Copyright: 2012-2014, James McLaughlin et al. License: BSD-2-clause -Files: src/resolv.c src/resolv.h +Files: src/resolv.cpp src/resolv.h Copyright: 2011-2014, Dustin Lundquist License: BSD-2-clause diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 6b3d0dce..a49bdac7 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -16,7 +16,12 @@ foreach(name IN LISTS DOC_NAMES) endforeach() set(DOC_SOURCES) foreach(name local server tunnel redir manager utils aead stream) - list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/${name}.c") + # Modules are moving from C to C++ one at a time. + if(EXISTS "${PROJECT_SOURCE_DIR}/src/${name}.cpp") + list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/${name}.cpp") + else() + list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/${name}.c") + endif() endforeach() list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/ss-nat") diff --git a/scripts/check_cli_docs.py b/scripts/check_cli_docs.py index c87a196d..75575d58 100644 --- a/scripts/check_cli_docs.py +++ b/scripts/check_cli_docs.py @@ -98,13 +98,21 @@ def documented_options(source_name, sources): return result +def module_source(sources, module): + """Source file name for a program module; modules move from .c to .cpp.""" + for suffix in ('.c', '.cpp'): + if module + suffix in sources: + return module + suffix + raise ValueError(f"No source file for module {module}") + + def check(root=ROOT, rendered=None): sources = {path.name: path.read_text(encoding='utf-8') - for path in (root / 'src').glob('*.c')} + for pattern in ('*.c', '*.cpp') for path in (root / 'src').glob(pattern)} sources['ss-nat'] = (root / 'src/ss-nat').read_text(encoding='utf-8') for module in PROGRAMS: program = 'ss-' + module - filename = 'ss-nat' if module == 'nat' else module + '.c' + filename = 'ss-nat' if module == 'nat' else module_source(sources, module) declared = options(sources[filename], shell=module == 'nat') documented = documented_options(filename, sources) missing = declared.keys() - documented.keys() diff --git a/scripts/no_heap_baseline.txt b/scripts/no_heap_baseline.txt index 6cedf8e0..7c7fe012 100644 --- a/scripts/no_heap_baseline.txt +++ b/scripts/no_heap_baseline.txt @@ -2,9 +2,17 @@ # Format: . check_no_heap.py fails if a file gains # violations, and also when it loses some, so the number here always goes # down. Remove a file once it is rewritten on the src/core primitives. +src/aead.cpp 4 +src/aead2022.cpp 3 +src/aead2022_udp.cpp 5 src/cache.cpp 3 +src/crypto.cpp 4 src/ipset.cpp 3 +src/jconf.cpp 16 src/json.cpp 2 +src/plugin.cpp 3 src/process.cpp 26 +src/resolv.cpp 6 src/rule.cpp 2 src/ssurl.cpp 3 +src/stream.cpp 3 diff --git a/scripts/ss-setup.sh b/scripts/ss-setup.sh index 72fdaf41..4726018f 100755 --- a/scripts/ss-setup.sh +++ b/scripts/ss-setup.sh @@ -14,7 +14,7 @@ readonly CONFIG_DIR="/etc/shadowsocks-libev" readonly SYSTEMD_UNIT_DIR="/etc/systemd/system" readonly SYSTEMD_TEMPLATE="shadowsocks-libev-server@.service" -# AEAD ciphers supported by shadowsocks-libev (from src/aead.c) +# AEAD ciphers supported by shadowsocks-libev (from src/aead.cpp) readonly AEAD_CIPHERS=( "chacha20-ietf-poly1305" "aes-256-gcm" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe150898..74ba2e00 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,16 +9,16 @@ endif () set(SS_ACL_SOURCE - acl.c + acl.cpp ipset.cpp rule.cpp ) set(SS_CRYPTO_SOURCE - crypto.c - aead.c - aead2022.c - aead2022_udp.c + crypto.cpp + aead.cpp + aead2022.cpp + aead2022_udp.cpp base64.cpp ) @@ -40,20 +40,20 @@ target_compile_options(blake3 PRIVATE -Wno-error -Wno-unused-function) set_target_properties(blake3 PROPERTIES POSITION_INDEPENDENT_CODE ON) if(SS_ENABLE_LEGACY) - list(APPEND SS_CRYPTO_SOURCE stream.c) + list(APPEND SS_CRYPTO_SOURCE stream.cpp) endif() if(SS_ENABLE_PLUGINS) - set(SS_PLUGIN_SOURCE plugin.c process.cpp) + set(SS_PLUGIN_SOURCE plugin.cpp process.cpp) else() - set(SS_PLUGIN_SOURCE plugin_disabled.c) + set(SS_PLUGIN_SOURCE plugin_disabled.cpp) endif() set(SS_SHARED_SOURCES ppbloom.cpp utils.c - jconf.c + jconf.cpp json.cpp - netutils.c + netutils.cpp ) if (MINGW) set(SS_SHARED_SOURCES ${SS_SHARED_SOURCES} winsock.c) @@ -64,7 +64,7 @@ set(LIBSHADOWSOCKS_LIBEV_SOURCE udprelay.c cache.cpp local.c - resolv.c + resolv.cpp ssurl.cpp ${SS_CRYPTO_SOURCE} ${SS_PLUGIN_SOURCE} @@ -89,7 +89,7 @@ set(SS_SERVER_SOURCE ${SS_SHARED_SOURCES} udprelay.c cache.cpp - resolv.c + resolv.cpp server.c ${SS_CRYPTO_SOURCE} ${SS_PLUGIN_SOURCE} diff --git a/src/acl.c b/src/acl.cpp similarity index 100% rename from src/acl.c rename to src/acl.cpp diff --git a/src/aead.c b/src/aead.cpp similarity index 100% rename from src/aead.c rename to src/aead.cpp diff --git a/src/aead2022.c b/src/aead2022.cpp similarity index 100% rename from src/aead2022.c rename to src/aead2022.cpp diff --git a/src/aead2022_udp.c b/src/aead2022_udp.cpp similarity index 100% rename from src/aead2022_udp.c rename to src/aead2022_udp.cpp diff --git a/src/aead_internal.h b/src/aead_internal.h index b3be0dcb..80985b3a 100644 --- a/src/aead_internal.h +++ b/src/aead_internal.h @@ -1,5 +1,5 @@ /* - * aead_internal.h - Internal interface shared by aead.c and aead2022.c + * aead_internal.h - Internal interface shared by aead.cpp and aead2022.cpp * * Copyright (C) 2013 - 2026, Max Lv * @@ -54,7 +54,7 @@ is_aead_2022(int method) || method == CHACHA20POLY1305IETF2022; } -/* Low-level one-shot AEAD operations implemented in aead.c */ +/* Low-level one-shot AEAD operations implemented in aead.cpp */ int aead_cipher_encrypt(cipher_ctx_t *cipher_ctx, uint8_t *c, size_t *clen, uint8_t *m, size_t mlen, @@ -67,7 +67,7 @@ int aead_cipher_decrypt(cipher_ctx_t *cipher_ctx, uint8_t *n, uint8_t *k); void aead_cipher_ctx_set_key(cipher_ctx_t *cipher_ctx, int enc); -/* AEAD-2022 pieces implemented in aead2022.c */ +/* AEAD-2022 pieces implemented in aead2022.cpp */ int aead_get_role(void); void ss2022_derive_subkey(const uint8_t *key, size_t key_len, const uint8_t *salt, size_t salt_len, diff --git a/src/crypto.c b/src/crypto.cpp similarity index 100% rename from src/crypto.c rename to src/crypto.cpp diff --git a/src/jconf.c b/src/jconf.cpp similarity index 100% rename from src/jconf.c rename to src/jconf.cpp diff --git a/src/netutils.c b/src/netutils.cpp similarity index 100% rename from src/netutils.c rename to src/netutils.cpp diff --git a/src/plugin.c b/src/plugin.cpp similarity index 100% rename from src/plugin.c rename to src/plugin.cpp diff --git a/src/plugin_disabled.c b/src/plugin_disabled.cpp similarity index 100% rename from src/plugin_disabled.c rename to src/plugin_disabled.cpp diff --git a/src/resolv.c b/src/resolv.cpp similarity index 100% rename from src/resolv.c rename to src/resolv.cpp diff --git a/src/stream.c b/src/stream.cpp similarity index 100% rename from src/stream.c rename to src/stream.cpp diff --git a/src/utils.c b/src/utils.c index de010054..b6f95f9c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -364,11 +364,11 @@ later on the command line override the values taken from the URL. Set the cipher. The default is `chacha20-ietf-poly1305`. AEAD cipher names from the source (availability depends on the build): -\snippet aead.c cli-aead-ciphers +\snippet aead.cpp cli-aead-ciphers Legacy stream cipher names recognized by the source (disabled in minimal builds; some require backend support): -\snippet stream.c cli-stream-ciphers +\snippet stream.cpp cli-stream-ciphers The `2022-blake3-*` ciphers implement Shadowsocks 2022 (SIP022). They require a base64-encoded pre-shared key supplied with `--key` or `--password` (*-k*): 16 bytes for diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 49145de9..7b0befa8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -117,7 +117,7 @@ set(TEST_NETUTILS_LIBS ss_cares ) ss_add_test(test_netutils - "test_netutils.c;${PROJECT_SOURCE_DIR}/src/netutils.c;${PROJECT_SOURCE_DIR}/src/utils.c" + "test_netutils.c;${PROJECT_SOURCE_DIR}/src/netutils.cpp;${PROJECT_SOURCE_DIR}/src/utils.c" "${TEST_NETUTILS_LIBS}") # test_cache - expiration uses a platform monotonic clock @@ -145,7 +145,7 @@ ss_add_test(test_rule # test_acl - ACL precedence and prefix matching set(TEST_ACL_LIBS ${TEST_RULE_LIBS}) ss_add_test(test_acl - "test_acl.c;${PROJECT_SOURCE_DIR}/src/acl.c;${PROJECT_SOURCE_DIR}/src/ipset.cpp;${PROJECT_SOURCE_DIR}/src/rule.cpp;${PROJECT_SOURCE_DIR}/src/utils.c" + "test_acl.c;${PROJECT_SOURCE_DIR}/src/acl.cpp;${PROJECT_SOURCE_DIR}/src/ipset.cpp;${PROJECT_SOURCE_DIR}/src/rule.cpp;${PROJECT_SOURCE_DIR}/src/utils.c" "${TEST_ACL_LIBS}") endif() @@ -157,17 +157,17 @@ set(TEST_JCONF_LIBS ss_cares ) ss_add_test(test_jconf - "test_jconf.c;${PROJECT_SOURCE_DIR}/src/jconf.c;${PROJECT_SOURCE_DIR}/src/json.cpp;${PROJECT_SOURCE_DIR}/src/utils.c;${PROJECT_SOURCE_DIR}/src/netutils.c" + "test_jconf.c;${PROJECT_SOURCE_DIR}/src/jconf.cpp;${PROJECT_SOURCE_DIR}/src/json.cpp;${PROJECT_SOURCE_DIR}/src/utils.c;${PROJECT_SOURCE_DIR}/src/netutils.cpp" "${TEST_JCONF_LIBS};${SS_MATH_LIBRARY}") # Crypto sources shared by the tests that link the crypto layer. The AEAD-2022 # ciphers pull in BLAKE3 (linked as the `blake3` target) and the session-based -# UDP codec, so they must be built together with crypto.c. +# UDP codec, so they must be built together with crypto.cpp. set(SS_CRYPTO_TEST_SOURCES - ${PROJECT_SOURCE_DIR}/src/crypto.c - ${PROJECT_SOURCE_DIR}/src/aead.c - ${PROJECT_SOURCE_DIR}/src/aead2022.c - ${PROJECT_SOURCE_DIR}/src/aead2022_udp.c + ${PROJECT_SOURCE_DIR}/src/crypto.cpp + ${PROJECT_SOURCE_DIR}/src/aead.cpp + ${PROJECT_SOURCE_DIR}/src/aead2022.cpp + ${PROJECT_SOURCE_DIR}/src/aead2022_udp.cpp ${PROJECT_SOURCE_DIR}/src/ppbloom.cpp ${PROJECT_SOURCE_DIR}/src/cache.cpp ${PROJECT_SOURCE_DIR}/src/base64.cpp @@ -175,10 +175,10 @@ set(SS_CRYPTO_TEST_SOURCES ) if(SS_ENABLE_LEGACY) - list(APPEND SS_CRYPTO_TEST_SOURCES ${PROJECT_SOURCE_DIR}/src/stream.c) + list(APPEND SS_CRYPTO_TEST_SOURCES ${PROJECT_SOURCE_DIR}/src/stream.cpp) endif() -# test_buffer - needs sodium and mbedtls for crypto.c buffer functions +# test_buffer - needs sodium and mbedtls for crypto.cpp buffer functions ss_add_test(test_buffer "test_buffer.c;${SS_CRYPTO_TEST_SOURCES}" "ss_sodium;;ss_mbedcrypto;ss_ev;${TEST_PPBLOOM_LIBS};blake3;${SS_MATH_LIBRARY}") @@ -229,7 +229,7 @@ ss_add_test(test_process set_tests_properties(test_process PROPERTIES TIMEOUT 20) ss_add_test(test_resolv - "test_resolv.c;${PROJECT_SOURCE_DIR}/src/resolv.c;${PROJECT_SOURCE_DIR}/src/utils.c" + "test_resolv.c;${PROJECT_SOURCE_DIR}/src/resolv.cpp;${PROJECT_SOURCE_DIR}/src/utils.c" "ss_ev;ss_cares;ss_sodium") set_tests_properties(test_resolv PROPERTIES TIMEOUT 20) @@ -238,13 +238,13 @@ if(SS_ENABLE_REGEX) list(APPEND TEST_LITERAL_LIBS ss_pcre2) endif() ss_add_test(test_acl_literal - "test_acl_literal.c;${PROJECT_SOURCE_DIR}/src/acl.c;${PROJECT_SOURCE_DIR}/src/ipset.cpp;${PROJECT_SOURCE_DIR}/src/rule.cpp;${PROJECT_SOURCE_DIR}/src/utils.c" + "test_acl_literal.c;${PROJECT_SOURCE_DIR}/src/acl.cpp;${PROJECT_SOURCE_DIR}/src/ipset.cpp;${PROJECT_SOURCE_DIR}/src/rule.cpp;${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" + "test_resolv_async.c;${PROJECT_SOURCE_DIR}/src/resolv.cpp;${PROJECT_SOURCE_DIR}/src/utils.c" "ss_ev;ss_cares;ss_sodium") set_tests_properties(test_resolv_async PROPERTIES TIMEOUT 30) diff --git a/tests/test_aead2022.c b/tests/test_aead2022.c index 4a106b1b..9ea21c75 100644 --- a/tests/test_aead2022.c +++ b/tests/test_aead2022.c @@ -19,7 +19,7 @@ int verbose = 0; #include "utils.h" #include "blake3/blake3.h" -/* Provide nonce_cache symbol needed by crypto.c */ +/* Provide nonce_cache symbol needed by crypto.cpp */ struct cache *nonce_cache = NULL; /* 32-byte and 16-byte PSKs in base64 */ diff --git a/tests/test_buffer.c b/tests/test_buffer.c index e021df76..dd80f217 100644 --- a/tests/test_buffer.c +++ b/tests/test_buffer.c @@ -10,7 +10,7 @@ int verbose = 0; #include "crypto.h" -/* Provide nonce_cache symbol needed by crypto.c */ +/* Provide nonce_cache symbol needed by crypto.cpp */ struct cache *nonce_cache = NULL; static void diff --git a/tests/test_crypto.c b/tests/test_crypto.c index e0a4ad71..476fc525 100644 --- a/tests/test_crypto.c +++ b/tests/test_crypto.c @@ -13,7 +13,7 @@ int verbose = 0; #include "ppbloom.h" #include "utils.h" -/* Provide nonce_cache symbol needed by crypto.c */ +/* Provide nonce_cache symbol needed by crypto.cpp */ struct cache *nonce_cache = NULL; static void @@ -366,7 +366,7 @@ main(void) #if SS_ENABLE_LEGACY /* mbedTLS-backed ciphers and libsodium-backed ciphers use different - * code paths in stream.c, so cover both. */ + * code paths in stream.cpp, so cover both. */ test_stream_multi_segment_roundtrip("aes-256-cfb"); test_stream_multi_segment_roundtrip("aes-256-ctr"); test_stream_multi_segment_roundtrip("camellia-128-cfb");